xref: /OK3568_Linux_fs/kernel/tools/bpf/bpftool/xlated_dumper.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*4882a593Smuzhiyun /* Copyright (C) 2018 Netronome Systems, Inc. */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #define _GNU_SOURCE
5*4882a593Smuzhiyun #include <stdarg.h>
6*4882a593Smuzhiyun #include <stdio.h>
7*4882a593Smuzhiyun #include <stdlib.h>
8*4882a593Smuzhiyun #include <string.h>
9*4882a593Smuzhiyun #include <sys/types.h>
10*4882a593Smuzhiyun #include <bpf/libbpf.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "disasm.h"
13*4882a593Smuzhiyun #include "json_writer.h"
14*4882a593Smuzhiyun #include "main.h"
15*4882a593Smuzhiyun #include "xlated_dumper.h"
16*4882a593Smuzhiyun 
kernel_syms_cmp(const void * sym_a,const void * sym_b)17*4882a593Smuzhiyun static int kernel_syms_cmp(const void *sym_a, const void *sym_b)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun 	return ((struct kernel_sym *)sym_a)->address -
20*4882a593Smuzhiyun 	       ((struct kernel_sym *)sym_b)->address;
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun 
kernel_syms_load(struct dump_data * dd)23*4882a593Smuzhiyun void kernel_syms_load(struct dump_data *dd)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	struct kernel_sym *sym;
26*4882a593Smuzhiyun 	char buff[256];
27*4882a593Smuzhiyun 	void *tmp, *address;
28*4882a593Smuzhiyun 	FILE *fp;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	fp = fopen("/proc/kallsyms", "r");
31*4882a593Smuzhiyun 	if (!fp)
32*4882a593Smuzhiyun 		return;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	while (fgets(buff, sizeof(buff), fp)) {
35*4882a593Smuzhiyun 		tmp = reallocarray(dd->sym_mapping, dd->sym_count + 1,
36*4882a593Smuzhiyun 				   sizeof(*dd->sym_mapping));
37*4882a593Smuzhiyun 		if (!tmp) {
38*4882a593Smuzhiyun out:
39*4882a593Smuzhiyun 			free(dd->sym_mapping);
40*4882a593Smuzhiyun 			dd->sym_mapping = NULL;
41*4882a593Smuzhiyun 			fclose(fp);
42*4882a593Smuzhiyun 			return;
43*4882a593Smuzhiyun 		}
44*4882a593Smuzhiyun 		dd->sym_mapping = tmp;
45*4882a593Smuzhiyun 		sym = &dd->sym_mapping[dd->sym_count];
46*4882a593Smuzhiyun 		if (sscanf(buff, "%p %*c %s", &address, sym->name) != 2)
47*4882a593Smuzhiyun 			continue;
48*4882a593Smuzhiyun 		sym->address = (unsigned long)address;
49*4882a593Smuzhiyun 		if (!strcmp(sym->name, "__bpf_call_base")) {
50*4882a593Smuzhiyun 			dd->address_call_base = sym->address;
51*4882a593Smuzhiyun 			/* sysctl kernel.kptr_restrict was set */
52*4882a593Smuzhiyun 			if (!sym->address)
53*4882a593Smuzhiyun 				goto out;
54*4882a593Smuzhiyun 		}
55*4882a593Smuzhiyun 		if (sym->address)
56*4882a593Smuzhiyun 			dd->sym_count++;
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	fclose(fp);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	qsort(dd->sym_mapping, dd->sym_count,
62*4882a593Smuzhiyun 	      sizeof(*dd->sym_mapping), kernel_syms_cmp);
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
kernel_syms_destroy(struct dump_data * dd)65*4882a593Smuzhiyun void kernel_syms_destroy(struct dump_data *dd)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	free(dd->sym_mapping);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
kernel_syms_search(struct dump_data * dd,unsigned long key)70*4882a593Smuzhiyun struct kernel_sym *kernel_syms_search(struct dump_data *dd,
71*4882a593Smuzhiyun 				      unsigned long key)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	struct kernel_sym sym = {
74*4882a593Smuzhiyun 		.address = key,
75*4882a593Smuzhiyun 	};
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return dd->sym_mapping ?
78*4882a593Smuzhiyun 	       bsearch(&sym, dd->sym_mapping, dd->sym_count,
79*4882a593Smuzhiyun 		       sizeof(*dd->sym_mapping), kernel_syms_cmp) : NULL;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
print_insn(void * private_data,const char * fmt,...)82*4882a593Smuzhiyun static void __printf(2, 3) print_insn(void *private_data, const char *fmt, ...)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	va_list args;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	va_start(args, fmt);
87*4882a593Smuzhiyun 	vprintf(fmt, args);
88*4882a593Smuzhiyun 	va_end(args);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun static void __printf(2, 3)
print_insn_for_graph(void * private_data,const char * fmt,...)92*4882a593Smuzhiyun print_insn_for_graph(void *private_data, const char *fmt, ...)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	char buf[64], *p;
95*4882a593Smuzhiyun 	va_list args;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	va_start(args, fmt);
98*4882a593Smuzhiyun 	vsnprintf(buf, sizeof(buf), fmt, args);
99*4882a593Smuzhiyun 	va_end(args);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	p = buf;
102*4882a593Smuzhiyun 	while (*p != '\0') {
103*4882a593Smuzhiyun 		if (*p == '\n') {
104*4882a593Smuzhiyun 			memmove(p + 3, p, strlen(buf) + 1 - (p - buf));
105*4882a593Smuzhiyun 			/* Align each instruction dump row left. */
106*4882a593Smuzhiyun 			*p++ = '\\';
107*4882a593Smuzhiyun 			*p++ = 'l';
108*4882a593Smuzhiyun 			/* Output multiline concatenation. */
109*4882a593Smuzhiyun 			*p++ = '\\';
110*4882a593Smuzhiyun 		} else if (*p == '<' || *p == '>' || *p == '|' || *p == '&') {
111*4882a593Smuzhiyun 			memmove(p + 1, p, strlen(buf) + 1 - (p - buf));
112*4882a593Smuzhiyun 			/* Escape special character. */
113*4882a593Smuzhiyun 			*p++ = '\\';
114*4882a593Smuzhiyun 		}
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 		p++;
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	printf("%s", buf);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun static void __printf(2, 3)
print_insn_json(void * private_data,const char * fmt,...)123*4882a593Smuzhiyun print_insn_json(void *private_data, const char *fmt, ...)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	unsigned int l = strlen(fmt);
126*4882a593Smuzhiyun 	char chomped_fmt[l];
127*4882a593Smuzhiyun 	va_list args;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	va_start(args, fmt);
130*4882a593Smuzhiyun 	if (l > 0) {
131*4882a593Smuzhiyun 		strncpy(chomped_fmt, fmt, l - 1);
132*4882a593Smuzhiyun 		chomped_fmt[l - 1] = '\0';
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 	jsonw_vprintf_enquote(json_wtr, chomped_fmt, args);
135*4882a593Smuzhiyun 	va_end(args);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
print_call_pcrel(struct dump_data * dd,struct kernel_sym * sym,unsigned long address,const struct bpf_insn * insn)138*4882a593Smuzhiyun static const char *print_call_pcrel(struct dump_data *dd,
139*4882a593Smuzhiyun 				    struct kernel_sym *sym,
140*4882a593Smuzhiyun 				    unsigned long address,
141*4882a593Smuzhiyun 				    const struct bpf_insn *insn)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	if (!dd->nr_jited_ksyms)
144*4882a593Smuzhiyun 		/* Do not show address for interpreted programs */
145*4882a593Smuzhiyun 		snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
146*4882a593Smuzhiyun 			"%+d", insn->off);
147*4882a593Smuzhiyun 	else if (sym)
148*4882a593Smuzhiyun 		snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
149*4882a593Smuzhiyun 			 "%+d#%s", insn->off, sym->name);
150*4882a593Smuzhiyun 	else
151*4882a593Smuzhiyun 		snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
152*4882a593Smuzhiyun 			 "%+d#0x%lx", insn->off, address);
153*4882a593Smuzhiyun 	return dd->scratch_buff;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
print_call_helper(struct dump_data * dd,struct kernel_sym * sym,unsigned long address)156*4882a593Smuzhiyun static const char *print_call_helper(struct dump_data *dd,
157*4882a593Smuzhiyun 				     struct kernel_sym *sym,
158*4882a593Smuzhiyun 				     unsigned long address)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	if (sym)
161*4882a593Smuzhiyun 		snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
162*4882a593Smuzhiyun 			 "%s", sym->name);
163*4882a593Smuzhiyun 	else
164*4882a593Smuzhiyun 		snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
165*4882a593Smuzhiyun 			 "0x%lx", address);
166*4882a593Smuzhiyun 	return dd->scratch_buff;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
print_call(void * private_data,const struct bpf_insn * insn)169*4882a593Smuzhiyun static const char *print_call(void *private_data,
170*4882a593Smuzhiyun 			      const struct bpf_insn *insn)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct dump_data *dd = private_data;
173*4882a593Smuzhiyun 	unsigned long address = dd->address_call_base + insn->imm;
174*4882a593Smuzhiyun 	struct kernel_sym *sym;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (insn->src_reg == BPF_PSEUDO_CALL &&
177*4882a593Smuzhiyun 	    (__u32) insn->imm < dd->nr_jited_ksyms && dd->jited_ksyms)
178*4882a593Smuzhiyun 		address = dd->jited_ksyms[insn->imm];
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	sym = kernel_syms_search(dd, address);
181*4882a593Smuzhiyun 	if (insn->src_reg == BPF_PSEUDO_CALL)
182*4882a593Smuzhiyun 		return print_call_pcrel(dd, sym, address, insn);
183*4882a593Smuzhiyun 	else
184*4882a593Smuzhiyun 		return print_call_helper(dd, sym, address);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
print_imm(void * private_data,const struct bpf_insn * insn,__u64 full_imm)187*4882a593Smuzhiyun static const char *print_imm(void *private_data,
188*4882a593Smuzhiyun 			     const struct bpf_insn *insn,
189*4882a593Smuzhiyun 			     __u64 full_imm)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	struct dump_data *dd = private_data;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	if (insn->src_reg == BPF_PSEUDO_MAP_FD)
194*4882a593Smuzhiyun 		snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
195*4882a593Smuzhiyun 			 "map[id:%u]", insn->imm);
196*4882a593Smuzhiyun 	else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE)
197*4882a593Smuzhiyun 		snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
198*4882a593Smuzhiyun 			 "map[id:%u][0]+%u", insn->imm, (insn + 1)->imm);
199*4882a593Smuzhiyun 	else
200*4882a593Smuzhiyun 		snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
201*4882a593Smuzhiyun 			 "0x%llx", (unsigned long long)full_imm);
202*4882a593Smuzhiyun 	return dd->scratch_buff;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
dump_xlated_json(struct dump_data * dd,void * buf,unsigned int len,bool opcodes,bool linum)205*4882a593Smuzhiyun void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
206*4882a593Smuzhiyun 		      bool opcodes, bool linum)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo;
209*4882a593Smuzhiyun 	const struct bpf_insn_cbs cbs = {
210*4882a593Smuzhiyun 		.cb_print	= print_insn_json,
211*4882a593Smuzhiyun 		.cb_call	= print_call,
212*4882a593Smuzhiyun 		.cb_imm		= print_imm,
213*4882a593Smuzhiyun 		.private_data	= dd,
214*4882a593Smuzhiyun 	};
215*4882a593Smuzhiyun 	struct bpf_func_info *record;
216*4882a593Smuzhiyun 	struct bpf_insn *insn = buf;
217*4882a593Smuzhiyun 	struct btf *btf = dd->btf;
218*4882a593Smuzhiyun 	bool double_insn = false;
219*4882a593Smuzhiyun 	unsigned int nr_skip = 0;
220*4882a593Smuzhiyun 	char func_sig[1024];
221*4882a593Smuzhiyun 	unsigned int i;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	jsonw_start_array(json_wtr);
224*4882a593Smuzhiyun 	record = dd->func_info;
225*4882a593Smuzhiyun 	for (i = 0; i < len / sizeof(*insn); i++) {
226*4882a593Smuzhiyun 		if (double_insn) {
227*4882a593Smuzhiyun 			double_insn = false;
228*4882a593Smuzhiyun 			continue;
229*4882a593Smuzhiyun 		}
230*4882a593Smuzhiyun 		double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 		jsonw_start_object(json_wtr);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 		if (btf && record) {
235*4882a593Smuzhiyun 			if (record->insn_off == i) {
236*4882a593Smuzhiyun 				btf_dumper_type_only(btf, record->type_id,
237*4882a593Smuzhiyun 						     func_sig,
238*4882a593Smuzhiyun 						     sizeof(func_sig));
239*4882a593Smuzhiyun 				if (func_sig[0] != '\0') {
240*4882a593Smuzhiyun 					jsonw_name(json_wtr, "proto");
241*4882a593Smuzhiyun 					jsonw_string(json_wtr, func_sig);
242*4882a593Smuzhiyun 				}
243*4882a593Smuzhiyun 				record = (void *)record + dd->finfo_rec_size;
244*4882a593Smuzhiyun 			}
245*4882a593Smuzhiyun 		}
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 		if (prog_linfo) {
248*4882a593Smuzhiyun 			const struct bpf_line_info *linfo;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 			linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip);
251*4882a593Smuzhiyun 			if (linfo) {
252*4882a593Smuzhiyun 				btf_dump_linfo_json(btf, linfo, linum);
253*4882a593Smuzhiyun 				nr_skip++;
254*4882a593Smuzhiyun 			}
255*4882a593Smuzhiyun 		}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		jsonw_name(json_wtr, "disasm");
258*4882a593Smuzhiyun 		print_bpf_insn(&cbs, insn + i, true);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 		if (opcodes) {
261*4882a593Smuzhiyun 			jsonw_name(json_wtr, "opcodes");
262*4882a593Smuzhiyun 			jsonw_start_object(json_wtr);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 			jsonw_name(json_wtr, "code");
265*4882a593Smuzhiyun 			jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 			jsonw_name(json_wtr, "src_reg");
268*4882a593Smuzhiyun 			jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 			jsonw_name(json_wtr, "dst_reg");
271*4882a593Smuzhiyun 			jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 			jsonw_name(json_wtr, "off");
274*4882a593Smuzhiyun 			print_hex_data_json((uint8_t *)(&insn[i].off), 2);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 			jsonw_name(json_wtr, "imm");
277*4882a593Smuzhiyun 			if (double_insn && i < len - 1)
278*4882a593Smuzhiyun 				print_hex_data_json((uint8_t *)(&insn[i].imm),
279*4882a593Smuzhiyun 						    12);
280*4882a593Smuzhiyun 			else
281*4882a593Smuzhiyun 				print_hex_data_json((uint8_t *)(&insn[i].imm),
282*4882a593Smuzhiyun 						    4);
283*4882a593Smuzhiyun 			jsonw_end_object(json_wtr);
284*4882a593Smuzhiyun 		}
285*4882a593Smuzhiyun 		jsonw_end_object(json_wtr);
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 	jsonw_end_array(json_wtr);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
dump_xlated_plain(struct dump_data * dd,void * buf,unsigned int len,bool opcodes,bool linum)290*4882a593Smuzhiyun void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
291*4882a593Smuzhiyun 		       bool opcodes, bool linum)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo;
294*4882a593Smuzhiyun 	const struct bpf_insn_cbs cbs = {
295*4882a593Smuzhiyun 		.cb_print	= print_insn,
296*4882a593Smuzhiyun 		.cb_call	= print_call,
297*4882a593Smuzhiyun 		.cb_imm		= print_imm,
298*4882a593Smuzhiyun 		.private_data	= dd,
299*4882a593Smuzhiyun 	};
300*4882a593Smuzhiyun 	struct bpf_func_info *record;
301*4882a593Smuzhiyun 	struct bpf_insn *insn = buf;
302*4882a593Smuzhiyun 	struct btf *btf = dd->btf;
303*4882a593Smuzhiyun 	unsigned int nr_skip = 0;
304*4882a593Smuzhiyun 	bool double_insn = false;
305*4882a593Smuzhiyun 	char func_sig[1024];
306*4882a593Smuzhiyun 	unsigned int i;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	record = dd->func_info;
309*4882a593Smuzhiyun 	for (i = 0; i < len / sizeof(*insn); i++) {
310*4882a593Smuzhiyun 		if (double_insn) {
311*4882a593Smuzhiyun 			double_insn = false;
312*4882a593Smuzhiyun 			continue;
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 		if (btf && record) {
316*4882a593Smuzhiyun 			if (record->insn_off == i) {
317*4882a593Smuzhiyun 				btf_dumper_type_only(btf, record->type_id,
318*4882a593Smuzhiyun 						     func_sig,
319*4882a593Smuzhiyun 						     sizeof(func_sig));
320*4882a593Smuzhiyun 				if (func_sig[0] != '\0')
321*4882a593Smuzhiyun 					printf("%s:\n", func_sig);
322*4882a593Smuzhiyun 				record = (void *)record + dd->finfo_rec_size;
323*4882a593Smuzhiyun 			}
324*4882a593Smuzhiyun 		}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 		if (prog_linfo) {
327*4882a593Smuzhiyun 			const struct bpf_line_info *linfo;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 			linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip);
330*4882a593Smuzhiyun 			if (linfo) {
331*4882a593Smuzhiyun 				btf_dump_linfo_plain(btf, linfo, "; ",
332*4882a593Smuzhiyun 						     linum);
333*4882a593Smuzhiyun 				nr_skip++;
334*4882a593Smuzhiyun 			}
335*4882a593Smuzhiyun 		}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 		double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 		printf("% 4d: ", i);
340*4882a593Smuzhiyun 		print_bpf_insn(&cbs, insn + i, true);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 		if (opcodes) {
343*4882a593Smuzhiyun 			printf("       ");
344*4882a593Smuzhiyun 			fprint_hex(stdout, insn + i, 8, " ");
345*4882a593Smuzhiyun 			if (double_insn && i < len - 1) {
346*4882a593Smuzhiyun 				printf(" ");
347*4882a593Smuzhiyun 				fprint_hex(stdout, insn + i + 1, 8, " ");
348*4882a593Smuzhiyun 			}
349*4882a593Smuzhiyun 			printf("\n");
350*4882a593Smuzhiyun 		}
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
dump_xlated_for_graph(struct dump_data * dd,void * buf_start,void * buf_end,unsigned int start_idx)354*4882a593Smuzhiyun void dump_xlated_for_graph(struct dump_data *dd, void *buf_start, void *buf_end,
355*4882a593Smuzhiyun 			   unsigned int start_idx)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	const struct bpf_insn_cbs cbs = {
358*4882a593Smuzhiyun 		.cb_print	= print_insn_for_graph,
359*4882a593Smuzhiyun 		.cb_call	= print_call,
360*4882a593Smuzhiyun 		.cb_imm		= print_imm,
361*4882a593Smuzhiyun 		.private_data	= dd,
362*4882a593Smuzhiyun 	};
363*4882a593Smuzhiyun 	struct bpf_insn *insn_start = buf_start;
364*4882a593Smuzhiyun 	struct bpf_insn *insn_end = buf_end;
365*4882a593Smuzhiyun 	struct bpf_insn *cur = insn_start;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	for (; cur <= insn_end; cur++) {
368*4882a593Smuzhiyun 		printf("% 4d: ", (int)(cur - insn_start + start_idx));
369*4882a593Smuzhiyun 		print_bpf_insn(&cbs, cur, true);
370*4882a593Smuzhiyun 		if (cur != insn_end)
371*4882a593Smuzhiyun 			printf(" | ");
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun }
374