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