aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/header.c63
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/session.c108
-rw-r--r--tools/perf/util/session.h7
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
469static 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
467int perf_header__process_sections(struct perf_header *self, int fd, 481int 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
536static int perf_file_section__process(struct perf_file_section *self, 572static 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
561int perf_header__read(struct perf_header *self, int fd) 598int 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
81int perf_header__process_sections(struct perf_header *self, int fd, 82int 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
205void 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
216static 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
222static 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
228static 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
237static 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
246static 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
256typedef void (*event__swap_op)(event_t *self);
257
258static 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
204static int perf_session__process_event(struct perf_session *self, 269static 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
244int perf_header__read_build_ids(int input, u64 offset, u64 size) 312void 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
319int 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
292int perf_session__process_events(struct perf_session *self, 371int 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 }
333remap: 419remap:
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:
342more: 428more:
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 {
51struct perf_session *perf_session__new(const char *filename, int mode, bool force); 51struct perf_session *perf_session__new(const char *filename, int mode, bool force);
52void perf_session__delete(struct perf_session *self); 52void perf_session__delete(struct perf_session *self);
53 53
54void perf_event_header__bswap(struct perf_event_header *self);
55
54int perf_session__process_events(struct perf_session *self, 56int 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
62bool perf_session__has_traces(struct perf_session *self, const char *msg); 64bool perf_session__has_traces(struct perf_session *self, const char *msg);
63 65
64int perf_header__read_build_ids(int input, u64 offset, u64 file_size); 66int perf_header__read_build_ids(struct perf_header *self, int input,
67 u64 offset, u64 file_size);
65 68
66int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, 69int 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,
69void perf_session__reloc_vmlinux_maps(struct perf_session *self, 72void perf_session__reloc_vmlinux_maps(struct perf_session *self,
70 u64 unrelocated_addr); 73 u64 unrelocated_addr);
71 74
75void mem_bswap_64(void *src, int byte_size);
76
72#endif /* __PERF_SESSION_H */ 77#endif /* __PERF_SESSION_H */