Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
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
14#include <stdarg.h>
15#include <stdint.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <assert.h>
19#include <unistd.h>
20#include <string.h>
21#include <bfd.h>
22#include <dis-asm.h>
23#include <sys/stat.h>
24#include <limits.h>
25#include <libbpf.h>
26
27#include "json_writer.h"
28#include "main.h"
29
30static void get_exec_path(char *tpath, size_t size)
31{
32 const char *path = "/proc/self/exe";
33 ssize_t len;
34
35 len = readlink(path, tpath, size - 1);
36 assert(len > 0);
37 tpath[len] = 0;
38}
39
40static int oper_count;
41static int fprintf_json(void *out, const char *fmt, ...)
42{
43 va_list ap;
44 char *s;
45
46 va_start(ap, fmt);
47 if (!oper_count) {
48 int i;
49
50 s = va_arg(ap, char *);
51
52 /* Strip trailing spaces */
53 i = strlen(s) - 1;
54 while (s[i] == ' ')
55 s[i--] = '\0';
56
57 jsonw_string_field(json_wtr, "operation", s);
58 jsonw_name(json_wtr, "operands");
59 jsonw_start_array(json_wtr);
60 oper_count++;
61 } else if (!strcmp(fmt, ",")) {
62 /* Skip */
63 } else {
64 s = va_arg(ap, char *);
65 jsonw_string(json_wtr, s);
66 oper_count++;
67 }
68 va_end(ap);
69 return 0;
70}
71
72void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
73 const char *arch, const char *disassembler_options,
74 const struct btf *btf,
75 const struct bpf_prog_linfo *prog_linfo,
76 __u64 func_ksym, unsigned int func_idx,
77 bool linum)
78{
79 const struct bpf_line_info *linfo = NULL;
80 disassembler_ftype disassemble;
81 struct disassemble_info info;
82 unsigned int nr_skip = 0;
83 int count, i, pc = 0;
84 char tpath[PATH_MAX];
85 bfd *bfdf;
86
87 if (!len)
88 return;
89
90 memset(tpath, 0, sizeof(tpath));
91 get_exec_path(tpath, sizeof(tpath));
92
93 bfdf = bfd_openr(tpath, NULL);
94 assert(bfdf);
95 assert(bfd_check_format(bfdf, bfd_object));
96
97 if (json_output)
98 init_disassemble_info(&info, stdout,
99 (fprintf_ftype) fprintf_json);
100 else
101 init_disassemble_info(&info, stdout,
102 (fprintf_ftype) fprintf);
103
104 /* Update architecture info for offload. */
105 if (arch) {
106 const bfd_arch_info_type *inf = bfd_scan_arch(arch);
107
108 if (inf) {
109 bfdf->arch_info = inf;
110 } else {
111 p_err("No libbfd support for %s", arch);
112 return;
113 }
114 }
115
116 info.arch = bfd_get_arch(bfdf);
117 info.mach = bfd_get_mach(bfdf);
118 if (disassembler_options)
119 info.disassembler_options = disassembler_options;
120 info.buffer = image;
121 info.buffer_length = len;
122
123 disassemble_init_for_target(&info);
124
125#ifdef DISASM_FOUR_ARGS_SIGNATURE
126 disassemble = disassembler(info.arch,
127 bfd_big_endian(bfdf),
128 info.mach,
129 bfdf);
130#else
131 disassemble = disassembler(bfdf);
132#endif
133 assert(disassemble);
134
135 if (json_output)
136 jsonw_start_array(json_wtr);
137 do {
138 if (prog_linfo) {
139 linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
140 func_ksym + pc,
141 func_idx,
142 nr_skip);
143 if (linfo)
144 nr_skip++;
145 }
146
147 if (json_output) {
148 jsonw_start_object(json_wtr);
149 oper_count = 0;
150 if (linfo)
151 btf_dump_linfo_json(btf, linfo, linum);
152 jsonw_name(json_wtr, "pc");
153 jsonw_printf(json_wtr, "\"0x%x\"", pc);
154 } else {
155 if (linfo)
156 btf_dump_linfo_plain(btf, linfo, "; ",
157 linum);
158 printf("%4x:\t", pc);
159 }
160
161 count = disassemble(pc, &info);
162 if (json_output) {
163 /* Operand array, was started in fprintf_json. Before
164 * that, make sure we have a _null_ value if no operand
165 * other than operation code was present.
166 */
167 if (oper_count == 1)
168 jsonw_null(json_wtr);
169 jsonw_end_array(json_wtr);
170 }
171
172 if (opcodes) {
173 if (json_output) {
174 jsonw_name(json_wtr, "opcodes");
175 jsonw_start_array(json_wtr);
176 for (i = 0; i < count; ++i)
177 jsonw_printf(json_wtr, "\"0x%02hhx\"",
178 (uint8_t)image[pc + i]);
179 jsonw_end_array(json_wtr);
180 } else {
181 printf("\n\t");
182 for (i = 0; i < count; ++i)
183 printf("%02x ",
184 (uint8_t)image[pc + i]);
185 }
186 }
187 if (json_output)
188 jsonw_end_object(json_wtr);
189 else
190 printf("\n");
191
192 pc += count;
193 } while (count > 0 && pc < len);
194 if (json_output)
195 jsonw_end_array(json_wtr);
196
197 bfd_close(bfdf);
198}
199
200int disasm_init(void)
201{
202 bfd_init();
203 return 0;
204}