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