aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/event.c46
-rw-r--r--tools/perf/util/event.h12
-rw-r--r--tools/perf/util/evlist.c31
-rw-r--r--tools/perf/util/evlist.h3
-rw-r--r--tools/perf/util/evsel.c32
-rw-r--r--tools/perf/util/header.c31
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/include/linux/list.h2
-rw-r--r--tools/perf/util/python.c13
-rw-r--r--tools/perf/util/session.c50
-rw-r--r--tools/perf/util/session.h2
11 files changed, 158 insertions, 66 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1023f67633a4..252b72a5e59e 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -9,21 +9,21 @@
9#include "thread_map.h" 9#include "thread_map.h"
10 10
11static const char *perf_event__names[] = { 11static const char *perf_event__names[] = {
12 [0] = "TOTAL", 12 [0] = "TOTAL",
13 [PERF_RECORD_MMAP] = "MMAP", 13 [PERF_RECORD_MMAP] = "MMAP",
14 [PERF_RECORD_LOST] = "LOST", 14 [PERF_RECORD_LOST] = "LOST",
15 [PERF_RECORD_COMM] = "COMM", 15 [PERF_RECORD_COMM] = "COMM",
16 [PERF_RECORD_EXIT] = "EXIT", 16 [PERF_RECORD_EXIT] = "EXIT",
17 [PERF_RECORD_THROTTLE] = "THROTTLE", 17 [PERF_RECORD_THROTTLE] = "THROTTLE",
18 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", 18 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
19 [PERF_RECORD_FORK] = "FORK", 19 [PERF_RECORD_FORK] = "FORK",
20 [PERF_RECORD_READ] = "READ", 20 [PERF_RECORD_READ] = "READ",
21 [PERF_RECORD_SAMPLE] = "SAMPLE", 21 [PERF_RECORD_SAMPLE] = "SAMPLE",
22 [PERF_RECORD_HEADER_ATTR] = "ATTR", 22 [PERF_RECORD_HEADER_ATTR] = "ATTR",
23 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", 23 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
24 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", 24 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
25 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", 25 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
26 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", 26 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
27}; 27};
28 28
29const char *perf_event__name(unsigned int id) 29const char *perf_event__name(unsigned int id)
@@ -35,6 +35,22 @@ const char *perf_event__name(unsigned int id)
35 return perf_event__names[id]; 35 return perf_event__names[id];
36} 36}
37 37
38int perf_sample_size(u64 sample_type)
39{
40 u64 mask = sample_type & PERF_SAMPLE_MASK;
41 int size = 0;
42 int i;
43
44 for (i = 0; i < 64; i++) {
45 if (mask & (1UL << i))
46 size++;
47 }
48
49 size *= sizeof(u64);
50
51 return size;
52}
53
38static struct perf_sample synth_sample = { 54static struct perf_sample synth_sample = {
39 .pid = -1, 55 .pid = -1,
40 .tid = -1, 56 .tid = -1,
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 9c35170fb379..c08332871408 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -56,6 +56,13 @@ struct read_event {
56 u64 id; 56 u64 id;
57}; 57};
58 58
59
60#define PERF_SAMPLE_MASK \
61 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
62 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \
63 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
64 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
65
59struct sample_event { 66struct sample_event {
60 struct perf_event_header header; 67 struct perf_event_header header;
61 u64 array[]; 68 u64 array[];
@@ -75,6 +82,8 @@ struct perf_sample {
75 struct ip_callchain *callchain; 82 struct ip_callchain *callchain;
76}; 83};
77 84
85int perf_sample_size(u64 sample_type);
86
78#define BUILD_ID_SIZE 20 87#define BUILD_ID_SIZE 20
79 88
80struct build_id_event { 89struct build_id_event {
@@ -178,6 +187,7 @@ int perf_event__preprocess_sample(const union perf_event *self,
178const char *perf_event__name(unsigned int id); 187const char *perf_event__name(unsigned int id);
179 188
180int perf_event__parse_sample(const union perf_event *event, u64 type, 189int perf_event__parse_sample(const union perf_event *event, u64 type,
181 bool sample_id_all, struct perf_sample *sample); 190 int sample_size, bool sample_id_all,
191 struct perf_sample *sample);
182 192
183#endif /* __PERF_RECORD_H */ 193#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 23eb22b05d27..50aa34879c33 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -459,3 +459,34 @@ int perf_evlist__set_filters(struct perf_evlist *evlist)
459 459
460 return 0; 460 return 0;
461} 461}
462
463u64 perf_evlist__sample_type(struct perf_evlist *evlist)
464{
465 struct perf_evsel *pos;
466 u64 type = 0;
467
468 list_for_each_entry(pos, &evlist->entries, node) {
469 if (!type)
470 type = pos->attr.sample_type;
471 else if (type != pos->attr.sample_type)
472 die("non matching sample_type");
473 }
474
475 return type;
476}
477
478bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
479{
480 bool value = false, first = true;
481 struct perf_evsel *pos;
482
483 list_for_each_entry(pos, &evlist->entries, node) {
484 if (first) {
485 value = pos->attr.sample_id_all;
486 first = false;
487 } else if (value != pos->attr.sample_id_all)
488 die("non matching sample_id_all");
489 }
490
491 return value;
492}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 7109d7add14e..0a1ef1f051f0 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -66,4 +66,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
66void perf_evlist__delete_maps(struct perf_evlist *evlist); 66void perf_evlist__delete_maps(struct perf_evlist *evlist);
67int perf_evlist__set_filters(struct perf_evlist *evlist); 67int perf_evlist__set_filters(struct perf_evlist *evlist);
68 68
69u64 perf_evlist__sample_type(struct perf_evlist *evlist);
70bool perf_evlist__sample_id_all(const struct perf_evlist *evlist);
71
69#endif /* __PERF_EVLIST_H */ 72#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d6fd59beb860..ee0fe0dffa71 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -303,8 +303,20 @@ static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
303 return 0; 303 return 0;
304} 304}
305 305
306static bool sample_overlap(const union perf_event *event,
307 const void *offset, u64 size)
308{
309 const void *base = event;
310
311 if (offset + size > base + event->header.size)
312 return true;
313
314 return false;
315}
316
306int perf_event__parse_sample(const union perf_event *event, u64 type, 317int perf_event__parse_sample(const union perf_event *event, u64 type,
307 bool sample_id_all, struct perf_sample *data) 318 int sample_size, bool sample_id_all,
319 struct perf_sample *data)
308{ 320{
309 const u64 *array; 321 const u64 *array;
310 322
@@ -319,6 +331,9 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
319 331
320 array = event->sample.array; 332 array = event->sample.array;
321 333
334 if (sample_size + sizeof(event->header) > event->header.size)
335 return -EFAULT;
336
322 if (type & PERF_SAMPLE_IP) { 337 if (type & PERF_SAMPLE_IP) {
323 data->ip = event->ip.ip; 338 data->ip = event->ip.ip;
324 array++; 339 array++;
@@ -369,14 +384,29 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
369 } 384 }
370 385
371 if (type & PERF_SAMPLE_CALLCHAIN) { 386 if (type & PERF_SAMPLE_CALLCHAIN) {
387 if (sample_overlap(event, array, sizeof(data->callchain->nr)))
388 return -EFAULT;
389
372 data->callchain = (struct ip_callchain *)array; 390 data->callchain = (struct ip_callchain *)array;
391
392 if (sample_overlap(event, array, data->callchain->nr))
393 return -EFAULT;
394
373 array += 1 + data->callchain->nr; 395 array += 1 + data->callchain->nr;
374 } 396 }
375 397
376 if (type & PERF_SAMPLE_RAW) { 398 if (type & PERF_SAMPLE_RAW) {
377 u32 *p = (u32 *)array; 399 u32 *p = (u32 *)array;
400
401 if (sample_overlap(event, array, sizeof(u32)))
402 return -EFAULT;
403
378 data->raw_size = *p; 404 data->raw_size = *p;
379 p++; 405 p++;
406
407 if (sample_overlap(event, p, data->raw_size))
408 return -EFAULT;
409
380 data->raw_data = p; 410 data->raw_data = p;
381 } 411 }
382 412
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 93862a8027ea..0717bebc7649 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -934,37 +934,6 @@ out_delete_evlist:
934 return -ENOMEM; 934 return -ENOMEM;
935} 935}
936 936
937u64 perf_evlist__sample_type(struct perf_evlist *evlist)
938{
939 struct perf_evsel *pos;
940 u64 type = 0;
941
942 list_for_each_entry(pos, &evlist->entries, node) {
943 if (!type)
944 type = pos->attr.sample_type;
945 else if (type != pos->attr.sample_type)
946 die("non matching sample_type");
947 }
948
949 return type;
950}
951
952bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
953{
954 bool value = false, first = true;
955 struct perf_evsel *pos;
956
957 list_for_each_entry(pos, &evlist->entries, node) {
958 if (first) {
959 value = pos->attr.sample_id_all;
960 first = false;
961 } else if (value != pos->attr.sample_id_all)
962 die("non matching sample_id_all");
963 }
964
965 return value;
966}
967
968int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 937int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
969 perf_event__handler_t process, 938 perf_event__handler_t process,
970 struct perf_session *session) 939 struct perf_session *session)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 456661d7f10e..1886256768a1 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -64,8 +64,6 @@ int perf_header__write_pipe(int fd);
64int perf_header__push_event(u64 id, const char *name); 64int perf_header__push_event(u64 id, const char *name);
65char *perf_header__find_event(u64 id); 65char *perf_header__find_event(u64 id);
66 66
67u64 perf_evlist__sample_type(struct perf_evlist *evlist);
68bool perf_evlist__sample_id_all(const struct perf_evlist *evlist);
69void perf_header__set_feat(struct perf_header *header, int feat); 67void perf_header__set_feat(struct perf_header *header, int feat);
70void perf_header__clear_feat(struct perf_header *header, int feat); 68void perf_header__clear_feat(struct perf_header *header, int feat);
71bool perf_header__has_feat(const struct perf_header *header, int feat); 69bool perf_header__has_feat(const struct perf_header *header, int feat);
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index 99358d61e9a5..1d928a0ce997 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,4 +1,6 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2#include <linux/prefetch.h>
3
2#include "../../../../include/linux/list.h" 4#include "../../../../include/linux/list.h"
3 5
4#ifndef PERF_LIST_H 6#ifndef PERF_LIST_H
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index b5c7d818001c..69436b3200a4 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -675,6 +675,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
675 union perf_event *event; 675 union perf_event *event;
676 int sample_id_all = 1, cpu; 676 int sample_id_all = 1, cpu;
677 static char *kwlist[] = {"sample_id_all", NULL, NULL}; 677 static char *kwlist[] = {"sample_id_all", NULL, NULL};
678 int err;
678 679
679 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist, 680 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
680 &cpu, &sample_id_all)) 681 &cpu, &sample_id_all))
@@ -690,11 +691,17 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
690 return PyErr_NoMemory(); 691 return PyErr_NoMemory();
691 692
692 first = list_entry(evlist->entries.next, struct perf_evsel, node); 693 first = list_entry(evlist->entries.next, struct perf_evsel, node);
693 perf_event__parse_sample(event, first->attr.sample_type, sample_id_all, 694 err = perf_event__parse_sample(event, first->attr.sample_type,
694 &pevent->sample); 695 perf_sample_size(first->attr.sample_type),
696 sample_id_all, &pevent->sample);
697 if (err) {
698 pr_err("Can't parse sample, err = %d\n", err);
699 goto end;
700 }
701
695 return pyevent; 702 return pyevent;
696 } 703 }
697 704end:
698 Py_INCREF(Py_None); 705 Py_INCREF(Py_None);
699 return Py_None; 706 return Py_None;
700} 707}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index fff66741f18d..64500fc78799 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -97,6 +97,7 @@ out:
97void perf_session__update_sample_type(struct perf_session *self) 97void perf_session__update_sample_type(struct perf_session *self)
98{ 98{
99 self->sample_type = perf_evlist__sample_type(self->evlist); 99 self->sample_type = perf_evlist__sample_type(self->evlist);
100 self->sample_size = perf_sample_size(self->sample_type);
100 self->sample_id_all = perf_evlist__sample_id_all(self->evlist); 101 self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
101 perf_session__id_header_size(self); 102 perf_session__id_header_size(self);
102} 103}
@@ -479,6 +480,7 @@ static void flush_sample_queue(struct perf_session *s,
479 struct perf_sample sample; 480 struct perf_sample sample;
480 u64 limit = os->next_flush; 481 u64 limit = os->next_flush;
481 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 482 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
483 int ret;
482 484
483 if (!ops->ordered_samples || !limit) 485 if (!ops->ordered_samples || !limit)
484 return; 486 return;
@@ -487,9 +489,12 @@ static void flush_sample_queue(struct perf_session *s,
487 if (iter->timestamp > limit) 489 if (iter->timestamp > limit)
488 break; 490 break;
489 491
490 perf_session__parse_sample(s, iter->event, &sample); 492 ret = perf_session__parse_sample(s, iter->event, &sample);
491 perf_session_deliver_event(s, iter->event, &sample, ops, 493 if (ret)
492 iter->file_offset); 494 pr_err("Can't parse sample, err = %d\n", ret);
495 else
496 perf_session_deliver_event(s, iter->event, &sample, ops,
497 iter->file_offset);
493 498
494 os->last_flush = iter->timestamp; 499 os->last_flush = iter->timestamp;
495 list_del(&iter->list); 500 list_del(&iter->list);
@@ -805,7 +810,9 @@ static int perf_session__process_event(struct perf_session *session,
805 /* 810 /*
806 * For all kernel events we get the sample data 811 * For all kernel events we get the sample data
807 */ 812 */
808 perf_session__parse_sample(session, event, &sample); 813 ret = perf_session__parse_sample(session, event, &sample);
814 if (ret)
815 return ret;
809 816
810 /* Preprocess sample records - precheck callchains */ 817 /* Preprocess sample records - precheck callchains */
811 if (perf_session__preprocess_sample(session, event, &sample)) 818 if (perf_session__preprocess_sample(session, event, &sample))
@@ -953,6 +960,30 @@ out_err:
953 return err; 960 return err;
954} 961}
955 962
963static union perf_event *
964fetch_mmaped_event(struct perf_session *session,
965 u64 head, size_t mmap_size, char *buf)
966{
967 union perf_event *event;
968
969 /*
970 * Ensure we have enough space remaining to read
971 * the size of the event in the headers.
972 */
973 if (head + sizeof(event->header) > mmap_size)
974 return NULL;
975
976 event = (union perf_event *)(buf + head);
977
978 if (session->header.needs_swap)
979 perf_event_header__bswap(&event->header);
980
981 if (head + event->header.size > mmap_size)
982 return NULL;
983
984 return event;
985}
986
956int __perf_session__process_events(struct perf_session *session, 987int __perf_session__process_events(struct perf_session *session,
957 u64 data_offset, u64 data_size, 988 u64 data_offset, u64 data_size,
958 u64 file_size, struct perf_event_ops *ops) 989 u64 file_size, struct perf_event_ops *ops)
@@ -1007,15 +1038,8 @@ remap:
1007 file_pos = file_offset + head; 1038 file_pos = file_offset + head;
1008 1039
1009more: 1040more:
1010 event = (union perf_event *)(buf + head); 1041 event = fetch_mmaped_event(session, head, mmap_size, buf);
1011 1042 if (!event) {
1012 if (session->header.needs_swap)
1013 perf_event_header__bswap(&event->header);
1014 size = event->header.size;
1015 if (size == 0)
1016 size = 8;
1017
1018 if (head + event->header.size > mmap_size) {
1019 if (mmaps[map_idx]) { 1043 if (mmaps[map_idx]) {
1020 munmap(mmaps[map_idx], mmap_size); 1044 munmap(mmaps[map_idx], mmap_size);
1021 mmaps[map_idx] = NULL; 1045 mmaps[map_idx] = NULL;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 8daaa2d15396..66d4e1490879 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -43,6 +43,7 @@ struct perf_session {
43 */ 43 */
44 struct hists hists; 44 struct hists hists;
45 u64 sample_type; 45 u64 sample_type;
46 int sample_size;
46 int fd; 47 int fd;
47 bool fd_pipe; 48 bool fd_pipe;
48 bool repipe; 49 bool repipe;
@@ -159,6 +160,7 @@ static inline int perf_session__parse_sample(struct perf_session *session,
159 struct perf_sample *sample) 160 struct perf_sample *sample)
160{ 161{
161 return perf_event__parse_sample(event, session->sample_type, 162 return perf_event__parse_sample(event, session->sample_type,
163 session->sample_size,
162 session->sample_id_all, sample); 164 session->sample_id_all, sample);
163} 165}
164 166