196 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 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 28int 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_SIGNATURE104 disassemble = disassembler(info.arch,105 bfd_big_endian(bfdf),106 info.mach,107 bfdf);108#else109 disassemble = disassembler(bfdf);110#endif111 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 } else134 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;166out: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)174int 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 180int 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