Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf dso: Use libbfd to read build_id and .gnu_debuglink section

Wine generates PE binaries for most of its modules and perf is unable to
parse these files to get build_id or .gnu_debuglink section.

Using libbfd when available, instead of libelf, makes it possible to
resolve debug file location regardless of the dso binary format.

Committer notes:

Made the filename__read_build_id() variant that uses abfd->build_id
depend on the feature test that defines HAVE_LIBBFD_BUILDID_SUPPORT, to
get this to continue building with older libbfd/binutils.

Signed-off-by: Remi Bernon <rbernon@codeweavers.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jacek Caban <jacek@codeweavers.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lore.kernel.org/lkml/20200821165238.1340315-1-rbernon@codeweavers.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Remi Bernon and committed by
Arnaldo Carvalho de Melo
ba0509dc e71e19a9

+77 -3
+77 -3
tools/perf/util/symbol-elf.c
··· 50 50 #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 51 51 #endif 52 52 53 + #ifdef HAVE_LIBBFD_SUPPORT 54 + #define PACKAGE 'perf' 55 + #include <bfd.h> 56 + #else 53 57 #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT 54 58 extern char *cplus_demangle(const char *, int); 55 59 ··· 69 65 { 70 66 return NULL; 71 67 } 72 - #else 73 - #define PACKAGE 'perf' 74 - #include <bfd.h> 68 + #endif 75 69 #endif 76 70 #endif 77 71 ··· 532 530 return err; 533 531 } 534 532 533 + #ifdef HAVE_LIBBFD_BUILDID_SUPPORT 534 + 535 + int filename__read_build_id(const char *filename, void *bf, size_t size) 536 + { 537 + int err = -1; 538 + bfd *abfd; 539 + 540 + abfd = bfd_openr(filename, NULL); 541 + if (!abfd) 542 + return -1; 543 + 544 + if (!bfd_check_format(abfd, bfd_object)) { 545 + pr_debug2("%s: cannot read %s bfd file.\n", __func__, filename); 546 + goto out_close; 547 + } 548 + 549 + if (!abfd->build_id || abfd->build_id->size > size) 550 + goto out_close; 551 + 552 + memcpy(bf, abfd->build_id->data, abfd->build_id->size); 553 + memset(bf + abfd->build_id->size, 0, size - abfd->build_id->size); 554 + err = abfd->build_id->size; 555 + 556 + out_close: 557 + bfd_close(abfd); 558 + return err; 559 + } 560 + 561 + #else // HAVE_LIBBFD_BUILDID_SUPPORT 562 + 535 563 int filename__read_build_id(const char *filename, void *bf, size_t size) 536 564 { 537 565 int fd, err = -1; ··· 588 556 out: 589 557 return err; 590 558 } 559 + 560 + #endif // HAVE_LIBBFD_BUILDID_SUPPORT 591 561 592 562 int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 593 563 { ··· 642 608 return err; 643 609 } 644 610 611 + #ifdef HAVE_LIBBFD_SUPPORT 612 + 613 + int filename__read_debuglink(const char *filename, char *debuglink, 614 + size_t size) 615 + { 616 + int err = -1; 617 + asection *section; 618 + bfd *abfd; 619 + 620 + abfd = bfd_openr(filename, NULL); 621 + if (!abfd) 622 + return -1; 623 + 624 + if (!bfd_check_format(abfd, bfd_object)) { 625 + pr_debug2("%s: cannot read %s bfd file.\n", __func__, filename); 626 + goto out_close; 627 + } 628 + 629 + section = bfd_get_section_by_name(abfd, ".gnu_debuglink"); 630 + if (!section) 631 + goto out_close; 632 + 633 + if (section->size > size) 634 + goto out_close; 635 + 636 + if (!bfd_get_section_contents(abfd, section, debuglink, 0, 637 + section->size)) 638 + goto out_close; 639 + 640 + err = 0; 641 + 642 + out_close: 643 + bfd_close(abfd); 644 + return err; 645 + } 646 + 647 + #else 648 + 645 649 int filename__read_debuglink(const char *filename, char *debuglink, 646 650 size_t size) 647 651 { ··· 731 659 out: 732 660 return err; 733 661 } 662 + 663 + #endif 734 664 735 665 static int dso__swap_init(struct dso *dso, unsigned char eidata) 736 666 {