Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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
 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_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						     &notes->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, &notes->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, &notes->src->source);
192
193	zfree(&args->line);
194	return 0;
195}