1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include "util/annotate.h"
4 #include "util/disasm_bpf.h"
5 #include "util/symbol.h"
6 #include <linux/zalloc.h>
7 #include <string.h>
8
9 #if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
10 #define PACKAGE "perf"
11 #include <bfd.h>
12 #include <bpf/bpf.h>
13 #include <bpf/btf.h>
14 #include <bpf/libbpf.h>
15 #include <dis-asm.h>
16 #include <errno.h>
17 #include <linux/btf.h>
18 #include <tools/dis-asm-compat.h>
19
20 #include "util/bpf-event.h"
21 #include "util/bpf-utils.h"
22 #include "util/debug.h"
23 #include "util/dso.h"
24 #include "util/map.h"
25 #include "util/env.h"
26 #include "util/util.h"
27
symbol__disassemble_bpf(struct symbol * sym,struct annotate_args * args)28 int symbol__disassemble_bpf(struct symbol *sym, struct annotate_args *args)
29 {
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;
41 char tpath[PATH_MAX];
42 size_t buf_size;
43 int nr_skip = 0;
44 char *buf;
45 bfd *bfdf;
46 int ret;
47 FILE *s;
48
49 if (dso__binary_type(dso) != DSO_BINARY_TYPE__BPF_PROG_INFO)
50 return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE;
51
52 pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__,
53 sym->name, sym->start, sym->end - sym->start);
54
55 memset(tpath, 0, sizeof(tpath));
56 perf_exe(tpath, sizeof(tpath));
57
58 bfdf = bfd_openr(tpath, NULL);
59 if (bfdf == NULL)
60 abort();
61
62 if (!bfd_check_format(bfdf, bfd_object))
63 abort();
64
65 s = open_memstream(&buf, &buf_size);
66 if (!s) {
67 ret = errno;
68 goto out;
69 }
70 init_disassemble_info_compat(&info, s,
71 (fprintf_ftype) fprintf,
72 fprintf_styled);
73 info.arch = bfd_get_arch(bfdf);
74 info.mach = bfd_get_mach(bfdf);
75
76 info_node = perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env,
77 dso__bpf_prog(dso)->id);
78 if (!info_node) {
79 ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF;
80 goto out;
81 }
82 info_linear = info_node->info_linear;
83 sub_id = dso__bpf_prog(dso)->sub_id;
84
85 info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns);
86 info.buffer_length = info_linear->info.jited_prog_len;
87
88 if (info_linear->info.nr_line_info)
89 prog_linfo = bpf_prog_linfo__new(&info_linear->info);
90
91 if (info_linear->info.btf_id) {
92 struct btf_node *node;
93
94 node = perf_env__find_btf(dso__bpf_prog(dso)->env,
95 info_linear->info.btf_id);
96 if (node)
97 btf = btf__new((__u8 *)(node->data),
98 node->data_size);
99 }
100
101 disassemble_init_for_target(&info);
102
103 #ifdef DISASM_FOUR_ARGS_SIGNATURE
104 disassemble = disassembler(info.arch,
105 bfd_big_endian(bfdf),
106 info.mach,
107 bfdf);
108 #else
109 disassemble = disassembler(bfdf);
110 #endif
111 if (disassemble == NULL)
112 abort();
113
114 fflush(s);
115 do {
116 const struct bpf_line_info *linfo = NULL;
117 struct disasm_line *dl;
118 size_t prev_buf_size;
119 const char *srcline;
120 u64 addr;
121
122 addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id];
123 count = disassemble(pc, &info);
124
125 if (prog_linfo)
126 linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
127 addr, sub_id,
128 nr_skip);
129
130 if (linfo && btf) {
131 srcline = btf__name_by_offset(btf, linfo->line_off);
132 nr_skip++;
133 } else
134 srcline = NULL;
135
136 fprintf(s, "\n");
137 prev_buf_size = buf_size;
138 fflush(s);
139
140 if (!annotate_opts.hide_src_code && srcline) {
141 args->offset = -1;
142 args->line = strdup(srcline);
143 args->line_nr = 0;
144 args->fileloc = NULL;
145 args->ms.sym = sym;
146 dl = disasm_line__new(args);
147 if (dl) {
148 annotation_line__add(&dl->al,
149 ¬es->src->source);
150 }
151 }
152
153 args->offset = pc;
154 args->line = buf + prev_buf_size;
155 args->line_nr = 0;
156 args->fileloc = NULL;
157 args->ms.sym = sym;
158 dl = disasm_line__new(args);
159 if (dl)
160 annotation_line__add(&dl->al, ¬es->src->source);
161
162 pc += count;
163 } while (count > 0 && pc < len);
164
165 ret = 0;
166 out:
167 free(prog_linfo);
168 btf__free(btf);
169 fclose(s);
170 bfd_close(bfdf);
171 return ret;
172 }
173 #else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
symbol__disassemble_bpf(struct symbol * sym __maybe_unused,struct annotate_args * args __maybe_unused)174 int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, struct annotate_args *args __maybe_unused)
175 {
176 return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF;
177 }
178 #endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
179
symbol__disassemble_bpf_image(struct symbol * sym,struct annotate_args * args)180 int symbol__disassemble_bpf_image(struct symbol *sym, struct annotate_args *args)
181 {
182 struct annotation *notes = symbol__annotation(sym);
183 struct disasm_line *dl;
184
185 args->offset = -1;
186 args->line = strdup("to be implemented");
187 args->line_nr = 0;
188 args->fileloc = NULL;
189 dl = disasm_line__new(args);
190 if (dl)
191 annotation_line__add(&dl->al, ¬es->src->source);
192
193 zfree(&args->line);
194 return 0;
195 }
196