// SPDX-License-Identifier: GPL-2.0-only #include "util/annotate.h" #include "util/disasm_bpf.h" #include "util/symbol.h" #include #include #if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) #define PACKAGE "perf" #include #include #include #include #include #include #include #include #include "util/bpf-event.h" #include "util/bpf-utils.h" #include "util/debug.h" #include "util/dso.h" #include "util/map.h" #include "util/env.h" #include "util/util.h" int symbol__disassemble_bpf(struct symbol *sym, struct annotate_args *args) { struct annotation *notes = symbol__annotation(sym); struct bpf_prog_linfo *prog_linfo = NULL; struct bpf_prog_info_node *info_node; int len = sym->end - sym->start; disassembler_ftype disassemble; struct map *map = args->ms.map; struct perf_bpil *info_linear; struct disassemble_info info; struct dso *dso = map__dso(map); int pc = 0, count, sub_id; struct btf *btf = NULL; char tpath[PATH_MAX]; size_t buf_size; int nr_skip = 0; char *buf; bfd *bfdf; int ret; FILE *s; if (dso__binary_type(dso) != DSO_BINARY_TYPE__BPF_PROG_INFO) return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE; pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__, sym->name, sym->start, sym->end - sym->start); memset(tpath, 0, sizeof(tpath)); perf_exe(tpath, sizeof(tpath)); bfdf = bfd_openr(tpath, NULL); if (bfdf == NULL) abort(); if (!bfd_check_format(bfdf, bfd_object)) abort(); s = open_memstream(&buf, &buf_size); if (!s) { ret = errno; goto out; } init_disassemble_info_compat(&info, s, (fprintf_ftype) fprintf, fprintf_styled); info.arch = bfd_get_arch(bfdf); info.mach = bfd_get_mach(bfdf); info_node = perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env, dso__bpf_prog(dso)->id); if (!info_node) { ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF; goto out; } info_linear = info_node->info_linear; sub_id = dso__bpf_prog(dso)->sub_id; info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns); info.buffer_length = info_linear->info.jited_prog_len; if (info_linear->info.nr_line_info) prog_linfo = bpf_prog_linfo__new(&info_linear->info); if (info_linear->info.btf_id) { struct btf_node *node; node = perf_env__find_btf(dso__bpf_prog(dso)->env, info_linear->info.btf_id); if (node) btf = btf__new((__u8 *)(node->data), node->data_size); } disassemble_init_for_target(&info); #ifdef DISASM_FOUR_ARGS_SIGNATURE disassemble = disassembler(info.arch, bfd_big_endian(bfdf), info.mach, bfdf); #else disassemble = disassembler(bfdf); #endif if (disassemble == NULL) abort(); fflush(s); do { const struct bpf_line_info *linfo = NULL; struct disasm_line *dl; size_t prev_buf_size; const char *srcline; u64 addr; addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id]; count = disassemble(pc, &info); if (prog_linfo) linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, addr, sub_id, nr_skip); if (linfo && btf) { srcline = btf__name_by_offset(btf, linfo->line_off); nr_skip++; } else srcline = NULL; fprintf(s, "\n"); prev_buf_size = buf_size; fflush(s); if (!annotate_opts.hide_src_code && srcline) { args->offset = -1; args->line = strdup(srcline); args->line_nr = 0; args->fileloc = NULL; args->ms.sym = sym; dl = disasm_line__new(args); if (dl) { annotation_line__add(&dl->al, ¬es->src->source); } } args->offset = pc; args->line = buf + prev_buf_size; args->line_nr = 0; args->fileloc = NULL; args->ms.sym = sym; dl = disasm_line__new(args); if (dl) annotation_line__add(&dl->al, ¬es->src->source); pc += count; } while (count > 0 && pc < len); ret = 0; out: free(prog_linfo); btf__free(btf); fclose(s); bfd_close(bfdf); return ret; } #else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, struct annotate_args *args __maybe_unused) { return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; } #endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) int symbol__disassemble_bpf_image(struct symbol *sym, struct annotate_args *args) { struct annotation *notes = symbol__annotation(sym); struct disasm_line *dl; args->offset = -1; args->line = strdup("to be implemented"); args->line_nr = 0; args->fileloc = NULL; dl = disasm_line__new(args); if (dl) annotation_line__add(&dl->al, ¬es->src->source); zfree(&args->line); return 0; }