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

perf symbols: Try reading the symbol table with libbfd

Wine generates PE binaries for its code modules and also generates debug
files in PE or PDB formats, which perf cannot parse either.

Trying to read symbols on non-ELF binaries with libbfd, when supported,
makes it possible for perf to report symbols and annotations for Windows
applications running under Wine.

Because libbfd doesn't provide symbol size (probably because of some
backends not supporting it), we compute it by first sorting the symbols
by addresses and then considering that they are sequential in a given
section.

v3: Also include local and weak bfd symbols and mark them as such, only
global symbols were previously reported, and that caused a very
imprecise address to symbol resolution.

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-2-rbernon@codeweavers.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Remi Bernon and committed by
Arnaldo Carvalho de Melo
eac9a434 ba0509dc

+144
+140
tools/perf/util/symbol.c
··· 1526 1526 return -1; 1527 1527 } 1528 1528 1529 + #ifdef HAVE_LIBBFD_SUPPORT 1530 + #define PACKAGE 'perf' 1531 + #include <bfd.h> 1532 + 1533 + static int bfd_symbols__cmpvalue(const void *a, const void *b) 1534 + { 1535 + const asymbol *as = *(const asymbol **)a, *bs = *(const asymbol **)b; 1536 + 1537 + if (bfd_asymbol_value(as) != bfd_asymbol_value(bs)) 1538 + return bfd_asymbol_value(as) - bfd_asymbol_value(bs); 1539 + 1540 + return bfd_asymbol_name(as)[0] - bfd_asymbol_name(bs)[0]; 1541 + } 1542 + 1543 + static int bfd2elf_binding(asymbol *symbol) 1544 + { 1545 + if (symbol->flags & BSF_WEAK) 1546 + return STB_WEAK; 1547 + if (symbol->flags & BSF_GLOBAL) 1548 + return STB_GLOBAL; 1549 + if (symbol->flags & BSF_LOCAL) 1550 + return STB_LOCAL; 1551 + return -1; 1552 + } 1553 + 1554 + int dso__load_bfd_symbols(struct dso *dso, const char *debugfile) 1555 + { 1556 + int err = -1; 1557 + long symbols_size, symbols_count; 1558 + asection *section; 1559 + asymbol **symbols, *sym; 1560 + struct symbol *symbol; 1561 + bfd *abfd; 1562 + u_int i; 1563 + u64 start, len; 1564 + 1565 + abfd = bfd_openr(dso->long_name, NULL); 1566 + if (!abfd) 1567 + return -1; 1568 + 1569 + if (!bfd_check_format(abfd, bfd_object)) { 1570 + pr_debug2("%s: cannot read %s bfd file.\n", __func__, 1571 + dso->long_name); 1572 + goto out_close; 1573 + } 1574 + 1575 + if (bfd_get_flavour(abfd) == bfd_target_elf_flavour) 1576 + goto out_close; 1577 + 1578 + section = bfd_get_section_by_name(abfd, ".text"); 1579 + if (section) 1580 + dso->text_offset = section->vma - section->filepos; 1581 + 1582 + bfd_close(abfd); 1583 + 1584 + abfd = bfd_openr(debugfile, NULL); 1585 + if (!abfd) 1586 + return -1; 1587 + 1588 + if (!bfd_check_format(abfd, bfd_object)) { 1589 + pr_debug2("%s: cannot read %s bfd file.\n", __func__, 1590 + debugfile); 1591 + goto out_close; 1592 + } 1593 + 1594 + if (bfd_get_flavour(abfd) == bfd_target_elf_flavour) 1595 + goto out_close; 1596 + 1597 + symbols_size = bfd_get_symtab_upper_bound(abfd); 1598 + if (symbols_size == 0) { 1599 + bfd_close(abfd); 1600 + return 0; 1601 + } 1602 + 1603 + if (symbols_size < 0) 1604 + goto out_close; 1605 + 1606 + symbols = malloc(symbols_size); 1607 + if (!symbols) 1608 + goto out_close; 1609 + 1610 + symbols_count = bfd_canonicalize_symtab(abfd, symbols); 1611 + if (symbols_count < 0) 1612 + goto out_free; 1613 + 1614 + qsort(symbols, symbols_count, sizeof(asymbol *), bfd_symbols__cmpvalue); 1615 + 1616 + #ifdef bfd_get_section 1617 + #define bfd_asymbol_section bfd_get_section 1618 + #endif 1619 + for (i = 0; i < symbols_count; ++i) { 1620 + sym = symbols[i]; 1621 + section = bfd_asymbol_section(sym); 1622 + if (bfd2elf_binding(sym) < 0) 1623 + continue; 1624 + 1625 + while (i + 1 < symbols_count && 1626 + bfd_asymbol_section(symbols[i + 1]) == section && 1627 + bfd2elf_binding(symbols[i + 1]) < 0) 1628 + i++; 1629 + 1630 + if (i + 1 < symbols_count && 1631 + bfd_asymbol_section(symbols[i + 1]) == section) 1632 + len = symbols[i + 1]->value - sym->value; 1633 + else 1634 + len = section->size - sym->value; 1635 + 1636 + start = bfd_asymbol_value(sym) - dso->text_offset; 1637 + symbol = symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC, 1638 + bfd_asymbol_name(sym)); 1639 + if (!symbol) 1640 + goto out_free; 1641 + 1642 + symbols__insert(&dso->symbols, symbol); 1643 + } 1644 + #ifdef bfd_get_section 1645 + #undef bfd_asymbol_section 1646 + #endif 1647 + 1648 + symbols__fixup_end(&dso->symbols); 1649 + symbols__fixup_duplicate(&dso->symbols); 1650 + dso->adjust_symbols = 1; 1651 + 1652 + err = 0; 1653 + out_free: 1654 + free(symbols); 1655 + out_close: 1656 + bfd_close(abfd); 1657 + return err; 1658 + } 1659 + #endif 1660 + 1529 1661 static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 1530 1662 enum dso_binary_type type) 1531 1663 { ··· 1831 1699 bool next_slot = false; 1832 1700 bool is_reg; 1833 1701 bool nsexit; 1702 + int bfdrc = -1; 1834 1703 int sirc = -1; 1835 1704 1836 1705 enum dso_binary_type symtab_type = binary_type_symtab[i]; ··· 1850 1717 nsinfo__mountns_exit(&nsc); 1851 1718 1852 1719 is_reg = is_regular_file(name); 1720 + #ifdef HAVE_LIBBFD_SUPPORT 1853 1721 if (is_reg) 1722 + bfdrc = dso__load_bfd_symbols(dso, name); 1723 + #endif 1724 + if (is_reg && bfdrc < 0) 1854 1725 sirc = symsrc__init(ss, dso, name, symtab_type); 1855 1726 1856 1727 if (nsexit) 1857 1728 nsinfo__mountns_enter(dso->nsinfo, &nsc); 1729 + 1730 + if (bfdrc == 0) 1731 + break; 1858 1732 1859 1733 if (!is_reg || sirc < 0) 1860 1734 continue;
+4
tools/perf/util/symbol.h
··· 175 175 176 176 struct symsrc; 177 177 178 + #ifdef HAVE_LIBBFD_SUPPORT 179 + int dso__load_bfd_symbols(struct dso *dso, const char *debugfile); 180 + #endif 181 + 178 182 int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 179 183 struct symsrc *runtime_ss, int kmodule); 180 184 int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss);