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
);