xref: /aosp_15_r20/external/bpftool/src/jit_disasm.c (revision 858ea5e570667251cdc31d3fe7b846b591105938)
1*858ea5e5SAndroid Build Coastguard Worker // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*858ea5e5SAndroid Build Coastguard Worker /*
3*858ea5e5SAndroid Build Coastguard Worker  * Based on:
4*858ea5e5SAndroid Build Coastguard Worker  *
5*858ea5e5SAndroid Build Coastguard Worker  * Minimal BPF JIT image disassembler
6*858ea5e5SAndroid Build Coastguard Worker  *
7*858ea5e5SAndroid Build Coastguard Worker  * Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
8*858ea5e5SAndroid Build Coastguard Worker  * debugging or verification purposes.
9*858ea5e5SAndroid Build Coastguard Worker  *
10*858ea5e5SAndroid Build Coastguard Worker  * Copyright 2013 Daniel Borkmann <[email protected]>
11*858ea5e5SAndroid Build Coastguard Worker  * Licensed under the GNU General Public License, version 2.0 (GPLv2)
12*858ea5e5SAndroid Build Coastguard Worker  */
13*858ea5e5SAndroid Build Coastguard Worker 
14*858ea5e5SAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
15*858ea5e5SAndroid Build Coastguard Worker #define _GNU_SOURCE
16*858ea5e5SAndroid Build Coastguard Worker #endif
17*858ea5e5SAndroid Build Coastguard Worker #include <stdio.h>
18*858ea5e5SAndroid Build Coastguard Worker #include <stdarg.h>
19*858ea5e5SAndroid Build Coastguard Worker #include <stdint.h>
20*858ea5e5SAndroid Build Coastguard Worker #include <stdlib.h>
21*858ea5e5SAndroid Build Coastguard Worker #include <unistd.h>
22*858ea5e5SAndroid Build Coastguard Worker #include <string.h>
23*858ea5e5SAndroid Build Coastguard Worker #include <sys/stat.h>
24*858ea5e5SAndroid Build Coastguard Worker #include <limits.h>
25*858ea5e5SAndroid Build Coastguard Worker #include <bpf/libbpf.h>
26*858ea5e5SAndroid Build Coastguard Worker 
27*858ea5e5SAndroid Build Coastguard Worker #ifdef HAVE_LLVM_SUPPORT
28*858ea5e5SAndroid Build Coastguard Worker #include <llvm-c/Core.h>
29*858ea5e5SAndroid Build Coastguard Worker #include <llvm-c/Disassembler.h>
30*858ea5e5SAndroid Build Coastguard Worker #include <llvm-c/Target.h>
31*858ea5e5SAndroid Build Coastguard Worker #include <llvm-c/TargetMachine.h>
32*858ea5e5SAndroid Build Coastguard Worker #endif
33*858ea5e5SAndroid Build Coastguard Worker 
34*858ea5e5SAndroid Build Coastguard Worker #ifdef HAVE_LIBBFD_SUPPORT
35*858ea5e5SAndroid Build Coastguard Worker #include <bfd.h>
36*858ea5e5SAndroid Build Coastguard Worker #include <dis-asm.h>
37*858ea5e5SAndroid Build Coastguard Worker #include <tools/dis-asm-compat.h>
38*858ea5e5SAndroid Build Coastguard Worker #endif
39*858ea5e5SAndroid Build Coastguard Worker 
40*858ea5e5SAndroid Build Coastguard Worker #include "json_writer.h"
41*858ea5e5SAndroid Build Coastguard Worker #include "main.h"
42*858ea5e5SAndroid Build Coastguard Worker 
43*858ea5e5SAndroid Build Coastguard Worker static int oper_count;
44*858ea5e5SAndroid Build Coastguard Worker 
45*858ea5e5SAndroid Build Coastguard Worker #ifdef HAVE_LLVM_SUPPORT
46*858ea5e5SAndroid Build Coastguard Worker #define DISASM_SPACER
47*858ea5e5SAndroid Build Coastguard Worker 
48*858ea5e5SAndroid Build Coastguard Worker typedef LLVMDisasmContextRef disasm_ctx_t;
49*858ea5e5SAndroid Build Coastguard Worker 
printf_json(char * s)50*858ea5e5SAndroid Build Coastguard Worker static int printf_json(char *s)
51*858ea5e5SAndroid Build Coastguard Worker {
52*858ea5e5SAndroid Build Coastguard Worker 	s = strtok(s, " \t");
53*858ea5e5SAndroid Build Coastguard Worker 	jsonw_string_field(json_wtr, "operation", s);
54*858ea5e5SAndroid Build Coastguard Worker 
55*858ea5e5SAndroid Build Coastguard Worker 	jsonw_name(json_wtr, "operands");
56*858ea5e5SAndroid Build Coastguard Worker 	jsonw_start_array(json_wtr);
57*858ea5e5SAndroid Build Coastguard Worker 	oper_count = 1;
58*858ea5e5SAndroid Build Coastguard Worker 
59*858ea5e5SAndroid Build Coastguard Worker 	while ((s = strtok(NULL, " \t,()")) != 0) {
60*858ea5e5SAndroid Build Coastguard Worker 		jsonw_string(json_wtr, s);
61*858ea5e5SAndroid Build Coastguard Worker 		oper_count++;
62*858ea5e5SAndroid Build Coastguard Worker 	}
63*858ea5e5SAndroid Build Coastguard Worker 	return 0;
64*858ea5e5SAndroid Build Coastguard Worker }
65*858ea5e5SAndroid Build Coastguard Worker 
66*858ea5e5SAndroid Build Coastguard Worker /* This callback to set the ref_type is necessary to have the LLVM disassembler
67*858ea5e5SAndroid Build Coastguard Worker  * print PC-relative addresses instead of byte offsets for branch instruction
68*858ea5e5SAndroid Build Coastguard Worker  * targets.
69*858ea5e5SAndroid Build Coastguard Worker  */
70*858ea5e5SAndroid Build Coastguard Worker static const char *
symbol_lookup_callback(__maybe_unused void * disasm_info,__maybe_unused uint64_t ref_value,uint64_t * ref_type,__maybe_unused uint64_t ref_PC,__maybe_unused const char ** ref_name)71*858ea5e5SAndroid Build Coastguard Worker symbol_lookup_callback(__maybe_unused void *disasm_info,
72*858ea5e5SAndroid Build Coastguard Worker 		       __maybe_unused uint64_t ref_value,
73*858ea5e5SAndroid Build Coastguard Worker 		       uint64_t *ref_type, __maybe_unused uint64_t ref_PC,
74*858ea5e5SAndroid Build Coastguard Worker 		       __maybe_unused const char **ref_name)
75*858ea5e5SAndroid Build Coastguard Worker {
76*858ea5e5SAndroid Build Coastguard Worker 	*ref_type = LLVMDisassembler_ReferenceType_InOut_None;
77*858ea5e5SAndroid Build Coastguard Worker 	return NULL;
78*858ea5e5SAndroid Build Coastguard Worker }
79*858ea5e5SAndroid Build Coastguard Worker 
80*858ea5e5SAndroid Build Coastguard Worker static int
init_context(disasm_ctx_t * ctx,const char * arch,__maybe_unused const char * disassembler_options,__maybe_unused unsigned char * image,__maybe_unused ssize_t len)81*858ea5e5SAndroid Build Coastguard Worker init_context(disasm_ctx_t *ctx, const char *arch,
82*858ea5e5SAndroid Build Coastguard Worker 	     __maybe_unused const char *disassembler_options,
83*858ea5e5SAndroid Build Coastguard Worker 	     __maybe_unused unsigned char *image, __maybe_unused ssize_t len)
84*858ea5e5SAndroid Build Coastguard Worker {
85*858ea5e5SAndroid Build Coastguard Worker 	char *triple;
86*858ea5e5SAndroid Build Coastguard Worker 
87*858ea5e5SAndroid Build Coastguard Worker 	if (arch)
88*858ea5e5SAndroid Build Coastguard Worker 		triple = LLVMNormalizeTargetTriple(arch);
89*858ea5e5SAndroid Build Coastguard Worker 	else
90*858ea5e5SAndroid Build Coastguard Worker 		triple = LLVMGetDefaultTargetTriple();
91*858ea5e5SAndroid Build Coastguard Worker 	if (!triple) {
92*858ea5e5SAndroid Build Coastguard Worker 		p_err("Failed to retrieve triple");
93*858ea5e5SAndroid Build Coastguard Worker 		return -1;
94*858ea5e5SAndroid Build Coastguard Worker 	}
95*858ea5e5SAndroid Build Coastguard Worker 	*ctx = LLVMCreateDisasm(triple, NULL, 0, NULL, symbol_lookup_callback);
96*858ea5e5SAndroid Build Coastguard Worker 	LLVMDisposeMessage(triple);
97*858ea5e5SAndroid Build Coastguard Worker 
98*858ea5e5SAndroid Build Coastguard Worker 	if (!*ctx) {
99*858ea5e5SAndroid Build Coastguard Worker 		p_err("Failed to create disassembler");
100*858ea5e5SAndroid Build Coastguard Worker 		return -1;
101*858ea5e5SAndroid Build Coastguard Worker 	}
102*858ea5e5SAndroid Build Coastguard Worker 
103*858ea5e5SAndroid Build Coastguard Worker 	return 0;
104*858ea5e5SAndroid Build Coastguard Worker }
105*858ea5e5SAndroid Build Coastguard Worker 
destroy_context(disasm_ctx_t * ctx)106*858ea5e5SAndroid Build Coastguard Worker static void destroy_context(disasm_ctx_t *ctx)
107*858ea5e5SAndroid Build Coastguard Worker {
108*858ea5e5SAndroid Build Coastguard Worker 	LLVMDisposeMessage(*ctx);
109*858ea5e5SAndroid Build Coastguard Worker }
110*858ea5e5SAndroid Build Coastguard Worker 
111*858ea5e5SAndroid Build Coastguard Worker static int
disassemble_insn(disasm_ctx_t * ctx,unsigned char * image,ssize_t len,int pc)112*858ea5e5SAndroid Build Coastguard Worker disassemble_insn(disasm_ctx_t *ctx, unsigned char *image, ssize_t len, int pc)
113*858ea5e5SAndroid Build Coastguard Worker {
114*858ea5e5SAndroid Build Coastguard Worker 	char buf[256];
115*858ea5e5SAndroid Build Coastguard Worker 	int count;
116*858ea5e5SAndroid Build Coastguard Worker 
117*858ea5e5SAndroid Build Coastguard Worker 	count = LLVMDisasmInstruction(*ctx, image + pc, len - pc, pc,
118*858ea5e5SAndroid Build Coastguard Worker 				      buf, sizeof(buf));
119*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
120*858ea5e5SAndroid Build Coastguard Worker 		printf_json(buf);
121*858ea5e5SAndroid Build Coastguard Worker 	else
122*858ea5e5SAndroid Build Coastguard Worker 		printf("%s", buf);
123*858ea5e5SAndroid Build Coastguard Worker 
124*858ea5e5SAndroid Build Coastguard Worker 	return count;
125*858ea5e5SAndroid Build Coastguard Worker }
126*858ea5e5SAndroid Build Coastguard Worker 
disasm_init(void)127*858ea5e5SAndroid Build Coastguard Worker int disasm_init(void)
128*858ea5e5SAndroid Build Coastguard Worker {
129*858ea5e5SAndroid Build Coastguard Worker 	LLVMInitializeAllTargetInfos();
130*858ea5e5SAndroid Build Coastguard Worker 	LLVMInitializeAllTargetMCs();
131*858ea5e5SAndroid Build Coastguard Worker 	LLVMInitializeAllDisassemblers();
132*858ea5e5SAndroid Build Coastguard Worker 	return 0;
133*858ea5e5SAndroid Build Coastguard Worker }
134*858ea5e5SAndroid Build Coastguard Worker #endif /* HAVE_LLVM_SUPPORT */
135*858ea5e5SAndroid Build Coastguard Worker 
136*858ea5e5SAndroid Build Coastguard Worker #ifdef HAVE_LIBBFD_SUPPORT
137*858ea5e5SAndroid Build Coastguard Worker #define DISASM_SPACER "\t"
138*858ea5e5SAndroid Build Coastguard Worker 
139*858ea5e5SAndroid Build Coastguard Worker typedef struct {
140*858ea5e5SAndroid Build Coastguard Worker 	struct disassemble_info *info;
141*858ea5e5SAndroid Build Coastguard Worker 	disassembler_ftype disassemble;
142*858ea5e5SAndroid Build Coastguard Worker 	bfd *bfdf;
143*858ea5e5SAndroid Build Coastguard Worker } disasm_ctx_t;
144*858ea5e5SAndroid Build Coastguard Worker 
get_exec_path(char * tpath,size_t size)145*858ea5e5SAndroid Build Coastguard Worker static int get_exec_path(char *tpath, size_t size)
146*858ea5e5SAndroid Build Coastguard Worker {
147*858ea5e5SAndroid Build Coastguard Worker 	const char *path = "/proc/self/exe";
148*858ea5e5SAndroid Build Coastguard Worker 	ssize_t len;
149*858ea5e5SAndroid Build Coastguard Worker 
150*858ea5e5SAndroid Build Coastguard Worker 	len = readlink(path, tpath, size - 1);
151*858ea5e5SAndroid Build Coastguard Worker 	if (len <= 0)
152*858ea5e5SAndroid Build Coastguard Worker 		return -1;
153*858ea5e5SAndroid Build Coastguard Worker 
154*858ea5e5SAndroid Build Coastguard Worker 	tpath[len] = 0;
155*858ea5e5SAndroid Build Coastguard Worker 
156*858ea5e5SAndroid Build Coastguard Worker 	return 0;
157*858ea5e5SAndroid Build Coastguard Worker }
158*858ea5e5SAndroid Build Coastguard Worker 
printf_json(void * out,const char * fmt,va_list ap)159*858ea5e5SAndroid Build Coastguard Worker static int printf_json(void *out, const char *fmt, va_list ap)
160*858ea5e5SAndroid Build Coastguard Worker {
161*858ea5e5SAndroid Build Coastguard Worker 	char *s;
162*858ea5e5SAndroid Build Coastguard Worker 	int err;
163*858ea5e5SAndroid Build Coastguard Worker 
164*858ea5e5SAndroid Build Coastguard Worker 	err = vasprintf(&s, fmt, ap);
165*858ea5e5SAndroid Build Coastguard Worker 	if (err < 0)
166*858ea5e5SAndroid Build Coastguard Worker 		return -1;
167*858ea5e5SAndroid Build Coastguard Worker 
168*858ea5e5SAndroid Build Coastguard Worker 	if (!oper_count) {
169*858ea5e5SAndroid Build Coastguard Worker 		int i;
170*858ea5e5SAndroid Build Coastguard Worker 
171*858ea5e5SAndroid Build Coastguard Worker 		/* Strip trailing spaces */
172*858ea5e5SAndroid Build Coastguard Worker 		i = strlen(s) - 1;
173*858ea5e5SAndroid Build Coastguard Worker 		while (s[i] == ' ')
174*858ea5e5SAndroid Build Coastguard Worker 			s[i--] = '\0';
175*858ea5e5SAndroid Build Coastguard Worker 
176*858ea5e5SAndroid Build Coastguard Worker 		jsonw_string_field(json_wtr, "operation", s);
177*858ea5e5SAndroid Build Coastguard Worker 		jsonw_name(json_wtr, "operands");
178*858ea5e5SAndroid Build Coastguard Worker 		jsonw_start_array(json_wtr);
179*858ea5e5SAndroid Build Coastguard Worker 		oper_count++;
180*858ea5e5SAndroid Build Coastguard Worker 	} else if (!strcmp(fmt, ",")) {
181*858ea5e5SAndroid Build Coastguard Worker 		   /* Skip */
182*858ea5e5SAndroid Build Coastguard Worker 	} else {
183*858ea5e5SAndroid Build Coastguard Worker 		jsonw_string(json_wtr, s);
184*858ea5e5SAndroid Build Coastguard Worker 		oper_count++;
185*858ea5e5SAndroid Build Coastguard Worker 	}
186*858ea5e5SAndroid Build Coastguard Worker 	free(s);
187*858ea5e5SAndroid Build Coastguard Worker 	return 0;
188*858ea5e5SAndroid Build Coastguard Worker }
189*858ea5e5SAndroid Build Coastguard Worker 
fprintf_json(void * out,const char * fmt,...)190*858ea5e5SAndroid Build Coastguard Worker static int fprintf_json(void *out, const char *fmt, ...)
191*858ea5e5SAndroid Build Coastguard Worker {
192*858ea5e5SAndroid Build Coastguard Worker 	va_list ap;
193*858ea5e5SAndroid Build Coastguard Worker 	int r;
194*858ea5e5SAndroid Build Coastguard Worker 
195*858ea5e5SAndroid Build Coastguard Worker 	va_start(ap, fmt);
196*858ea5e5SAndroid Build Coastguard Worker 	r = printf_json(out, fmt, ap);
197*858ea5e5SAndroid Build Coastguard Worker 	va_end(ap);
198*858ea5e5SAndroid Build Coastguard Worker 
199*858ea5e5SAndroid Build Coastguard Worker 	return r;
200*858ea5e5SAndroid Build Coastguard Worker }
201*858ea5e5SAndroid Build Coastguard Worker 
fprintf_json_styled(void * out,enum disassembler_style style __maybe_unused,const char * fmt,...)202*858ea5e5SAndroid Build Coastguard Worker static int fprintf_json_styled(void *out,
203*858ea5e5SAndroid Build Coastguard Worker 			       enum disassembler_style style __maybe_unused,
204*858ea5e5SAndroid Build Coastguard Worker 			       const char *fmt, ...)
205*858ea5e5SAndroid Build Coastguard Worker {
206*858ea5e5SAndroid Build Coastguard Worker 	va_list ap;
207*858ea5e5SAndroid Build Coastguard Worker 	int r;
208*858ea5e5SAndroid Build Coastguard Worker 
209*858ea5e5SAndroid Build Coastguard Worker 	va_start(ap, fmt);
210*858ea5e5SAndroid Build Coastguard Worker 	r = printf_json(out, fmt, ap);
211*858ea5e5SAndroid Build Coastguard Worker 	va_end(ap);
212*858ea5e5SAndroid Build Coastguard Worker 
213*858ea5e5SAndroid Build Coastguard Worker 	return r;
214*858ea5e5SAndroid Build Coastguard Worker }
215*858ea5e5SAndroid Build Coastguard Worker 
init_context(disasm_ctx_t * ctx,const char * arch,const char * disassembler_options,unsigned char * image,ssize_t len)216*858ea5e5SAndroid Build Coastguard Worker static int init_context(disasm_ctx_t *ctx, const char *arch,
217*858ea5e5SAndroid Build Coastguard Worker 			const char *disassembler_options,
218*858ea5e5SAndroid Build Coastguard Worker 			unsigned char *image, ssize_t len)
219*858ea5e5SAndroid Build Coastguard Worker {
220*858ea5e5SAndroid Build Coastguard Worker 	struct disassemble_info *info;
221*858ea5e5SAndroid Build Coastguard Worker 	char tpath[PATH_MAX];
222*858ea5e5SAndroid Build Coastguard Worker 	bfd *bfdf;
223*858ea5e5SAndroid Build Coastguard Worker 
224*858ea5e5SAndroid Build Coastguard Worker 	memset(tpath, 0, sizeof(tpath));
225*858ea5e5SAndroid Build Coastguard Worker 	if (get_exec_path(tpath, sizeof(tpath))) {
226*858ea5e5SAndroid Build Coastguard Worker 		p_err("failed to create disassembler (get_exec_path)");
227*858ea5e5SAndroid Build Coastguard Worker 		return -1;
228*858ea5e5SAndroid Build Coastguard Worker 	}
229*858ea5e5SAndroid Build Coastguard Worker 
230*858ea5e5SAndroid Build Coastguard Worker 	ctx->bfdf = bfd_openr(tpath, NULL);
231*858ea5e5SAndroid Build Coastguard Worker 	if (!ctx->bfdf) {
232*858ea5e5SAndroid Build Coastguard Worker 		p_err("failed to create disassembler (bfd_openr)");
233*858ea5e5SAndroid Build Coastguard Worker 		return -1;
234*858ea5e5SAndroid Build Coastguard Worker 	}
235*858ea5e5SAndroid Build Coastguard Worker 	if (!bfd_check_format(ctx->bfdf, bfd_object)) {
236*858ea5e5SAndroid Build Coastguard Worker 		p_err("failed to create disassembler (bfd_check_format)");
237*858ea5e5SAndroid Build Coastguard Worker 		goto err_close;
238*858ea5e5SAndroid Build Coastguard Worker 	}
239*858ea5e5SAndroid Build Coastguard Worker 	bfdf = ctx->bfdf;
240*858ea5e5SAndroid Build Coastguard Worker 
241*858ea5e5SAndroid Build Coastguard Worker 	ctx->info = malloc(sizeof(struct disassemble_info));
242*858ea5e5SAndroid Build Coastguard Worker 	if (!ctx->info) {
243*858ea5e5SAndroid Build Coastguard Worker 		p_err("mem alloc failed");
244*858ea5e5SAndroid Build Coastguard Worker 		goto err_close;
245*858ea5e5SAndroid Build Coastguard Worker 	}
246*858ea5e5SAndroid Build Coastguard Worker 	info = ctx->info;
247*858ea5e5SAndroid Build Coastguard Worker 
248*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
249*858ea5e5SAndroid Build Coastguard Worker 		init_disassemble_info_compat(info, stdout,
250*858ea5e5SAndroid Build Coastguard Worker 					     (fprintf_ftype) fprintf_json,
251*858ea5e5SAndroid Build Coastguard Worker 					     fprintf_json_styled);
252*858ea5e5SAndroid Build Coastguard Worker 	else
253*858ea5e5SAndroid Build Coastguard Worker 		init_disassemble_info_compat(info, stdout,
254*858ea5e5SAndroid Build Coastguard Worker 					     (fprintf_ftype) fprintf,
255*858ea5e5SAndroid Build Coastguard Worker 					     fprintf_styled);
256*858ea5e5SAndroid Build Coastguard Worker 
257*858ea5e5SAndroid Build Coastguard Worker 	/* Update architecture info for offload. */
258*858ea5e5SAndroid Build Coastguard Worker 	if (arch) {
259*858ea5e5SAndroid Build Coastguard Worker 		const bfd_arch_info_type *inf = bfd_scan_arch(arch);
260*858ea5e5SAndroid Build Coastguard Worker 
261*858ea5e5SAndroid Build Coastguard Worker 		if (inf) {
262*858ea5e5SAndroid Build Coastguard Worker 			bfdf->arch_info = inf;
263*858ea5e5SAndroid Build Coastguard Worker 		} else {
264*858ea5e5SAndroid Build Coastguard Worker 			p_err("No libbfd support for %s", arch);
265*858ea5e5SAndroid Build Coastguard Worker 			goto err_free;
266*858ea5e5SAndroid Build Coastguard Worker 		}
267*858ea5e5SAndroid Build Coastguard Worker 	}
268*858ea5e5SAndroid Build Coastguard Worker 
269*858ea5e5SAndroid Build Coastguard Worker 	info->arch = bfd_get_arch(bfdf);
270*858ea5e5SAndroid Build Coastguard Worker 	info->mach = bfd_get_mach(bfdf);
271*858ea5e5SAndroid Build Coastguard Worker 	if (disassembler_options)
272*858ea5e5SAndroid Build Coastguard Worker 		info->disassembler_options = disassembler_options;
273*858ea5e5SAndroid Build Coastguard Worker 	info->buffer = image;
274*858ea5e5SAndroid Build Coastguard Worker 	info->buffer_length = len;
275*858ea5e5SAndroid Build Coastguard Worker 
276*858ea5e5SAndroid Build Coastguard Worker 	disassemble_init_for_target(info);
277*858ea5e5SAndroid Build Coastguard Worker 
278*858ea5e5SAndroid Build Coastguard Worker #ifdef DISASM_FOUR_ARGS_SIGNATURE
279*858ea5e5SAndroid Build Coastguard Worker 	ctx->disassemble = disassembler(info->arch,
280*858ea5e5SAndroid Build Coastguard Worker 					bfd_big_endian(bfdf),
281*858ea5e5SAndroid Build Coastguard Worker 					info->mach,
282*858ea5e5SAndroid Build Coastguard Worker 					bfdf);
283*858ea5e5SAndroid Build Coastguard Worker #else
284*858ea5e5SAndroid Build Coastguard Worker 	ctx->disassemble = disassembler(bfdf);
285*858ea5e5SAndroid Build Coastguard Worker #endif
286*858ea5e5SAndroid Build Coastguard Worker 	if (!ctx->disassemble) {
287*858ea5e5SAndroid Build Coastguard Worker 		p_err("failed to create disassembler");
288*858ea5e5SAndroid Build Coastguard Worker 		goto err_free;
289*858ea5e5SAndroid Build Coastguard Worker 	}
290*858ea5e5SAndroid Build Coastguard Worker 	return 0;
291*858ea5e5SAndroid Build Coastguard Worker 
292*858ea5e5SAndroid Build Coastguard Worker err_free:
293*858ea5e5SAndroid Build Coastguard Worker 	free(info);
294*858ea5e5SAndroid Build Coastguard Worker err_close:
295*858ea5e5SAndroid Build Coastguard Worker 	bfd_close(ctx->bfdf);
296*858ea5e5SAndroid Build Coastguard Worker 	return -1;
297*858ea5e5SAndroid Build Coastguard Worker }
298*858ea5e5SAndroid Build Coastguard Worker 
destroy_context(disasm_ctx_t * ctx)299*858ea5e5SAndroid Build Coastguard Worker static void destroy_context(disasm_ctx_t *ctx)
300*858ea5e5SAndroid Build Coastguard Worker {
301*858ea5e5SAndroid Build Coastguard Worker 	free(ctx->info);
302*858ea5e5SAndroid Build Coastguard Worker 	bfd_close(ctx->bfdf);
303*858ea5e5SAndroid Build Coastguard Worker }
304*858ea5e5SAndroid Build Coastguard Worker 
305*858ea5e5SAndroid Build Coastguard Worker static int
disassemble_insn(disasm_ctx_t * ctx,__maybe_unused unsigned char * image,__maybe_unused ssize_t len,int pc)306*858ea5e5SAndroid Build Coastguard Worker disassemble_insn(disasm_ctx_t *ctx, __maybe_unused unsigned char *image,
307*858ea5e5SAndroid Build Coastguard Worker 		 __maybe_unused ssize_t len, int pc)
308*858ea5e5SAndroid Build Coastguard Worker {
309*858ea5e5SAndroid Build Coastguard Worker 	return ctx->disassemble(pc, ctx->info);
310*858ea5e5SAndroid Build Coastguard Worker }
311*858ea5e5SAndroid Build Coastguard Worker 
disasm_init(void)312*858ea5e5SAndroid Build Coastguard Worker int disasm_init(void)
313*858ea5e5SAndroid Build Coastguard Worker {
314*858ea5e5SAndroid Build Coastguard Worker 	bfd_init();
315*858ea5e5SAndroid Build Coastguard Worker 	return 0;
316*858ea5e5SAndroid Build Coastguard Worker }
317*858ea5e5SAndroid Build Coastguard Worker #endif /* HAVE_LIBBPFD_SUPPORT */
318*858ea5e5SAndroid Build Coastguard Worker 
disasm_print_insn(unsigned char * image,ssize_t len,int opcodes,const char * arch,const char * disassembler_options,const struct btf * btf,const struct bpf_prog_linfo * prog_linfo,__u64 func_ksym,unsigned int func_idx,bool linum)319*858ea5e5SAndroid Build Coastguard Worker int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
320*858ea5e5SAndroid Build Coastguard Worker 		      const char *arch, const char *disassembler_options,
321*858ea5e5SAndroid Build Coastguard Worker 		      const struct btf *btf,
322*858ea5e5SAndroid Build Coastguard Worker 		      const struct bpf_prog_linfo *prog_linfo,
323*858ea5e5SAndroid Build Coastguard Worker 		      __u64 func_ksym, unsigned int func_idx,
324*858ea5e5SAndroid Build Coastguard Worker 		      bool linum)
325*858ea5e5SAndroid Build Coastguard Worker {
326*858ea5e5SAndroid Build Coastguard Worker 	const struct bpf_line_info *linfo = NULL;
327*858ea5e5SAndroid Build Coastguard Worker 	unsigned int nr_skip = 0;
328*858ea5e5SAndroid Build Coastguard Worker 	int count, i, pc = 0;
329*858ea5e5SAndroid Build Coastguard Worker 	disasm_ctx_t ctx;
330*858ea5e5SAndroid Build Coastguard Worker 
331*858ea5e5SAndroid Build Coastguard Worker 	if (!len)
332*858ea5e5SAndroid Build Coastguard Worker 		return -1;
333*858ea5e5SAndroid Build Coastguard Worker 
334*858ea5e5SAndroid Build Coastguard Worker 	if (init_context(&ctx, arch, disassembler_options, image, len))
335*858ea5e5SAndroid Build Coastguard Worker 		return -1;
336*858ea5e5SAndroid Build Coastguard Worker 
337*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
338*858ea5e5SAndroid Build Coastguard Worker 		jsonw_start_array(json_wtr);
339*858ea5e5SAndroid Build Coastguard Worker 	do {
340*858ea5e5SAndroid Build Coastguard Worker 		if (prog_linfo) {
341*858ea5e5SAndroid Build Coastguard Worker 			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
342*858ea5e5SAndroid Build Coastguard Worker 								func_ksym + pc,
343*858ea5e5SAndroid Build Coastguard Worker 								func_idx,
344*858ea5e5SAndroid Build Coastguard Worker 								nr_skip);
345*858ea5e5SAndroid Build Coastguard Worker 			if (linfo)
346*858ea5e5SAndroid Build Coastguard Worker 				nr_skip++;
347*858ea5e5SAndroid Build Coastguard Worker 		}
348*858ea5e5SAndroid Build Coastguard Worker 
349*858ea5e5SAndroid Build Coastguard Worker 		if (json_output) {
350*858ea5e5SAndroid Build Coastguard Worker 			jsonw_start_object(json_wtr);
351*858ea5e5SAndroid Build Coastguard Worker 			oper_count = 0;
352*858ea5e5SAndroid Build Coastguard Worker 			if (linfo)
353*858ea5e5SAndroid Build Coastguard Worker 				btf_dump_linfo_json(btf, linfo, linum);
354*858ea5e5SAndroid Build Coastguard Worker 			jsonw_name(json_wtr, "pc");
355*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(json_wtr, "\"0x%x\"", pc);
356*858ea5e5SAndroid Build Coastguard Worker 		} else {
357*858ea5e5SAndroid Build Coastguard Worker 			if (linfo)
358*858ea5e5SAndroid Build Coastguard Worker 				btf_dump_linfo_plain(btf, linfo, "; ",
359*858ea5e5SAndroid Build Coastguard Worker 						     linum);
360*858ea5e5SAndroid Build Coastguard Worker 			printf("%4x:" DISASM_SPACER, pc);
361*858ea5e5SAndroid Build Coastguard Worker 		}
362*858ea5e5SAndroid Build Coastguard Worker 
363*858ea5e5SAndroid Build Coastguard Worker 		count = disassemble_insn(&ctx, image, len, pc);
364*858ea5e5SAndroid Build Coastguard Worker 
365*858ea5e5SAndroid Build Coastguard Worker 		if (json_output) {
366*858ea5e5SAndroid Build Coastguard Worker 			/* Operand array, was started in fprintf_json. Before
367*858ea5e5SAndroid Build Coastguard Worker 			 * that, make sure we have a _null_ value if no operand
368*858ea5e5SAndroid Build Coastguard Worker 			 * other than operation code was present.
369*858ea5e5SAndroid Build Coastguard Worker 			 */
370*858ea5e5SAndroid Build Coastguard Worker 			if (oper_count == 1)
371*858ea5e5SAndroid Build Coastguard Worker 				jsonw_null(json_wtr);
372*858ea5e5SAndroid Build Coastguard Worker 			jsonw_end_array(json_wtr);
373*858ea5e5SAndroid Build Coastguard Worker 		}
374*858ea5e5SAndroid Build Coastguard Worker 
375*858ea5e5SAndroid Build Coastguard Worker 		if (opcodes) {
376*858ea5e5SAndroid Build Coastguard Worker 			if (json_output) {
377*858ea5e5SAndroid Build Coastguard Worker 				jsonw_name(json_wtr, "opcodes");
378*858ea5e5SAndroid Build Coastguard Worker 				jsonw_start_array(json_wtr);
379*858ea5e5SAndroid Build Coastguard Worker 				for (i = 0; i < count; ++i)
380*858ea5e5SAndroid Build Coastguard Worker 					jsonw_printf(json_wtr, "\"0x%02hhx\"",
381*858ea5e5SAndroid Build Coastguard Worker 						     (uint8_t)image[pc + i]);
382*858ea5e5SAndroid Build Coastguard Worker 				jsonw_end_array(json_wtr);
383*858ea5e5SAndroid Build Coastguard Worker 			} else {
384*858ea5e5SAndroid Build Coastguard Worker 				printf("\n\t");
385*858ea5e5SAndroid Build Coastguard Worker 				for (i = 0; i < count; ++i)
386*858ea5e5SAndroid Build Coastguard Worker 					printf("%02x ",
387*858ea5e5SAndroid Build Coastguard Worker 					       (uint8_t)image[pc + i]);
388*858ea5e5SAndroid Build Coastguard Worker 			}
389*858ea5e5SAndroid Build Coastguard Worker 		}
390*858ea5e5SAndroid Build Coastguard Worker 		if (json_output)
391*858ea5e5SAndroid Build Coastguard Worker 			jsonw_end_object(json_wtr);
392*858ea5e5SAndroid Build Coastguard Worker 		else
393*858ea5e5SAndroid Build Coastguard Worker 			printf("\n");
394*858ea5e5SAndroid Build Coastguard Worker 
395*858ea5e5SAndroid Build Coastguard Worker 		pc += count;
396*858ea5e5SAndroid Build Coastguard Worker 	} while (count > 0 && pc < len);
397*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
398*858ea5e5SAndroid Build Coastguard Worker 		jsonw_end_array(json_wtr);
399*858ea5e5SAndroid Build Coastguard Worker 
400*858ea5e5SAndroid Build Coastguard Worker 	destroy_context(&ctx);
401*858ea5e5SAndroid Build Coastguard Worker 
402*858ea5e5SAndroid Build Coastguard Worker 	return 0;
403*858ea5e5SAndroid Build Coastguard Worker }
404