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