1 // SPDX-License-Identifier: GPL-2.0-only
3 #include "util/annotate.h"
4 #include "util/disasm_bpf.h"
5 #include "util/symbol.h"
6 #include <linux/zalloc.h>
9 #if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
10 #define PACKAGE "perf"
14 #include <bpf/libbpf.h>
17 #include <linux/btf.h>
18 #include <tools/dis-asm-compat.h>
20 #include "util/bpf-event.h"
21 #include "util/bpf-utils.h"
22 #include "util/debug.h"
26 #include "util/util.h"
28 int symbol__disassemble_bpf(struct symbol *sym, struct annotate_args *args)
30 struct annotation *notes = symbol__annotation(sym);
31 struct bpf_prog_linfo *prog_linfo = NULL;
32 struct bpf_prog_info_node *info_node;
33 int len = sym->end - sym->start;
34 disassembler_ftype disassemble;
35 struct map *map = args->ms.map;
36 struct perf_bpil *info_linear;
37 struct disassemble_info info;
38 struct dso *dso = map__dso(map);
39 int pc = 0, count, sub_id;
40 struct btf *btf = NULL;
49 if (dso__binary_type(dso) != DSO_BINARY_TYPE__BPF_PROG_INFO)
50 return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE;
52 pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__,
53 sym->name, sym->start, sym->end - sym->start);
55 memset(tpath, 0, sizeof(tpath));
56 perf_exe(tpath, sizeof(tpath));
58 bfdf = bfd_openr(tpath, NULL);
62 if (!bfd_check_format(bfdf, bfd_object))
65 s = open_memstream(&buf, &buf_size);
70 init_disassemble_info_compat(&info, s,
71 (fprintf_ftype) fprintf,
73 info.arch = bfd_get_arch(bfdf);
74 info.mach = bfd_get_mach(bfdf);
76 info_node = perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env,
77 dso__bpf_prog(dso)->id);
79 ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF;
82 info_linear = info_node->info_linear;
83 sub_id = dso__bpf_prog(dso)->sub_id;
85 info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns);
86 info.buffer_length = info_linear->info.jited_prog_len;
88 if (info_linear->info.nr_line_info)
89 prog_linfo = bpf_prog_linfo__new(&info_linear->info);
91 if (info_linear->info.btf_id) {
92 struct btf_node *node;
94 node = perf_env__find_btf(dso__bpf_prog(dso)->env,
95 info_linear->info.btf_id);
97 btf = btf__new((__u8 *)(node->data),
101 disassemble_init_for_target(&info);
103 #ifdef DISASM_FOUR_ARGS_SIGNATURE
104 disassemble = disassembler(info.arch,
105 bfd_big_endian(bfdf),
109 disassemble = disassembler(bfdf);
111 if (disassemble == NULL)
116 const struct bpf_line_info *linfo = NULL;
117 struct disasm_line *dl;
118 size_t prev_buf_size;
122 addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id];
123 count = disassemble(pc, &info);
126 linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
131 srcline = btf__name_by_offset(btf, linfo->line_off);
137 prev_buf_size = buf_size;
140 if (!annotate_opts.hide_src_code && srcline) {
142 args->line = strdup(srcline);
144 args->fileloc = NULL;
146 dl = disasm_line__new(args);
148 annotation_line__add(&dl->al,
149 ¬es->src->source);
154 args->line = buf + prev_buf_size;
156 args->fileloc = NULL;
158 dl = disasm_line__new(args);
160 annotation_line__add(&dl->al, ¬es->src->source);
163 } while (count > 0 && pc < len);
173 #else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
174 int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, struct annotate_args *args __maybe_unused)
176 return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF;
178 #endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
180 int symbol__disassemble_bpf_image(struct symbol *sym, struct annotate_args *args)
182 struct annotation *notes = symbol__annotation(sym);
183 struct disasm_line *dl;
186 args->line = strdup("to be implemented");
188 args->fileloc = NULL;
189 dl = disasm_line__new(args);
191 annotation_line__add(&dl->al, ¬es->src->source);