|
10 | 10 | #include <errno.h>
|
11 | 11 | #include <inttypes.h>
|
12 | 12 | #include <libgen.h>
|
| 13 | +#include <bpf/bpf.h> |
| 14 | +#include <bpf/btf.h> |
| 15 | +#include <bpf/libbpf.h> |
| 16 | +#include <linux/btf.h> |
13 | 17 | #include "util.h"
|
14 | 18 | #include "ui/ui.h"
|
15 | 19 | #include "sort.h"
|
|
24 | 28 | #include "annotate.h"
|
25 | 29 | #include "evsel.h"
|
26 | 30 | #include "evlist.h"
|
| 31 | +#include "bpf-event.h" |
27 | 32 | #include "block-range.h"
|
28 | 33 | #include "string2.h"
|
29 | 34 | #include "arch/common.h"
|
30 | 35 | #include <regex.h>
|
31 | 36 | #include <pthread.h>
|
32 | 37 | #include <linux/bitops.h>
|
33 | 38 | #include <linux/kernel.h>
|
| 39 | +#include <bpf/libbpf.h> |
34 | 40 |
|
35 | 41 | /* FIXME: For the HE_COLORSET */
|
36 | 42 | #include "ui/browser.h"
|
@@ -1615,6 +1621,9 @@ int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *
|
1615 | 1621 | " --vmlinux vmlinux\n", build_id_msg ?: "");
|
1616 | 1622 | }
|
1617 | 1623 | break;
|
| 1624 | + case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF: |
| 1625 | + scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation"); |
| 1626 | + break; |
1618 | 1627 | default:
|
1619 | 1628 | scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum);
|
1620 | 1629 | break;
|
@@ -1674,6 +1683,156 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
|
1674 | 1683 | return 0;
|
1675 | 1684 | }
|
1676 | 1685 |
|
| 1686 | +#if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) |
| 1687 | +#define PACKAGE "perf" |
| 1688 | +#include <bfd.h> |
| 1689 | +#include <dis-asm.h> |
| 1690 | + |
| 1691 | +static int symbol__disassemble_bpf(struct symbol *sym, |
| 1692 | + struct annotate_args *args) |
| 1693 | +{ |
| 1694 | + struct annotation *notes = symbol__annotation(sym); |
| 1695 | + struct annotation_options *opts = args->options; |
| 1696 | + struct bpf_prog_info_linear *info_linear; |
| 1697 | + struct bpf_prog_linfo *prog_linfo = NULL; |
| 1698 | + struct bpf_prog_info_node *info_node; |
| 1699 | + int len = sym->end - sym->start; |
| 1700 | + disassembler_ftype disassemble; |
| 1701 | + struct map *map = args->ms.map; |
| 1702 | + struct disassemble_info info; |
| 1703 | + struct dso *dso = map->dso; |
| 1704 | + int pc = 0, count, sub_id; |
| 1705 | + struct btf *btf = NULL; |
| 1706 | + char tpath[PATH_MAX]; |
| 1707 | + size_t buf_size; |
| 1708 | + int nr_skip = 0; |
| 1709 | + int ret = -1; |
| 1710 | + char *buf; |
| 1711 | + bfd *bfdf; |
| 1712 | + FILE *s; |
| 1713 | + |
| 1714 | + if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) |
| 1715 | + return -1; |
| 1716 | + |
| 1717 | + pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__, |
| 1718 | + sym->name, sym->start, sym->end - sym->start); |
| 1719 | + |
| 1720 | + memset(tpath, 0, sizeof(tpath)); |
| 1721 | + perf_exe(tpath, sizeof(tpath)); |
| 1722 | + |
| 1723 | + bfdf = bfd_openr(tpath, NULL); |
| 1724 | + assert(bfdf); |
| 1725 | + assert(bfd_check_format(bfdf, bfd_object)); |
| 1726 | + |
| 1727 | + s = open_memstream(&buf, &buf_size); |
| 1728 | + if (!s) |
| 1729 | + goto out; |
| 1730 | + init_disassemble_info(&info, s, |
| 1731 | + (fprintf_ftype) fprintf); |
| 1732 | + |
| 1733 | + info.arch = bfd_get_arch(bfdf); |
| 1734 | + info.mach = bfd_get_mach(bfdf); |
| 1735 | + |
| 1736 | + info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, |
| 1737 | + dso->bpf_prog.id); |
| 1738 | + if (!info_node) |
| 1739 | + goto out; |
| 1740 | + info_linear = info_node->info_linear; |
| 1741 | + sub_id = dso->bpf_prog.sub_id; |
| 1742 | + |
| 1743 | + info.buffer = (void *)(info_linear->info.jited_prog_insns); |
| 1744 | + info.buffer_length = info_linear->info.jited_prog_len; |
| 1745 | + |
| 1746 | + if (info_linear->info.nr_line_info) |
| 1747 | + prog_linfo = bpf_prog_linfo__new(&info_linear->info); |
| 1748 | + |
| 1749 | + if (info_linear->info.btf_id) { |
| 1750 | + struct btf_node *node; |
| 1751 | + |
| 1752 | + node = perf_env__find_btf(dso->bpf_prog.env, |
| 1753 | + info_linear->info.btf_id); |
| 1754 | + if (node) |
| 1755 | + btf = btf__new((__u8 *)(node->data), |
| 1756 | + node->data_size); |
| 1757 | + } |
| 1758 | + |
| 1759 | + disassemble_init_for_target(&info); |
| 1760 | + |
| 1761 | +#ifdef DISASM_FOUR_ARGS_SIGNATURE |
| 1762 | + disassemble = disassembler(info.arch, |
| 1763 | + bfd_big_endian(bfdf), |
| 1764 | + info.mach, |
| 1765 | + bfdf); |
| 1766 | +#else |
| 1767 | + disassemble = disassembler(bfdf); |
| 1768 | +#endif |
| 1769 | + assert(disassemble); |
| 1770 | + |
| 1771 | + fflush(s); |
| 1772 | + do { |
| 1773 | + const struct bpf_line_info *linfo = NULL; |
| 1774 | + struct disasm_line *dl; |
| 1775 | + size_t prev_buf_size; |
| 1776 | + const char *srcline; |
| 1777 | + u64 addr; |
| 1778 | + |
| 1779 | + addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id]; |
| 1780 | + count = disassemble(pc, &info); |
| 1781 | + |
| 1782 | + if (prog_linfo) |
| 1783 | + linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, |
| 1784 | + addr, sub_id, |
| 1785 | + nr_skip); |
| 1786 | + |
| 1787 | + if (linfo && btf) { |
| 1788 | + srcline = btf__name_by_offset(btf, linfo->line_off); |
| 1789 | + nr_skip++; |
| 1790 | + } else |
| 1791 | + srcline = NULL; |
| 1792 | + |
| 1793 | + fprintf(s, "\n"); |
| 1794 | + prev_buf_size = buf_size; |
| 1795 | + fflush(s); |
| 1796 | + |
| 1797 | + if (!opts->hide_src_code && srcline) { |
| 1798 | + args->offset = -1; |
| 1799 | + args->line = strdup(srcline); |
| 1800 | + args->line_nr = 0; |
| 1801 | + args->ms.sym = sym; |
| 1802 | + dl = disasm_line__new(args); |
| 1803 | + if (dl) { |
| 1804 | + annotation_line__add(&dl->al, |
| 1805 | + ¬es->src->source); |
| 1806 | + } |
| 1807 | + } |
| 1808 | + |
| 1809 | + args->offset = pc; |
| 1810 | + args->line = buf + prev_buf_size; |
| 1811 | + args->line_nr = 0; |
| 1812 | + args->ms.sym = sym; |
| 1813 | + dl = disasm_line__new(args); |
| 1814 | + if (dl) |
| 1815 | + annotation_line__add(&dl->al, ¬es->src->source); |
| 1816 | + |
| 1817 | + pc += count; |
| 1818 | + } while (count > 0 && pc < len); |
| 1819 | + |
| 1820 | + ret = 0; |
| 1821 | +out: |
| 1822 | + free(prog_linfo); |
| 1823 | + free(btf); |
| 1824 | + fclose(s); |
| 1825 | + bfd_close(bfdf); |
| 1826 | + return ret; |
| 1827 | +} |
| 1828 | +#else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) |
| 1829 | +static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, |
| 1830 | + struct annotate_args *args __maybe_unused) |
| 1831 | +{ |
| 1832 | + return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; |
| 1833 | +} |
| 1834 | +#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) |
| 1835 | + |
1677 | 1836 | static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
1678 | 1837 | {
|
1679 | 1838 | struct annotation_options *opts = args->options;
|
@@ -1701,7 +1860,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
1701 | 1860 | pr_debug("annotating [%p] %30s : [%p] %30s\n",
|
1702 | 1861 | dso, dso->long_name, sym, sym->name);
|
1703 | 1862 |
|
1704 |
| - if (dso__is_kcore(dso)) { |
| 1863 | + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { |
| 1864 | + return symbol__disassemble_bpf(sym, args); |
| 1865 | + } else if (dso__is_kcore(dso)) { |
1705 | 1866 | kce.kcore_filename = symfs_filename;
|
1706 | 1867 | kce.addr = map__rip_2objdump(map, sym->start);
|
1707 | 1868 | kce.offs = sym->start;
|
|
0 commit comments