diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/util/header.c | 63 | ||||
-rw-r--r-- | tools/perf/util/header.h | 2 | ||||
-rw-r--r-- | tools/perf/util/session.c | 108 | ||||
-rw-r--r-- | tools/perf/util/session.h | 7 |
4 files changed, 157 insertions, 23 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ec96321eb9e4..b31e0ae4b8db 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1,8 +1,10 @@ | |||
1 | #include <sys/types.h> | 1 | #include <sys/types.h> |
2 | #include <byteswap.h> | ||
2 | #include <unistd.h> | 3 | #include <unistd.h> |
3 | #include <stdio.h> | 4 | #include <stdio.h> |
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
5 | #include <linux/list.h> | 6 | #include <linux/list.h> |
7 | #include <linux/kernel.h> | ||
6 | 8 | ||
7 | #include "util.h" | 9 | #include "util.h" |
8 | #include "header.h" | 10 | #include "header.h" |
@@ -464,8 +466,21 @@ static int do_read(int fd, void *buf, size_t size) | |||
464 | return 0; | 466 | return 0; |
465 | } | 467 | } |
466 | 468 | ||
469 | static int perf_header__getbuffer64(struct perf_header *self, | ||
470 | int fd, void *buf, size_t size) | ||
471 | { | ||
472 | if (do_read(fd, buf, size)) | ||
473 | return -1; | ||
474 | |||
475 | if (self->needs_swap) | ||
476 | mem_bswap_64(buf, size); | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
467 | int perf_header__process_sections(struct perf_header *self, int fd, | 481 | int perf_header__process_sections(struct perf_header *self, int fd, |
468 | int (*process)(struct perf_file_section *self, | 482 | int (*process)(struct perf_file_section *self, |
483 | struct perf_header *ph, | ||
469 | int feat, int fd)) | 484 | int feat, int fd)) |
470 | { | 485 | { |
471 | struct perf_file_section *feat_sec; | 486 | struct perf_file_section *feat_sec; |
@@ -486,7 +501,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
486 | 501 | ||
487 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 502 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); |
488 | 503 | ||
489 | if (do_read(fd, feat_sec, sec_size)) | 504 | if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) |
490 | goto out_free; | 505 | goto out_free; |
491 | 506 | ||
492 | err = 0; | 507 | err = 0; |
@@ -494,7 +509,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
494 | if (perf_header__has_feat(self, feat)) { | 509 | if (perf_header__has_feat(self, feat)) { |
495 | struct perf_file_section *sec = &feat_sec[idx++]; | 510 | struct perf_file_section *sec = &feat_sec[idx++]; |
496 | 511 | ||
497 | err = process(sec, feat, fd); | 512 | err = process(sec, self, feat, fd); |
498 | if (err < 0) | 513 | if (err < 0) |
499 | break; | 514 | break; |
500 | } | 515 | } |
@@ -511,10 +526,20 @@ int perf_file_header__read(struct perf_file_header *self, | |||
511 | lseek(fd, 0, SEEK_SET); | 526 | lseek(fd, 0, SEEK_SET); |
512 | 527 | ||
513 | if (do_read(fd, self, sizeof(*self)) || | 528 | if (do_read(fd, self, sizeof(*self)) || |
514 | self->magic != PERF_MAGIC || | 529 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) |
515 | self->attr_size != sizeof(struct perf_file_attr)) | ||
516 | return -1; | 530 | return -1; |
517 | 531 | ||
532 | if (self->attr_size != sizeof(struct perf_file_attr)) { | ||
533 | u64 attr_size = bswap_64(self->attr_size); | ||
534 | |||
535 | if (attr_size != sizeof(struct perf_file_attr)) | ||
536 | return -1; | ||
537 | |||
538 | mem_bswap_64(self, offsetof(struct perf_file_header, | ||
539 | adds_features)); | ||
540 | ph->needs_swap = true; | ||
541 | } | ||
542 | |||
518 | if (self->size != sizeof(*self)) { | 543 | if (self->size != sizeof(*self)) { |
519 | /* Support the previous format */ | 544 | /* Support the previous format */ |
520 | if (self->size == offsetof(typeof(*self), adds_features)) | 545 | if (self->size == offsetof(typeof(*self), adds_features)) |
@@ -524,16 +549,28 @@ int perf_file_header__read(struct perf_file_header *self, | |||
524 | } | 549 | } |
525 | 550 | ||
526 | memcpy(&ph->adds_features, &self->adds_features, | 551 | memcpy(&ph->adds_features, &self->adds_features, |
527 | sizeof(self->adds_features)); | 552 | sizeof(ph->adds_features)); |
553 | /* | ||
554 | * FIXME: hack that assumes that if we need swap the perf.data file | ||
555 | * may be coming from an arch with a different word-size, ergo different | ||
556 | * DEFINE_BITMAP format, investigate more later, but for now its mostly | ||
557 | * safe to assume that we have a build-id section. Trace files probably | ||
558 | * have several other issues in this realm anyway... | ||
559 | */ | ||
560 | if (ph->needs_swap) { | ||
561 | memset(&ph->adds_features, 0, sizeof(ph->adds_features)); | ||
562 | perf_header__set_feat(ph, HEADER_BUILD_ID); | ||
563 | } | ||
528 | 564 | ||
529 | ph->event_offset = self->event_types.offset; | 565 | ph->event_offset = self->event_types.offset; |
530 | ph->event_size = self->event_types.size; | 566 | ph->event_size = self->event_types.size; |
531 | ph->data_offset = self->data.offset; | 567 | ph->data_offset = self->data.offset; |
532 | ph->data_size = self->data.size; | 568 | ph->data_size = self->data.size; |
533 | return 0; | 569 | return 0; |
534 | } | 570 | } |
535 | 571 | ||
536 | static int perf_file_section__process(struct perf_file_section *self, | 572 | static int perf_file_section__process(struct perf_file_section *self, |
573 | struct perf_header *ph, | ||
537 | int feat, int fd) | 574 | int feat, int fd) |
538 | { | 575 | { |
539 | if (lseek(fd, self->offset, SEEK_SET) < 0) { | 576 | if (lseek(fd, self->offset, SEEK_SET) < 0) { |
@@ -548,7 +585,7 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
548 | break; | 585 | break; |
549 | 586 | ||
550 | case HEADER_BUILD_ID: | 587 | case HEADER_BUILD_ID: |
551 | if (perf_header__read_build_ids(fd, self->offset, self->size)) | 588 | if (perf_header__read_build_ids(ph, fd, self->offset, self->size)) |
552 | pr_debug("Failed to read buildids, continuing...\n"); | 589 | pr_debug("Failed to read buildids, continuing...\n"); |
553 | break; | 590 | break; |
554 | default: | 591 | default: |
@@ -560,7 +597,7 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
560 | 597 | ||
561 | int perf_header__read(struct perf_header *self, int fd) | 598 | int perf_header__read(struct perf_header *self, int fd) |
562 | { | 599 | { |
563 | struct perf_file_header f_header; | 600 | struct perf_file_header f_header; |
564 | struct perf_file_attr f_attr; | 601 | struct perf_file_attr f_attr; |
565 | u64 f_id; | 602 | u64 f_id; |
566 | int nr_attrs, nr_ids, i, j; | 603 | int nr_attrs, nr_ids, i, j; |
@@ -577,8 +614,9 @@ int perf_header__read(struct perf_header *self, int fd) | |||
577 | struct perf_header_attr *attr; | 614 | struct perf_header_attr *attr; |
578 | off_t tmp; | 615 | off_t tmp; |
579 | 616 | ||
580 | if (do_read(fd, &f_attr, sizeof(f_attr))) | 617 | if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) |
581 | goto out_errno; | 618 | goto out_errno; |
619 | |||
582 | tmp = lseek(fd, 0, SEEK_CUR); | 620 | tmp = lseek(fd, 0, SEEK_CUR); |
583 | 621 | ||
584 | attr = perf_header_attr__new(&f_attr.attr); | 622 | attr = perf_header_attr__new(&f_attr.attr); |
@@ -589,7 +627,7 @@ int perf_header__read(struct perf_header *self, int fd) | |||
589 | lseek(fd, f_attr.ids.offset, SEEK_SET); | 627 | lseek(fd, f_attr.ids.offset, SEEK_SET); |
590 | 628 | ||
591 | for (j = 0; j < nr_ids; j++) { | 629 | for (j = 0; j < nr_ids; j++) { |
592 | if (do_read(fd, &f_id, sizeof(f_id))) | 630 | if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) |
593 | goto out_errno; | 631 | goto out_errno; |
594 | 632 | ||
595 | if (perf_header_attr__add_id(attr, f_id) < 0) { | 633 | if (perf_header_attr__add_id(attr, f_id) < 0) { |
@@ -610,7 +648,8 @@ int perf_header__read(struct perf_header *self, int fd) | |||
610 | events = malloc(f_header.event_types.size); | 648 | events = malloc(f_header.event_types.size); |
611 | if (events == NULL) | 649 | if (events == NULL) |
612 | return -ENOMEM; | 650 | return -ENOMEM; |
613 | if (do_read(fd, events, f_header.event_types.size)) | 651 | if (perf_header__getbuffer64(self, fd, events, |
652 | f_header.event_types.size)) | ||
614 | goto out_errno; | 653 | goto out_errno; |
615 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | 654 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); |
616 | } | 655 | } |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 2b69aab67e35..ccc8540feccd 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -52,6 +52,7 @@ struct perf_header { | |||
52 | u64 data_size; | 52 | u64 data_size; |
53 | u64 event_offset; | 53 | u64 event_offset; |
54 | u64 event_size; | 54 | u64 event_size; |
55 | bool needs_swap; | ||
55 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); | 56 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); |
56 | }; | 57 | }; |
57 | 58 | ||
@@ -80,6 +81,7 @@ bool perf_header__has_feat(const struct perf_header *self, int feat); | |||
80 | 81 | ||
81 | int perf_header__process_sections(struct perf_header *self, int fd, | 82 | int perf_header__process_sections(struct perf_header *self, int fd, |
82 | int (*process)(struct perf_file_section *self, | 83 | int (*process)(struct perf_file_section *self, |
84 | struct perf_header *ph, | ||
83 | int feat, int fd)); | 85 | int feat, int fd)); |
84 | 86 | ||
85 | #endif /* __PERF_HEADER_H */ | 87 | #endif /* __PERF_HEADER_H */ |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e3ccdb46d6c4..604e14f6a6f9 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | 2 | ||
3 | #include <byteswap.h> | ||
3 | #include <unistd.h> | 4 | #include <unistd.h> |
4 | #include <sys/types.h> | 5 | #include <sys/types.h> |
5 | 6 | ||
@@ -201,21 +202,88 @@ void event__print_totals(void) | |||
201 | event__name[i], event__total[i]); | 202 | event__name[i], event__total[i]); |
202 | } | 203 | } |
203 | 204 | ||
205 | void mem_bswap_64(void *src, int byte_size) | ||
206 | { | ||
207 | u64 *m = src; | ||
208 | |||
209 | while (byte_size > 0) { | ||
210 | *m = bswap_64(*m); | ||
211 | byte_size -= sizeof(u64); | ||
212 | ++m; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static void event__all64_swap(event_t *self) | ||
217 | { | ||
218 | struct perf_event_header *hdr = &self->header; | ||
219 | mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); | ||
220 | } | ||
221 | |||
222 | static void event__comm_swap(event_t *self) | ||
223 | { | ||
224 | self->comm.pid = bswap_32(self->comm.pid); | ||
225 | self->comm.tid = bswap_32(self->comm.tid); | ||
226 | } | ||
227 | |||
228 | static void event__mmap_swap(event_t *self) | ||
229 | { | ||
230 | self->mmap.pid = bswap_32(self->mmap.pid); | ||
231 | self->mmap.tid = bswap_32(self->mmap.tid); | ||
232 | self->mmap.start = bswap_64(self->mmap.start); | ||
233 | self->mmap.len = bswap_64(self->mmap.len); | ||
234 | self->mmap.pgoff = bswap_64(self->mmap.pgoff); | ||
235 | } | ||
236 | |||
237 | static void event__task_swap(event_t *self) | ||
238 | { | ||
239 | self->fork.pid = bswap_32(self->fork.pid); | ||
240 | self->fork.tid = bswap_32(self->fork.tid); | ||
241 | self->fork.ppid = bswap_32(self->fork.ppid); | ||
242 | self->fork.ptid = bswap_32(self->fork.ptid); | ||
243 | self->fork.time = bswap_64(self->fork.time); | ||
244 | } | ||
245 | |||
246 | static void event__read_swap(event_t *self) | ||
247 | { | ||
248 | self->read.pid = bswap_32(self->read.pid); | ||
249 | self->read.tid = bswap_32(self->read.tid); | ||
250 | self->read.value = bswap_64(self->read.value); | ||
251 | self->read.time_enabled = bswap_64(self->read.time_enabled); | ||
252 | self->read.time_running = bswap_64(self->read.time_running); | ||
253 | self->read.id = bswap_64(self->read.id); | ||
254 | } | ||
255 | |||
256 | typedef void (*event__swap_op)(event_t *self); | ||
257 | |||
258 | static event__swap_op event__swap_ops[] = { | ||
259 | [PERF_RECORD_MMAP] = event__mmap_swap, | ||
260 | [PERF_RECORD_COMM] = event__comm_swap, | ||
261 | [PERF_RECORD_FORK] = event__task_swap, | ||
262 | [PERF_RECORD_EXIT] = event__task_swap, | ||
263 | [PERF_RECORD_LOST] = event__all64_swap, | ||
264 | [PERF_RECORD_READ] = event__read_swap, | ||
265 | [PERF_RECORD_SAMPLE] = event__all64_swap, | ||
266 | [PERF_RECORD_MAX] = NULL, | ||
267 | }; | ||
268 | |||
204 | static int perf_session__process_event(struct perf_session *self, | 269 | static int perf_session__process_event(struct perf_session *self, |
205 | event_t *event, | 270 | event_t *event, |
206 | struct perf_event_ops *ops, | 271 | struct perf_event_ops *ops, |
207 | unsigned long offset, unsigned long head) | 272 | u64 offset, u64 head) |
208 | { | 273 | { |
209 | trace_event(event); | 274 | trace_event(event); |
210 | 275 | ||
211 | if (event->header.type < PERF_RECORD_MAX) { | 276 | if (event->header.type < PERF_RECORD_MAX) { |
212 | dump_printf("%#lx [%#x]: PERF_RECORD_%s", | 277 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", |
213 | offset + head, event->header.size, | 278 | offset + head, event->header.size, |
214 | event__name[event->header.type]); | 279 | event__name[event->header.type]); |
215 | ++event__total[0]; | 280 | ++event__total[0]; |
216 | ++event__total[event->header.type]; | 281 | ++event__total[event->header.type]; |
217 | } | 282 | } |
218 | 283 | ||
284 | if (self->header.needs_swap && event__swap_ops[event->header.type]) | ||
285 | event__swap_ops[event->header.type](event); | ||
286 | |||
219 | switch (event->header.type) { | 287 | switch (event->header.type) { |
220 | case PERF_RECORD_SAMPLE: | 288 | case PERF_RECORD_SAMPLE: |
221 | return ops->sample(event, self); | 289 | return ops->sample(event, self); |
@@ -241,7 +309,15 @@ static int perf_session__process_event(struct perf_session *self, | |||
241 | } | 309 | } |
242 | } | 310 | } |
243 | 311 | ||
244 | int perf_header__read_build_ids(int input, u64 offset, u64 size) | 312 | void perf_event_header__bswap(struct perf_event_header *self) |
313 | { | ||
314 | self->type = bswap_32(self->type); | ||
315 | self->misc = bswap_16(self->misc); | ||
316 | self->size = bswap_16(self->size); | ||
317 | } | ||
318 | |||
319 | int perf_header__read_build_ids(struct perf_header *self, | ||
320 | int input, u64 offset, u64 size) | ||
245 | { | 321 | { |
246 | struct build_id_event bev; | 322 | struct build_id_event bev; |
247 | char filename[PATH_MAX]; | 323 | char filename[PATH_MAX]; |
@@ -256,6 +332,9 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size) | |||
256 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | 332 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) |
257 | goto out; | 333 | goto out; |
258 | 334 | ||
335 | if (self->needs_swap) | ||
336 | perf_event_header__bswap(&bev.header); | ||
337 | |||
259 | len = bev.header.size - sizeof(bev); | 338 | len = bev.header.size - sizeof(bev); |
260 | if (read(input, filename, len) != len) | 339 | if (read(input, filename, len) != len) |
261 | goto out; | 340 | goto out; |
@@ -292,9 +371,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se | |||
292 | int perf_session__process_events(struct perf_session *self, | 371 | int perf_session__process_events(struct perf_session *self, |
293 | struct perf_event_ops *ops) | 372 | struct perf_event_ops *ops) |
294 | { | 373 | { |
295 | int err; | 374 | int err, mmap_prot, mmap_flags; |
296 | unsigned long head, shift; | 375 | u64 head, shift; |
297 | unsigned long offset = 0; | 376 | u64 offset = 0; |
298 | size_t page_size; | 377 | size_t page_size; |
299 | event_t *event; | 378 | event_t *event; |
300 | uint32_t size; | 379 | uint32_t size; |
@@ -330,9 +409,16 @@ out_getcwd_err: | |||
330 | offset += shift; | 409 | offset += shift; |
331 | head -= shift; | 410 | head -= shift; |
332 | 411 | ||
412 | mmap_prot = PROT_READ; | ||
413 | mmap_flags = MAP_SHARED; | ||
414 | |||
415 | if (self->header.needs_swap) { | ||
416 | mmap_prot |= PROT_WRITE; | ||
417 | mmap_flags = MAP_PRIVATE; | ||
418 | } | ||
333 | remap: | 419 | remap: |
334 | buf = mmap(NULL, page_size * self->mmap_window, PROT_READ, | 420 | buf = mmap(NULL, page_size * self->mmap_window, mmap_prot, |
335 | MAP_SHARED, self->fd, offset); | 421 | mmap_flags, self->fd, offset); |
336 | if (buf == MAP_FAILED) { | 422 | if (buf == MAP_FAILED) { |
337 | pr_err("failed to mmap file\n"); | 423 | pr_err("failed to mmap file\n"); |
338 | err = -errno; | 424 | err = -errno; |
@@ -342,6 +428,8 @@ remap: | |||
342 | more: | 428 | more: |
343 | event = (event_t *)(buf + head); | 429 | event = (event_t *)(buf + head); |
344 | 430 | ||
431 | if (self->header.needs_swap) | ||
432 | perf_event_header__bswap(&event->header); | ||
345 | size = event->header.size; | 433 | size = event->header.size; |
346 | if (size == 0) | 434 | if (size == 0) |
347 | size = 8; | 435 | size = 8; |
@@ -361,12 +449,12 @@ more: | |||
361 | 449 | ||
362 | size = event->header.size; | 450 | size = event->header.size; |
363 | 451 | ||
364 | dump_printf("\n%#lx [%#x]: event: %d\n", | 452 | dump_printf("\n%#Lx [%#x]: event: %d\n", |
365 | offset + head, event->header.size, event->header.type); | 453 | offset + head, event->header.size, event->header.type); |
366 | 454 | ||
367 | if (size == 0 || | 455 | if (size == 0 || |
368 | perf_session__process_event(self, event, ops, offset, head) < 0) { | 456 | perf_session__process_event(self, event, ops, offset, head) < 0) { |
369 | dump_printf("%#lx [%#x]: skipping unknown header type: %d\n", | 457 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", |
370 | offset + head, event->header.size, | 458 | offset + head, event->header.size, |
371 | event->header.type); | 459 | event->header.type); |
372 | /* | 460 | /* |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index d4a9d20f8d44..36d1a80c0b6c 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -51,6 +51,8 @@ struct perf_event_ops { | |||
51 | struct perf_session *perf_session__new(const char *filename, int mode, bool force); | 51 | struct perf_session *perf_session__new(const char *filename, int mode, bool force); |
52 | void perf_session__delete(struct perf_session *self); | 52 | void perf_session__delete(struct perf_session *self); |
53 | 53 | ||
54 | void perf_event_header__bswap(struct perf_event_header *self); | ||
55 | |||
54 | int perf_session__process_events(struct perf_session *self, | 56 | int perf_session__process_events(struct perf_session *self, |
55 | struct perf_event_ops *event_ops); | 57 | struct perf_event_ops *event_ops); |
56 | 58 | ||
@@ -61,7 +63,8 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self, | |||
61 | 63 | ||
62 | bool perf_session__has_traces(struct perf_session *self, const char *msg); | 64 | bool perf_session__has_traces(struct perf_session *self, const char *msg); |
63 | 65 | ||
64 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); | 66 | int perf_header__read_build_ids(struct perf_header *self, int input, |
67 | u64 offset, u64 file_size); | ||
65 | 68 | ||
66 | int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, | 69 | int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, |
67 | const char *symbol_name, | 70 | const char *symbol_name, |
@@ -69,4 +72,6 @@ int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, | |||
69 | void perf_session__reloc_vmlinux_maps(struct perf_session *self, | 72 | void perf_session__reloc_vmlinux_maps(struct perf_session *self, |
70 | u64 unrelocated_addr); | 73 | u64 unrelocated_addr); |
71 | 74 | ||
75 | void mem_bswap_64(void *src, int byte_size); | ||
76 | |||
72 | #endif /* __PERF_SESSION_H */ | 77 | #endif /* __PERF_SESSION_H */ |