xref: /linux/tools/bpf/bpftool/jit_disasm.c (revision cad4977344b35ea116ec5fefe91a76b1dfa113f5)
1 /*
2  * Based on:
3  *
4  * Minimal BPF JIT image disassembler
5  *
6  * Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
7  * debugging or verification purposes.
8  *
9  * Copyright 2013 Daniel Borkmann <daniel@iogearbox.net>
10  * Licensed under the GNU General Public License, version 2.0 (GPLv2)
11  */
12 
13 #include <stdarg.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <assert.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <bfd.h>
21 #include <dis-asm.h>
22 #include <sys/stat.h>
23 #include <limits.h>
24 
25 #include "json_writer.h"
26 #include "main.h"
27 
28 static void get_exec_path(char *tpath, size_t size)
29 {
30 	const char *path = "/proc/self/exe";
31 	ssize_t len;
32 
33 	len = readlink(path, tpath, size - 1);
34 	assert(len > 0);
35 	tpath[len] = 0;
36 }
37 
38 static int oper_count;
39 static int fprintf_json(void *out, const char *fmt, ...)
40 {
41 	va_list ap;
42 	char *s;
43 
44 	va_start(ap, fmt);
45 	if (!oper_count) {
46 		int i;
47 
48 		s = va_arg(ap, char *);
49 
50 		/* Strip trailing spaces */
51 		i = strlen(s) - 1;
52 		while (s[i] == ' ')
53 			s[i--] = '\0';
54 
55 		jsonw_string_field(json_wtr, "operation", s);
56 		jsonw_name(json_wtr, "operands");
57 		jsonw_start_array(json_wtr);
58 		oper_count++;
59 	} else if (!strcmp(fmt, ",")) {
60 		   /* Skip */
61 	} else {
62 		s = va_arg(ap, char *);
63 		jsonw_string(json_wtr, s);
64 		oper_count++;
65 	}
66 	va_end(ap);
67 	return 0;
68 }
69 
70 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
71 		       const char *arch, const char *disassembler_options)
72 {
73 	disassembler_ftype disassemble;
74 	struct disassemble_info info;
75 	int count, i, pc = 0;
76 	char tpath[PATH_MAX];
77 	bfd *bfdf;
78 
79 	if (!len)
80 		return;
81 
82 	memset(tpath, 0, sizeof(tpath));
83 	get_exec_path(tpath, sizeof(tpath));
84 
85 	bfdf = bfd_openr(tpath, NULL);
86 	assert(bfdf);
87 	assert(bfd_check_format(bfdf, bfd_object));
88 
89 	if (json_output)
90 		init_disassemble_info(&info, stdout,
91 				      (fprintf_ftype) fprintf_json);
92 	else
93 		init_disassemble_info(&info, stdout,
94 				      (fprintf_ftype) fprintf);
95 
96 	/* Update architecture info for offload. */
97 	if (arch) {
98 		const bfd_arch_info_type *inf = bfd_scan_arch(arch);
99 
100 		if (inf) {
101 			bfdf->arch_info = inf;
102 		} else {
103 			p_err("No libbfd support for %s", arch);
104 			return;
105 		}
106 	}
107 
108 	info.arch = bfd_get_arch(bfdf);
109 	info.mach = bfd_get_mach(bfdf);
110 	if (disassembler_options)
111 		info.disassembler_options = disassembler_options;
112 	info.buffer = image;
113 	info.buffer_length = len;
114 
115 	disassemble_init_for_target(&info);
116 
117 #ifdef DISASM_FOUR_ARGS_SIGNATURE
118 	disassemble = disassembler(info.arch,
119 				   bfd_big_endian(bfdf),
120 				   info.mach,
121 				   bfdf);
122 #else
123 	disassemble = disassembler(bfdf);
124 #endif
125 	assert(disassemble);
126 
127 	if (json_output)
128 		jsonw_start_array(json_wtr);
129 	do {
130 		if (json_output) {
131 			jsonw_start_object(json_wtr);
132 			oper_count = 0;
133 			jsonw_name(json_wtr, "pc");
134 			jsonw_printf(json_wtr, "\"0x%x\"", pc);
135 		} else {
136 			printf("%4x:\t", pc);
137 		}
138 
139 		count = disassemble(pc, &info);
140 		if (json_output) {
141 			/* Operand array, was started in fprintf_json. Before
142 			 * that, make sure we have a _null_ value if no operand
143 			 * other than operation code was present.
144 			 */
145 			if (oper_count == 1)
146 				jsonw_null(json_wtr);
147 			jsonw_end_array(json_wtr);
148 		}
149 
150 		if (opcodes) {
151 			if (json_output) {
152 				jsonw_name(json_wtr, "opcodes");
153 				jsonw_start_array(json_wtr);
154 				for (i = 0; i < count; ++i)
155 					jsonw_printf(json_wtr, "\"0x%02hhx\"",
156 						     (uint8_t)image[pc + i]);
157 				jsonw_end_array(json_wtr);
158 			} else {
159 				printf("\n\t");
160 				for (i = 0; i < count; ++i)
161 					printf("%02x ",
162 					       (uint8_t)image[pc + i]);
163 			}
164 		}
165 		if (json_output)
166 			jsonw_end_object(json_wtr);
167 		else
168 			printf("\n");
169 
170 		pc += count;
171 	} while (count > 0 && pc < len);
172 	if (json_output)
173 		jsonw_end_array(json_wtr);
174 
175 	bfd_close(bfdf);
176 }
177 
178 int disasm_init(void)
179 {
180 	bfd_init();
181 	return 0;
182 }
183