Commit b25114817a73bbd2b84ce9dba02ee1ef8989a947

Authored by Arnaldo Carvalho de Melo
1 parent 9e69c21082

perf build-id: Add quirk to deal with perf.data file format breakage

The a1645ce1 changeset:

"perf: 'perf kvm' tool for monitoring guest performance from host"

Added a field to struct build_id_event that broke the file format.

Since the kernel build-id is the first entry, process the table using
the old format if the well known '[kernel.kallsyms]' string for the
kernel build-id has the first 4 characters chopped off (where the pid_t
sits).

Reported-by: Han Pingtian <phan@redhat.com>
Cc: Avi Kivity <avi@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
Cc: Zhang Yanmin <yanmin_zhang@linux.intel.com>
Cc: stable@kernel.org
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Showing 1 changed file with 56 additions and 1 deletions Side-by-side Diff

tools/perf/util/header.c
... ... @@ -695,13 +695,50 @@
695 695 return err;
696 696 }
697 697  
  698 +static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
  699 + int input, u64 offset, u64 size)
  700 +{
  701 + struct perf_session *session = container_of(header, struct perf_session, header);
  702 + struct {
  703 + struct perf_event_header header;
  704 + u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
  705 + char filename[0];
  706 + } old_bev;
  707 + struct build_id_event bev;
  708 + char filename[PATH_MAX];
  709 + u64 limit = offset + size;
  710 +
  711 + while (offset < limit) {
  712 + ssize_t len;
  713 +
  714 + if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
  715 + return -1;
  716 +
  717 + if (header->needs_swap)
  718 + perf_event_header__bswap(&old_bev.header);
  719 +
  720 + len = old_bev.header.size - sizeof(old_bev);
  721 + if (read(input, filename, len) != len)
  722 + return -1;
  723 +
  724 + bev.header = old_bev.header;
  725 + bev.pid = 0;
  726 + memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
  727 + __event_process_build_id(&bev, filename, session);
  728 +
  729 + offset += bev.header.size;
  730 + }
  731 +
  732 + return 0;
  733 +}
  734 +
698 735 static int perf_header__read_build_ids(struct perf_header *header,
699 736 int input, u64 offset, u64 size)
700 737 {
701 738 struct perf_session *session = container_of(header, struct perf_session, header);
702 739 struct build_id_event bev;
703 740 char filename[PATH_MAX];
704   - u64 limit = offset + size;
  741 + u64 limit = offset + size, orig_offset = offset;
705 742 int err = -1;
706 743  
707 744 while (offset < limit) {
... ... @@ -716,6 +753,24 @@
716 753 len = bev.header.size - sizeof(bev);
717 754 if (read(input, filename, len) != len)
718 755 goto out;
  756 + /*
  757 + * The a1645ce1 changeset:
  758 + *
  759 + * "perf: 'perf kvm' tool for monitoring guest performance from host"
  760 + *
  761 + * Added a field to struct build_id_event that broke the file
  762 + * format.
  763 + *
  764 + * Since the kernel build-id is the first entry, process the
  765 + * table using the old format if the well known
  766 + * '[kernel.kallsyms]' string for the kernel build-id has the
  767 + * first 4 characters chopped off (where the pid_t sits).
  768 + */
  769 + if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
  770 + if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
  771 + return -1;
  772 + return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
  773 + }
719 774  
720 775 __event_process_build_id(&bev, filename, session);
721 776