xref: /aosp_15_r20/external/bpftool/src/btf_dumper.c (revision 858ea5e570667251cdc31d3fe7b846b591105938)
1*858ea5e5SAndroid Build Coastguard Worker // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*858ea5e5SAndroid Build Coastguard Worker /* Copyright (c) 2018 Facebook */
3*858ea5e5SAndroid Build Coastguard Worker 
4*858ea5e5SAndroid Build Coastguard Worker #include <ctype.h>
5*858ea5e5SAndroid Build Coastguard Worker #include <stdio.h> /* for (FILE *) used by json_writer */
6*858ea5e5SAndroid Build Coastguard Worker #include <string.h>
7*858ea5e5SAndroid Build Coastguard Worker #include <unistd.h>
8*858ea5e5SAndroid Build Coastguard Worker #include <asm/byteorder.h>
9*858ea5e5SAndroid Build Coastguard Worker #include <linux/bitops.h>
10*858ea5e5SAndroid Build Coastguard Worker #include <linux/btf.h>
11*858ea5e5SAndroid Build Coastguard Worker #include <linux/err.h>
12*858ea5e5SAndroid Build Coastguard Worker #include <bpf/btf.h>
13*858ea5e5SAndroid Build Coastguard Worker #include <bpf/bpf.h>
14*858ea5e5SAndroid Build Coastguard Worker 
15*858ea5e5SAndroid Build Coastguard Worker #include "json_writer.h"
16*858ea5e5SAndroid Build Coastguard Worker #include "main.h"
17*858ea5e5SAndroid Build Coastguard Worker 
18*858ea5e5SAndroid Build Coastguard Worker #define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
19*858ea5e5SAndroid Build Coastguard Worker #define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
20*858ea5e5SAndroid Build Coastguard Worker #define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
21*858ea5e5SAndroid Build Coastguard Worker #define BITS_ROUNDUP_BYTES(bits) \
22*858ea5e5SAndroid Build Coastguard Worker 	(BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
23*858ea5e5SAndroid Build Coastguard Worker 
24*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
25*858ea5e5SAndroid Build Coastguard Worker 			      __u8 bit_offset, const void *data);
26*858ea5e5SAndroid Build Coastguard Worker 
27*858ea5e5SAndroid Build Coastguard Worker static int btf_dump_func(const struct btf *btf, char *func_sig,
28*858ea5e5SAndroid Build Coastguard Worker 			 const struct btf_type *func_proto,
29*858ea5e5SAndroid Build Coastguard Worker 			 const struct btf_type *func, int pos, int size);
30*858ea5e5SAndroid Build Coastguard Worker 
dump_prog_id_as_func_ptr(const struct btf_dumper * d,const struct btf_type * func_proto,__u32 prog_id)31*858ea5e5SAndroid Build Coastguard Worker static int dump_prog_id_as_func_ptr(const struct btf_dumper *d,
32*858ea5e5SAndroid Build Coastguard Worker 				    const struct btf_type *func_proto,
33*858ea5e5SAndroid Build Coastguard Worker 				    __u32 prog_id)
34*858ea5e5SAndroid Build Coastguard Worker {
35*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *func_type;
36*858ea5e5SAndroid Build Coastguard Worker 	int prog_fd = -1, func_sig_len;
37*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_prog_info info = {};
38*858ea5e5SAndroid Build Coastguard Worker 	__u32 info_len = sizeof(info);
39*858ea5e5SAndroid Build Coastguard Worker 	const char *prog_name = NULL;
40*858ea5e5SAndroid Build Coastguard Worker 	struct btf *prog_btf = NULL;
41*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_func_info finfo;
42*858ea5e5SAndroid Build Coastguard Worker 	__u32 finfo_rec_size;
43*858ea5e5SAndroid Build Coastguard Worker 	char prog_str[1024];
44*858ea5e5SAndroid Build Coastguard Worker 	int err;
45*858ea5e5SAndroid Build Coastguard Worker 
46*858ea5e5SAndroid Build Coastguard Worker 	/* Get the ptr's func_proto */
47*858ea5e5SAndroid Build Coastguard Worker 	func_sig_len = btf_dump_func(d->btf, prog_str, func_proto, NULL, 0,
48*858ea5e5SAndroid Build Coastguard Worker 				     sizeof(prog_str));
49*858ea5e5SAndroid Build Coastguard Worker 	if (func_sig_len == -1)
50*858ea5e5SAndroid Build Coastguard Worker 		return -1;
51*858ea5e5SAndroid Build Coastguard Worker 
52*858ea5e5SAndroid Build Coastguard Worker 	if (!prog_id)
53*858ea5e5SAndroid Build Coastguard Worker 		goto print;
54*858ea5e5SAndroid Build Coastguard Worker 
55*858ea5e5SAndroid Build Coastguard Worker 	/* Get the bpf_prog's name.  Obtain from func_info. */
56*858ea5e5SAndroid Build Coastguard Worker 	prog_fd = bpf_prog_get_fd_by_id(prog_id);
57*858ea5e5SAndroid Build Coastguard Worker 	if (prog_fd < 0)
58*858ea5e5SAndroid Build Coastguard Worker 		goto print;
59*858ea5e5SAndroid Build Coastguard Worker 
60*858ea5e5SAndroid Build Coastguard Worker 	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);
61*858ea5e5SAndroid Build Coastguard Worker 	if (err)
62*858ea5e5SAndroid Build Coastguard Worker 		goto print;
63*858ea5e5SAndroid Build Coastguard Worker 
64*858ea5e5SAndroid Build Coastguard Worker 	if (!info.btf_id || !info.nr_func_info)
65*858ea5e5SAndroid Build Coastguard Worker 		goto print;
66*858ea5e5SAndroid Build Coastguard Worker 
67*858ea5e5SAndroid Build Coastguard Worker 	finfo_rec_size = info.func_info_rec_size;
68*858ea5e5SAndroid Build Coastguard Worker 	memset(&info, 0, sizeof(info));
69*858ea5e5SAndroid Build Coastguard Worker 	info.nr_func_info = 1;
70*858ea5e5SAndroid Build Coastguard Worker 	info.func_info_rec_size = finfo_rec_size;
71*858ea5e5SAndroid Build Coastguard Worker 	info.func_info = ptr_to_u64(&finfo);
72*858ea5e5SAndroid Build Coastguard Worker 
73*858ea5e5SAndroid Build Coastguard Worker 	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);
74*858ea5e5SAndroid Build Coastguard Worker 	if (err)
75*858ea5e5SAndroid Build Coastguard Worker 		goto print;
76*858ea5e5SAndroid Build Coastguard Worker 
77*858ea5e5SAndroid Build Coastguard Worker 	prog_btf = btf__load_from_kernel_by_id(info.btf_id);
78*858ea5e5SAndroid Build Coastguard Worker 	if (!prog_btf)
79*858ea5e5SAndroid Build Coastguard Worker 		goto print;
80*858ea5e5SAndroid Build Coastguard Worker 	func_type = btf__type_by_id(prog_btf, finfo.type_id);
81*858ea5e5SAndroid Build Coastguard Worker 	if (!func_type || !btf_is_func(func_type))
82*858ea5e5SAndroid Build Coastguard Worker 		goto print;
83*858ea5e5SAndroid Build Coastguard Worker 
84*858ea5e5SAndroid Build Coastguard Worker 	prog_name = btf__name_by_offset(prog_btf, func_type->name_off);
85*858ea5e5SAndroid Build Coastguard Worker 
86*858ea5e5SAndroid Build Coastguard Worker print:
87*858ea5e5SAndroid Build Coastguard Worker 	if (!prog_id)
88*858ea5e5SAndroid Build Coastguard Worker 		snprintf(&prog_str[func_sig_len],
89*858ea5e5SAndroid Build Coastguard Worker 			 sizeof(prog_str) - func_sig_len, " 0");
90*858ea5e5SAndroid Build Coastguard Worker 	else if (prog_name)
91*858ea5e5SAndroid Build Coastguard Worker 		snprintf(&prog_str[func_sig_len],
92*858ea5e5SAndroid Build Coastguard Worker 			 sizeof(prog_str) - func_sig_len,
93*858ea5e5SAndroid Build Coastguard Worker 			 " %s/prog_id:%u", prog_name, prog_id);
94*858ea5e5SAndroid Build Coastguard Worker 	else
95*858ea5e5SAndroid Build Coastguard Worker 		snprintf(&prog_str[func_sig_len],
96*858ea5e5SAndroid Build Coastguard Worker 			 sizeof(prog_str) - func_sig_len,
97*858ea5e5SAndroid Build Coastguard Worker 			 " <unknown_prog_name>/prog_id:%u", prog_id);
98*858ea5e5SAndroid Build Coastguard Worker 
99*858ea5e5SAndroid Build Coastguard Worker 	prog_str[sizeof(prog_str) - 1] = '\0';
100*858ea5e5SAndroid Build Coastguard Worker 	jsonw_string(d->jw, prog_str);
101*858ea5e5SAndroid Build Coastguard Worker 	btf__free(prog_btf);
102*858ea5e5SAndroid Build Coastguard Worker 	if (prog_fd >= 0)
103*858ea5e5SAndroid Build Coastguard Worker 		close(prog_fd);
104*858ea5e5SAndroid Build Coastguard Worker 	return 0;
105*858ea5e5SAndroid Build Coastguard Worker }
106*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_ptr(const struct btf_dumper * d,const struct btf_type * t,const void * data)107*858ea5e5SAndroid Build Coastguard Worker static void btf_dumper_ptr(const struct btf_dumper *d,
108*858ea5e5SAndroid Build Coastguard Worker 			   const struct btf_type *t,
109*858ea5e5SAndroid Build Coastguard Worker 			   const void *data)
110*858ea5e5SAndroid Build Coastguard Worker {
111*858ea5e5SAndroid Build Coastguard Worker 	unsigned long value = *(unsigned long *)data;
112*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *ptr_type;
113*858ea5e5SAndroid Build Coastguard Worker 	__s32 ptr_type_id;
114*858ea5e5SAndroid Build Coastguard Worker 
115*858ea5e5SAndroid Build Coastguard Worker 	if (!d->prog_id_as_func_ptr || value > UINT32_MAX)
116*858ea5e5SAndroid Build Coastguard Worker 		goto print_ptr_value;
117*858ea5e5SAndroid Build Coastguard Worker 
118*858ea5e5SAndroid Build Coastguard Worker 	ptr_type_id = btf__resolve_type(d->btf, t->type);
119*858ea5e5SAndroid Build Coastguard Worker 	if (ptr_type_id < 0)
120*858ea5e5SAndroid Build Coastguard Worker 		goto print_ptr_value;
121*858ea5e5SAndroid Build Coastguard Worker 	ptr_type = btf__type_by_id(d->btf, ptr_type_id);
122*858ea5e5SAndroid Build Coastguard Worker 	if (!ptr_type || !btf_is_func_proto(ptr_type))
123*858ea5e5SAndroid Build Coastguard Worker 		goto print_ptr_value;
124*858ea5e5SAndroid Build Coastguard Worker 
125*858ea5e5SAndroid Build Coastguard Worker 	if (!dump_prog_id_as_func_ptr(d, ptr_type, value))
126*858ea5e5SAndroid Build Coastguard Worker 		return;
127*858ea5e5SAndroid Build Coastguard Worker 
128*858ea5e5SAndroid Build Coastguard Worker print_ptr_value:
129*858ea5e5SAndroid Build Coastguard Worker 	if (d->is_plain_text)
130*858ea5e5SAndroid Build Coastguard Worker 		jsonw_printf(d->jw, "\"%p\"", (void *)value);
131*858ea5e5SAndroid Build Coastguard Worker 	else
132*858ea5e5SAndroid Build Coastguard Worker 		jsonw_printf(d->jw, "%lu", value);
133*858ea5e5SAndroid Build Coastguard Worker }
134*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_modifier(const struct btf_dumper * d,__u32 type_id,__u8 bit_offset,const void * data)135*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id,
136*858ea5e5SAndroid Build Coastguard Worker 			       __u8 bit_offset, const void *data)
137*858ea5e5SAndroid Build Coastguard Worker {
138*858ea5e5SAndroid Build Coastguard Worker 	int actual_type_id;
139*858ea5e5SAndroid Build Coastguard Worker 
140*858ea5e5SAndroid Build Coastguard Worker 	actual_type_id = btf__resolve_type(d->btf, type_id);
141*858ea5e5SAndroid Build Coastguard Worker 	if (actual_type_id < 0)
142*858ea5e5SAndroid Build Coastguard Worker 		return actual_type_id;
143*858ea5e5SAndroid Build Coastguard Worker 
144*858ea5e5SAndroid Build Coastguard Worker 	return btf_dumper_do_type(d, actual_type_id, bit_offset, data);
145*858ea5e5SAndroid Build Coastguard Worker }
146*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_enum(const struct btf_dumper * d,const struct btf_type * t,const void * data)147*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_enum(const struct btf_dumper *d,
148*858ea5e5SAndroid Build Coastguard Worker 			    const struct btf_type *t,
149*858ea5e5SAndroid Build Coastguard Worker 			    const void *data)
150*858ea5e5SAndroid Build Coastguard Worker {
151*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_enum *enums = btf_enum(t);
152*858ea5e5SAndroid Build Coastguard Worker 	__s64 value;
153*858ea5e5SAndroid Build Coastguard Worker 	__u16 i;
154*858ea5e5SAndroid Build Coastguard Worker 
155*858ea5e5SAndroid Build Coastguard Worker 	switch (t->size) {
156*858ea5e5SAndroid Build Coastguard Worker 	case 8:
157*858ea5e5SAndroid Build Coastguard Worker 		value = *(__s64 *)data;
158*858ea5e5SAndroid Build Coastguard Worker 		break;
159*858ea5e5SAndroid Build Coastguard Worker 	case 4:
160*858ea5e5SAndroid Build Coastguard Worker 		value = *(__s32 *)data;
161*858ea5e5SAndroid Build Coastguard Worker 		break;
162*858ea5e5SAndroid Build Coastguard Worker 	case 2:
163*858ea5e5SAndroid Build Coastguard Worker 		value = *(__s16 *)data;
164*858ea5e5SAndroid Build Coastguard Worker 		break;
165*858ea5e5SAndroid Build Coastguard Worker 	case 1:
166*858ea5e5SAndroid Build Coastguard Worker 		value = *(__s8 *)data;
167*858ea5e5SAndroid Build Coastguard Worker 		break;
168*858ea5e5SAndroid Build Coastguard Worker 	default:
169*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
170*858ea5e5SAndroid Build Coastguard Worker 	}
171*858ea5e5SAndroid Build Coastguard Worker 
172*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < btf_vlen(t); i++) {
173*858ea5e5SAndroid Build Coastguard Worker 		if (value == enums[i].val) {
174*858ea5e5SAndroid Build Coastguard Worker 			jsonw_string(d->jw,
175*858ea5e5SAndroid Build Coastguard Worker 				     btf__name_by_offset(d->btf,
176*858ea5e5SAndroid Build Coastguard Worker 							 enums[i].name_off));
177*858ea5e5SAndroid Build Coastguard Worker 			return 0;
178*858ea5e5SAndroid Build Coastguard Worker 		}
179*858ea5e5SAndroid Build Coastguard Worker 	}
180*858ea5e5SAndroid Build Coastguard Worker 
181*858ea5e5SAndroid Build Coastguard Worker 	jsonw_int(d->jw, value);
182*858ea5e5SAndroid Build Coastguard Worker 	return 0;
183*858ea5e5SAndroid Build Coastguard Worker }
184*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_enum64(const struct btf_dumper * d,const struct btf_type * t,const void * data)185*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_enum64(const struct btf_dumper *d,
186*858ea5e5SAndroid Build Coastguard Worker 			     const struct btf_type *t,
187*858ea5e5SAndroid Build Coastguard Worker 			     const void *data)
188*858ea5e5SAndroid Build Coastguard Worker {
189*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_enum64 *enums = btf_enum64(t);
190*858ea5e5SAndroid Build Coastguard Worker 	__u32 val_lo32, val_hi32;
191*858ea5e5SAndroid Build Coastguard Worker 	__u64 value;
192*858ea5e5SAndroid Build Coastguard Worker 	__u16 i;
193*858ea5e5SAndroid Build Coastguard Worker 
194*858ea5e5SAndroid Build Coastguard Worker 	value = *(__u64 *)data;
195*858ea5e5SAndroid Build Coastguard Worker 	val_lo32 = (__u32)value;
196*858ea5e5SAndroid Build Coastguard Worker 	val_hi32 = value >> 32;
197*858ea5e5SAndroid Build Coastguard Worker 
198*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < btf_vlen(t); i++) {
199*858ea5e5SAndroid Build Coastguard Worker 		if (val_lo32 == enums[i].val_lo32 && val_hi32 == enums[i].val_hi32) {
200*858ea5e5SAndroid Build Coastguard Worker 			jsonw_string(d->jw,
201*858ea5e5SAndroid Build Coastguard Worker 				     btf__name_by_offset(d->btf,
202*858ea5e5SAndroid Build Coastguard Worker 							 enums[i].name_off));
203*858ea5e5SAndroid Build Coastguard Worker 			return 0;
204*858ea5e5SAndroid Build Coastguard Worker 		}
205*858ea5e5SAndroid Build Coastguard Worker 	}
206*858ea5e5SAndroid Build Coastguard Worker 
207*858ea5e5SAndroid Build Coastguard Worker 	jsonw_int(d->jw, value);
208*858ea5e5SAndroid Build Coastguard Worker 	return 0;
209*858ea5e5SAndroid Build Coastguard Worker }
210*858ea5e5SAndroid Build Coastguard Worker 
is_str_array(const struct btf * btf,const struct btf_array * arr,const char * s)211*858ea5e5SAndroid Build Coastguard Worker static bool is_str_array(const struct btf *btf, const struct btf_array *arr,
212*858ea5e5SAndroid Build Coastguard Worker 			 const char *s)
213*858ea5e5SAndroid Build Coastguard Worker {
214*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *elem_type;
215*858ea5e5SAndroid Build Coastguard Worker 	const char *end_s;
216*858ea5e5SAndroid Build Coastguard Worker 
217*858ea5e5SAndroid Build Coastguard Worker 	if (!arr->nelems)
218*858ea5e5SAndroid Build Coastguard Worker 		return false;
219*858ea5e5SAndroid Build Coastguard Worker 
220*858ea5e5SAndroid Build Coastguard Worker 	elem_type = btf__type_by_id(btf, arr->type);
221*858ea5e5SAndroid Build Coastguard Worker 	/* Not skipping typedef.  typedef to char does not count as
222*858ea5e5SAndroid Build Coastguard Worker 	 * a string now.
223*858ea5e5SAndroid Build Coastguard Worker 	 */
224*858ea5e5SAndroid Build Coastguard Worker 	while (elem_type && btf_is_mod(elem_type))
225*858ea5e5SAndroid Build Coastguard Worker 		elem_type = btf__type_by_id(btf, elem_type->type);
226*858ea5e5SAndroid Build Coastguard Worker 
227*858ea5e5SAndroid Build Coastguard Worker 	if (!elem_type || !btf_is_int(elem_type) || elem_type->size != 1)
228*858ea5e5SAndroid Build Coastguard Worker 		return false;
229*858ea5e5SAndroid Build Coastguard Worker 
230*858ea5e5SAndroid Build Coastguard Worker 	if (btf_int_encoding(elem_type) != BTF_INT_CHAR &&
231*858ea5e5SAndroid Build Coastguard Worker 	    strcmp("char", btf__name_by_offset(btf, elem_type->name_off)))
232*858ea5e5SAndroid Build Coastguard Worker 		return false;
233*858ea5e5SAndroid Build Coastguard Worker 
234*858ea5e5SAndroid Build Coastguard Worker 	end_s = s + arr->nelems;
235*858ea5e5SAndroid Build Coastguard Worker 	while (s < end_s) {
236*858ea5e5SAndroid Build Coastguard Worker 		if (!*s)
237*858ea5e5SAndroid Build Coastguard Worker 			return true;
238*858ea5e5SAndroid Build Coastguard Worker 		if (*s <= 0x1f || *s >= 0x7f)
239*858ea5e5SAndroid Build Coastguard Worker 			return false;
240*858ea5e5SAndroid Build Coastguard Worker 		s++;
241*858ea5e5SAndroid Build Coastguard Worker 	}
242*858ea5e5SAndroid Build Coastguard Worker 
243*858ea5e5SAndroid Build Coastguard Worker 	/* '\0' is not found */
244*858ea5e5SAndroid Build Coastguard Worker 	return false;
245*858ea5e5SAndroid Build Coastguard Worker }
246*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_array(const struct btf_dumper * d,__u32 type_id,const void * data)247*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id,
248*858ea5e5SAndroid Build Coastguard Worker 			    const void *data)
249*858ea5e5SAndroid Build Coastguard Worker {
250*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *t = btf__type_by_id(d->btf, type_id);
251*858ea5e5SAndroid Build Coastguard Worker 	struct btf_array *arr = (struct btf_array *)(t + 1);
252*858ea5e5SAndroid Build Coastguard Worker 	long long elem_size;
253*858ea5e5SAndroid Build Coastguard Worker 	int ret = 0;
254*858ea5e5SAndroid Build Coastguard Worker 	__u32 i;
255*858ea5e5SAndroid Build Coastguard Worker 
256*858ea5e5SAndroid Build Coastguard Worker 	if (is_str_array(d->btf, arr, data)) {
257*858ea5e5SAndroid Build Coastguard Worker 		jsonw_string(d->jw, data);
258*858ea5e5SAndroid Build Coastguard Worker 		return 0;
259*858ea5e5SAndroid Build Coastguard Worker 	}
260*858ea5e5SAndroid Build Coastguard Worker 
261*858ea5e5SAndroid Build Coastguard Worker 	elem_size = btf__resolve_size(d->btf, arr->type);
262*858ea5e5SAndroid Build Coastguard Worker 	if (elem_size < 0)
263*858ea5e5SAndroid Build Coastguard Worker 		return elem_size;
264*858ea5e5SAndroid Build Coastguard Worker 
265*858ea5e5SAndroid Build Coastguard Worker 	jsonw_start_array(d->jw);
266*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < arr->nelems; i++) {
267*858ea5e5SAndroid Build Coastguard Worker 		ret = btf_dumper_do_type(d, arr->type, 0,
268*858ea5e5SAndroid Build Coastguard Worker 					 data + i * elem_size);
269*858ea5e5SAndroid Build Coastguard Worker 		if (ret)
270*858ea5e5SAndroid Build Coastguard Worker 			break;
271*858ea5e5SAndroid Build Coastguard Worker 	}
272*858ea5e5SAndroid Build Coastguard Worker 
273*858ea5e5SAndroid Build Coastguard Worker 	jsonw_end_array(d->jw);
274*858ea5e5SAndroid Build Coastguard Worker 	return ret;
275*858ea5e5SAndroid Build Coastguard Worker }
276*858ea5e5SAndroid Build Coastguard Worker 
btf_int128_print(json_writer_t * jw,const void * data,bool is_plain_text)277*858ea5e5SAndroid Build Coastguard Worker static void btf_int128_print(json_writer_t *jw, const void *data,
278*858ea5e5SAndroid Build Coastguard Worker 			     bool is_plain_text)
279*858ea5e5SAndroid Build Coastguard Worker {
280*858ea5e5SAndroid Build Coastguard Worker 	/* data points to a __int128 number.
281*858ea5e5SAndroid Build Coastguard Worker 	 * Suppose
282*858ea5e5SAndroid Build Coastguard Worker 	 *     int128_num = *(__int128 *)data;
283*858ea5e5SAndroid Build Coastguard Worker 	 * The below formulas shows what upper_num and lower_num represents:
284*858ea5e5SAndroid Build Coastguard Worker 	 *     upper_num = int128_num >> 64;
285*858ea5e5SAndroid Build Coastguard Worker 	 *     lower_num = int128_num & 0xffffffffFFFFFFFFULL;
286*858ea5e5SAndroid Build Coastguard Worker 	 */
287*858ea5e5SAndroid Build Coastguard Worker 	__u64 upper_num, lower_num;
288*858ea5e5SAndroid Build Coastguard Worker 
289*858ea5e5SAndroid Build Coastguard Worker #ifdef __BIG_ENDIAN_BITFIELD
290*858ea5e5SAndroid Build Coastguard Worker 	upper_num = *(__u64 *)data;
291*858ea5e5SAndroid Build Coastguard Worker 	lower_num = *(__u64 *)(data + 8);
292*858ea5e5SAndroid Build Coastguard Worker #else
293*858ea5e5SAndroid Build Coastguard Worker 	upper_num = *(__u64 *)(data + 8);
294*858ea5e5SAndroid Build Coastguard Worker 	lower_num = *(__u64 *)data;
295*858ea5e5SAndroid Build Coastguard Worker #endif
296*858ea5e5SAndroid Build Coastguard Worker 
297*858ea5e5SAndroid Build Coastguard Worker 	if (is_plain_text) {
298*858ea5e5SAndroid Build Coastguard Worker 		if (upper_num == 0)
299*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "0x%llx", lower_num);
300*858ea5e5SAndroid Build Coastguard Worker 		else
301*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "0x%llx%016llx", upper_num, lower_num);
302*858ea5e5SAndroid Build Coastguard Worker 	} else {
303*858ea5e5SAndroid Build Coastguard Worker 		if (upper_num == 0)
304*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "\"0x%llx\"", lower_num);
305*858ea5e5SAndroid Build Coastguard Worker 		else
306*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "\"0x%llx%016llx\"", upper_num, lower_num);
307*858ea5e5SAndroid Build Coastguard Worker 	}
308*858ea5e5SAndroid Build Coastguard Worker }
309*858ea5e5SAndroid Build Coastguard Worker 
btf_int128_shift(__u64 * print_num,__u16 left_shift_bits,__u16 right_shift_bits)310*858ea5e5SAndroid Build Coastguard Worker static void btf_int128_shift(__u64 *print_num, __u16 left_shift_bits,
311*858ea5e5SAndroid Build Coastguard Worker 			     __u16 right_shift_bits)
312*858ea5e5SAndroid Build Coastguard Worker {
313*858ea5e5SAndroid Build Coastguard Worker 	__u64 upper_num, lower_num;
314*858ea5e5SAndroid Build Coastguard Worker 
315*858ea5e5SAndroid Build Coastguard Worker #ifdef __BIG_ENDIAN_BITFIELD
316*858ea5e5SAndroid Build Coastguard Worker 	upper_num = print_num[0];
317*858ea5e5SAndroid Build Coastguard Worker 	lower_num = print_num[1];
318*858ea5e5SAndroid Build Coastguard Worker #else
319*858ea5e5SAndroid Build Coastguard Worker 	upper_num = print_num[1];
320*858ea5e5SAndroid Build Coastguard Worker 	lower_num = print_num[0];
321*858ea5e5SAndroid Build Coastguard Worker #endif
322*858ea5e5SAndroid Build Coastguard Worker 
323*858ea5e5SAndroid Build Coastguard Worker 	/* shake out un-needed bits by shift/or operations */
324*858ea5e5SAndroid Build Coastguard Worker 	if (left_shift_bits >= 64) {
325*858ea5e5SAndroid Build Coastguard Worker 		upper_num = lower_num << (left_shift_bits - 64);
326*858ea5e5SAndroid Build Coastguard Worker 		lower_num = 0;
327*858ea5e5SAndroid Build Coastguard Worker 	} else {
328*858ea5e5SAndroid Build Coastguard Worker 		upper_num = (upper_num << left_shift_bits) |
329*858ea5e5SAndroid Build Coastguard Worker 			    (lower_num >> (64 - left_shift_bits));
330*858ea5e5SAndroid Build Coastguard Worker 		lower_num = lower_num << left_shift_bits;
331*858ea5e5SAndroid Build Coastguard Worker 	}
332*858ea5e5SAndroid Build Coastguard Worker 
333*858ea5e5SAndroid Build Coastguard Worker 	if (right_shift_bits >= 64) {
334*858ea5e5SAndroid Build Coastguard Worker 		lower_num = upper_num >> (right_shift_bits - 64);
335*858ea5e5SAndroid Build Coastguard Worker 		upper_num = 0;
336*858ea5e5SAndroid Build Coastguard Worker 	} else {
337*858ea5e5SAndroid Build Coastguard Worker 		lower_num = (lower_num >> right_shift_bits) |
338*858ea5e5SAndroid Build Coastguard Worker 			    (upper_num << (64 - right_shift_bits));
339*858ea5e5SAndroid Build Coastguard Worker 		upper_num = upper_num >> right_shift_bits;
340*858ea5e5SAndroid Build Coastguard Worker 	}
341*858ea5e5SAndroid Build Coastguard Worker 
342*858ea5e5SAndroid Build Coastguard Worker #ifdef __BIG_ENDIAN_BITFIELD
343*858ea5e5SAndroid Build Coastguard Worker 	print_num[0] = upper_num;
344*858ea5e5SAndroid Build Coastguard Worker 	print_num[1] = lower_num;
345*858ea5e5SAndroid Build Coastguard Worker #else
346*858ea5e5SAndroid Build Coastguard Worker 	print_num[0] = lower_num;
347*858ea5e5SAndroid Build Coastguard Worker 	print_num[1] = upper_num;
348*858ea5e5SAndroid Build Coastguard Worker #endif
349*858ea5e5SAndroid Build Coastguard Worker }
350*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_bitfield(__u32 nr_bits,__u8 bit_offset,const void * data,json_writer_t * jw,bool is_plain_text)351*858ea5e5SAndroid Build Coastguard Worker static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset,
352*858ea5e5SAndroid Build Coastguard Worker 				const void *data, json_writer_t *jw,
353*858ea5e5SAndroid Build Coastguard Worker 				bool is_plain_text)
354*858ea5e5SAndroid Build Coastguard Worker {
355*858ea5e5SAndroid Build Coastguard Worker 	int left_shift_bits, right_shift_bits;
356*858ea5e5SAndroid Build Coastguard Worker 	__u64 print_num[2] = {};
357*858ea5e5SAndroid Build Coastguard Worker 	int bytes_to_copy;
358*858ea5e5SAndroid Build Coastguard Worker 	int bits_to_copy;
359*858ea5e5SAndroid Build Coastguard Worker 
360*858ea5e5SAndroid Build Coastguard Worker 	bits_to_copy = bit_offset + nr_bits;
361*858ea5e5SAndroid Build Coastguard Worker 	bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
362*858ea5e5SAndroid Build Coastguard Worker 
363*858ea5e5SAndroid Build Coastguard Worker 	memcpy(print_num, data, bytes_to_copy);
364*858ea5e5SAndroid Build Coastguard Worker #if defined(__BIG_ENDIAN_BITFIELD)
365*858ea5e5SAndroid Build Coastguard Worker 	left_shift_bits = bit_offset;
366*858ea5e5SAndroid Build Coastguard Worker #elif defined(__LITTLE_ENDIAN_BITFIELD)
367*858ea5e5SAndroid Build Coastguard Worker 	left_shift_bits = 128 - bits_to_copy;
368*858ea5e5SAndroid Build Coastguard Worker #else
369*858ea5e5SAndroid Build Coastguard Worker #error neither big nor little endian
370*858ea5e5SAndroid Build Coastguard Worker #endif
371*858ea5e5SAndroid Build Coastguard Worker 	right_shift_bits = 128 - nr_bits;
372*858ea5e5SAndroid Build Coastguard Worker 
373*858ea5e5SAndroid Build Coastguard Worker 	btf_int128_shift(print_num, left_shift_bits, right_shift_bits);
374*858ea5e5SAndroid Build Coastguard Worker 	btf_int128_print(jw, print_num, is_plain_text);
375*858ea5e5SAndroid Build Coastguard Worker }
376*858ea5e5SAndroid Build Coastguard Worker 
377*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_int_bits(__u32 int_type,__u8 bit_offset,const void * data,json_writer_t * jw,bool is_plain_text)378*858ea5e5SAndroid Build Coastguard Worker static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
379*858ea5e5SAndroid Build Coastguard Worker 				const void *data, json_writer_t *jw,
380*858ea5e5SAndroid Build Coastguard Worker 				bool is_plain_text)
381*858ea5e5SAndroid Build Coastguard Worker {
382*858ea5e5SAndroid Build Coastguard Worker 	int nr_bits = BTF_INT_BITS(int_type);
383*858ea5e5SAndroid Build Coastguard Worker 	int total_bits_offset;
384*858ea5e5SAndroid Build Coastguard Worker 
385*858ea5e5SAndroid Build Coastguard Worker 	/* bits_offset is at most 7.
386*858ea5e5SAndroid Build Coastguard Worker 	 * BTF_INT_OFFSET() cannot exceed 128 bits.
387*858ea5e5SAndroid Build Coastguard Worker 	 */
388*858ea5e5SAndroid Build Coastguard Worker 	total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
389*858ea5e5SAndroid Build Coastguard Worker 	data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
390*858ea5e5SAndroid Build Coastguard Worker 	bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
391*858ea5e5SAndroid Build Coastguard Worker 	btf_dumper_bitfield(nr_bits, bit_offset, data, jw,
392*858ea5e5SAndroid Build Coastguard Worker 			    is_plain_text);
393*858ea5e5SAndroid Build Coastguard Worker }
394*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_int(const struct btf_type * t,__u8 bit_offset,const void * data,json_writer_t * jw,bool is_plain_text)395*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset,
396*858ea5e5SAndroid Build Coastguard Worker 			  const void *data, json_writer_t *jw,
397*858ea5e5SAndroid Build Coastguard Worker 			  bool is_plain_text)
398*858ea5e5SAndroid Build Coastguard Worker {
399*858ea5e5SAndroid Build Coastguard Worker 	__u32 *int_type;
400*858ea5e5SAndroid Build Coastguard Worker 	__u32 nr_bits;
401*858ea5e5SAndroid Build Coastguard Worker 
402*858ea5e5SAndroid Build Coastguard Worker 	int_type = (__u32 *)(t + 1);
403*858ea5e5SAndroid Build Coastguard Worker 	nr_bits = BTF_INT_BITS(*int_type);
404*858ea5e5SAndroid Build Coastguard Worker 	/* if this is bit field */
405*858ea5e5SAndroid Build Coastguard Worker 	if (bit_offset || BTF_INT_OFFSET(*int_type) ||
406*858ea5e5SAndroid Build Coastguard Worker 	    BITS_PER_BYTE_MASKED(nr_bits)) {
407*858ea5e5SAndroid Build Coastguard Worker 		btf_dumper_int_bits(*int_type, bit_offset, data, jw,
408*858ea5e5SAndroid Build Coastguard Worker 				    is_plain_text);
409*858ea5e5SAndroid Build Coastguard Worker 		return 0;
410*858ea5e5SAndroid Build Coastguard Worker 	}
411*858ea5e5SAndroid Build Coastguard Worker 
412*858ea5e5SAndroid Build Coastguard Worker 	if (nr_bits == 128) {
413*858ea5e5SAndroid Build Coastguard Worker 		btf_int128_print(jw, data, is_plain_text);
414*858ea5e5SAndroid Build Coastguard Worker 		return 0;
415*858ea5e5SAndroid Build Coastguard Worker 	}
416*858ea5e5SAndroid Build Coastguard Worker 
417*858ea5e5SAndroid Build Coastguard Worker 	switch (BTF_INT_ENCODING(*int_type)) {
418*858ea5e5SAndroid Build Coastguard Worker 	case 0:
419*858ea5e5SAndroid Build Coastguard Worker 		if (BTF_INT_BITS(*int_type) == 64)
420*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "%llu", *(__u64 *)data);
421*858ea5e5SAndroid Build Coastguard Worker 		else if (BTF_INT_BITS(*int_type) == 32)
422*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "%u", *(__u32 *)data);
423*858ea5e5SAndroid Build Coastguard Worker 		else if (BTF_INT_BITS(*int_type) == 16)
424*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "%hu", *(__u16 *)data);
425*858ea5e5SAndroid Build Coastguard Worker 		else if (BTF_INT_BITS(*int_type) == 8)
426*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "%hhu", *(__u8 *)data);
427*858ea5e5SAndroid Build Coastguard Worker 		else
428*858ea5e5SAndroid Build Coastguard Worker 			btf_dumper_int_bits(*int_type, bit_offset, data, jw,
429*858ea5e5SAndroid Build Coastguard Worker 					    is_plain_text);
430*858ea5e5SAndroid Build Coastguard Worker 		break;
431*858ea5e5SAndroid Build Coastguard Worker 	case BTF_INT_SIGNED:
432*858ea5e5SAndroid Build Coastguard Worker 		if (BTF_INT_BITS(*int_type) == 64)
433*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "%lld", *(long long *)data);
434*858ea5e5SAndroid Build Coastguard Worker 		else if (BTF_INT_BITS(*int_type) == 32)
435*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "%d", *(int *)data);
436*858ea5e5SAndroid Build Coastguard Worker 		else if (BTF_INT_BITS(*int_type) == 16)
437*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "%hd", *(short *)data);
438*858ea5e5SAndroid Build Coastguard Worker 		else if (BTF_INT_BITS(*int_type) == 8)
439*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "%hhd", *(char *)data);
440*858ea5e5SAndroid Build Coastguard Worker 		else
441*858ea5e5SAndroid Build Coastguard Worker 			btf_dumper_int_bits(*int_type, bit_offset, data, jw,
442*858ea5e5SAndroid Build Coastguard Worker 					    is_plain_text);
443*858ea5e5SAndroid Build Coastguard Worker 		break;
444*858ea5e5SAndroid Build Coastguard Worker 	case BTF_INT_CHAR:
445*858ea5e5SAndroid Build Coastguard Worker 		if (isprint(*(char *)data))
446*858ea5e5SAndroid Build Coastguard Worker 			jsonw_printf(jw, "\"%c\"", *(char *)data);
447*858ea5e5SAndroid Build Coastguard Worker 		else
448*858ea5e5SAndroid Build Coastguard Worker 			if (is_plain_text)
449*858ea5e5SAndroid Build Coastguard Worker 				jsonw_printf(jw, "0x%hhx", *(char *)data);
450*858ea5e5SAndroid Build Coastguard Worker 			else
451*858ea5e5SAndroid Build Coastguard Worker 				jsonw_printf(jw, "\"\\u00%02hhx\"",
452*858ea5e5SAndroid Build Coastguard Worker 					     *(char *)data);
453*858ea5e5SAndroid Build Coastguard Worker 		break;
454*858ea5e5SAndroid Build Coastguard Worker 	case BTF_INT_BOOL:
455*858ea5e5SAndroid Build Coastguard Worker 		jsonw_bool(jw, *(bool *)data);
456*858ea5e5SAndroid Build Coastguard Worker 		break;
457*858ea5e5SAndroid Build Coastguard Worker 	default:
458*858ea5e5SAndroid Build Coastguard Worker 		/* shouldn't happen */
459*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
460*858ea5e5SAndroid Build Coastguard Worker 	}
461*858ea5e5SAndroid Build Coastguard Worker 
462*858ea5e5SAndroid Build Coastguard Worker 	return 0;
463*858ea5e5SAndroid Build Coastguard Worker }
464*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_struct(const struct btf_dumper * d,__u32 type_id,const void * data)465*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id,
466*858ea5e5SAndroid Build Coastguard Worker 			     const void *data)
467*858ea5e5SAndroid Build Coastguard Worker {
468*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *t;
469*858ea5e5SAndroid Build Coastguard Worker 	struct btf_member *m;
470*858ea5e5SAndroid Build Coastguard Worker 	const void *data_off;
471*858ea5e5SAndroid Build Coastguard Worker 	int kind_flag;
472*858ea5e5SAndroid Build Coastguard Worker 	int ret = 0;
473*858ea5e5SAndroid Build Coastguard Worker 	int i, vlen;
474*858ea5e5SAndroid Build Coastguard Worker 
475*858ea5e5SAndroid Build Coastguard Worker 	t = btf__type_by_id(d->btf, type_id);
476*858ea5e5SAndroid Build Coastguard Worker 	if (!t)
477*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
478*858ea5e5SAndroid Build Coastguard Worker 
479*858ea5e5SAndroid Build Coastguard Worker 	kind_flag = BTF_INFO_KFLAG(t->info);
480*858ea5e5SAndroid Build Coastguard Worker 	vlen = BTF_INFO_VLEN(t->info);
481*858ea5e5SAndroid Build Coastguard Worker 	jsonw_start_object(d->jw);
482*858ea5e5SAndroid Build Coastguard Worker 	m = (struct btf_member *)(t + 1);
483*858ea5e5SAndroid Build Coastguard Worker 
484*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < vlen; i++) {
485*858ea5e5SAndroid Build Coastguard Worker 		__u32 bit_offset = m[i].offset;
486*858ea5e5SAndroid Build Coastguard Worker 		__u32 bitfield_size = 0;
487*858ea5e5SAndroid Build Coastguard Worker 
488*858ea5e5SAndroid Build Coastguard Worker 		if (kind_flag) {
489*858ea5e5SAndroid Build Coastguard Worker 			bitfield_size = BTF_MEMBER_BITFIELD_SIZE(bit_offset);
490*858ea5e5SAndroid Build Coastguard Worker 			bit_offset = BTF_MEMBER_BIT_OFFSET(bit_offset);
491*858ea5e5SAndroid Build Coastguard Worker 		}
492*858ea5e5SAndroid Build Coastguard Worker 
493*858ea5e5SAndroid Build Coastguard Worker 		jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off));
494*858ea5e5SAndroid Build Coastguard Worker 		data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset);
495*858ea5e5SAndroid Build Coastguard Worker 		if (bitfield_size) {
496*858ea5e5SAndroid Build Coastguard Worker 			btf_dumper_bitfield(bitfield_size,
497*858ea5e5SAndroid Build Coastguard Worker 					    BITS_PER_BYTE_MASKED(bit_offset),
498*858ea5e5SAndroid Build Coastguard Worker 					    data_off, d->jw, d->is_plain_text);
499*858ea5e5SAndroid Build Coastguard Worker 		} else {
500*858ea5e5SAndroid Build Coastguard Worker 			ret = btf_dumper_do_type(d, m[i].type,
501*858ea5e5SAndroid Build Coastguard Worker 						 BITS_PER_BYTE_MASKED(bit_offset),
502*858ea5e5SAndroid Build Coastguard Worker 						 data_off);
503*858ea5e5SAndroid Build Coastguard Worker 			if (ret)
504*858ea5e5SAndroid Build Coastguard Worker 				break;
505*858ea5e5SAndroid Build Coastguard Worker 		}
506*858ea5e5SAndroid Build Coastguard Worker 	}
507*858ea5e5SAndroid Build Coastguard Worker 
508*858ea5e5SAndroid Build Coastguard Worker 	jsonw_end_object(d->jw);
509*858ea5e5SAndroid Build Coastguard Worker 
510*858ea5e5SAndroid Build Coastguard Worker 	return ret;
511*858ea5e5SAndroid Build Coastguard Worker }
512*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_var(const struct btf_dumper * d,__u32 type_id,__u8 bit_offset,const void * data)513*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_var(const struct btf_dumper *d, __u32 type_id,
514*858ea5e5SAndroid Build Coastguard Worker 			  __u8 bit_offset, const void *data)
515*858ea5e5SAndroid Build Coastguard Worker {
516*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *t = btf__type_by_id(d->btf, type_id);
517*858ea5e5SAndroid Build Coastguard Worker 	int ret;
518*858ea5e5SAndroid Build Coastguard Worker 
519*858ea5e5SAndroid Build Coastguard Worker 	jsonw_start_object(d->jw);
520*858ea5e5SAndroid Build Coastguard Worker 	jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off));
521*858ea5e5SAndroid Build Coastguard Worker 	ret = btf_dumper_do_type(d, t->type, bit_offset, data);
522*858ea5e5SAndroid Build Coastguard Worker 	jsonw_end_object(d->jw);
523*858ea5e5SAndroid Build Coastguard Worker 
524*858ea5e5SAndroid Build Coastguard Worker 	return ret;
525*858ea5e5SAndroid Build Coastguard Worker }
526*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_datasec(const struct btf_dumper * d,__u32 type_id,const void * data)527*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_datasec(const struct btf_dumper *d, __u32 type_id,
528*858ea5e5SAndroid Build Coastguard Worker 			      const void *data)
529*858ea5e5SAndroid Build Coastguard Worker {
530*858ea5e5SAndroid Build Coastguard Worker 	struct btf_var_secinfo *vsi;
531*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *t;
532*858ea5e5SAndroid Build Coastguard Worker 	int ret = 0, i, vlen;
533*858ea5e5SAndroid Build Coastguard Worker 
534*858ea5e5SAndroid Build Coastguard Worker 	t = btf__type_by_id(d->btf, type_id);
535*858ea5e5SAndroid Build Coastguard Worker 	if (!t)
536*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
537*858ea5e5SAndroid Build Coastguard Worker 
538*858ea5e5SAndroid Build Coastguard Worker 	vlen = BTF_INFO_VLEN(t->info);
539*858ea5e5SAndroid Build Coastguard Worker 	vsi = (struct btf_var_secinfo *)(t + 1);
540*858ea5e5SAndroid Build Coastguard Worker 
541*858ea5e5SAndroid Build Coastguard Worker 	jsonw_start_object(d->jw);
542*858ea5e5SAndroid Build Coastguard Worker 	jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off));
543*858ea5e5SAndroid Build Coastguard Worker 	jsonw_start_array(d->jw);
544*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < vlen; i++) {
545*858ea5e5SAndroid Build Coastguard Worker 		ret = btf_dumper_do_type(d, vsi[i].type, 0, data + vsi[i].offset);
546*858ea5e5SAndroid Build Coastguard Worker 		if (ret)
547*858ea5e5SAndroid Build Coastguard Worker 			break;
548*858ea5e5SAndroid Build Coastguard Worker 	}
549*858ea5e5SAndroid Build Coastguard Worker 	jsonw_end_array(d->jw);
550*858ea5e5SAndroid Build Coastguard Worker 	jsonw_end_object(d->jw);
551*858ea5e5SAndroid Build Coastguard Worker 
552*858ea5e5SAndroid Build Coastguard Worker 	return ret;
553*858ea5e5SAndroid Build Coastguard Worker }
554*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_do_type(const struct btf_dumper * d,__u32 type_id,__u8 bit_offset,const void * data)555*858ea5e5SAndroid Build Coastguard Worker static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
556*858ea5e5SAndroid Build Coastguard Worker 			      __u8 bit_offset, const void *data)
557*858ea5e5SAndroid Build Coastguard Worker {
558*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *t = btf__type_by_id(d->btf, type_id);
559*858ea5e5SAndroid Build Coastguard Worker 
560*858ea5e5SAndroid Build Coastguard Worker 	switch (BTF_INFO_KIND(t->info)) {
561*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_INT:
562*858ea5e5SAndroid Build Coastguard Worker 		return btf_dumper_int(t, bit_offset, data, d->jw,
563*858ea5e5SAndroid Build Coastguard Worker 				     d->is_plain_text);
564*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_STRUCT:
565*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_UNION:
566*858ea5e5SAndroid Build Coastguard Worker 		return btf_dumper_struct(d, type_id, data);
567*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_ARRAY:
568*858ea5e5SAndroid Build Coastguard Worker 		return btf_dumper_array(d, type_id, data);
569*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_ENUM:
570*858ea5e5SAndroid Build Coastguard Worker 		return btf_dumper_enum(d, t, data);
571*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_ENUM64:
572*858ea5e5SAndroid Build Coastguard Worker 		return btf_dumper_enum64(d, t, data);
573*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_PTR:
574*858ea5e5SAndroid Build Coastguard Worker 		btf_dumper_ptr(d, t, data);
575*858ea5e5SAndroid Build Coastguard Worker 		return 0;
576*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_UNKN:
577*858ea5e5SAndroid Build Coastguard Worker 		jsonw_printf(d->jw, "(unknown)");
578*858ea5e5SAndroid Build Coastguard Worker 		return 0;
579*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_FWD:
580*858ea5e5SAndroid Build Coastguard Worker 		/* map key or value can't be forward */
581*858ea5e5SAndroid Build Coastguard Worker 		jsonw_printf(d->jw, "(fwd-kind-invalid)");
582*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
583*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_TYPEDEF:
584*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_VOLATILE:
585*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_CONST:
586*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_RESTRICT:
587*858ea5e5SAndroid Build Coastguard Worker 		return btf_dumper_modifier(d, type_id, bit_offset, data);
588*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_VAR:
589*858ea5e5SAndroid Build Coastguard Worker 		return btf_dumper_var(d, type_id, bit_offset, data);
590*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_DATASEC:
591*858ea5e5SAndroid Build Coastguard Worker 		return btf_dumper_datasec(d, type_id, data);
592*858ea5e5SAndroid Build Coastguard Worker 	default:
593*858ea5e5SAndroid Build Coastguard Worker 		jsonw_printf(d->jw, "(unsupported-kind");
594*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
595*858ea5e5SAndroid Build Coastguard Worker 	}
596*858ea5e5SAndroid Build Coastguard Worker }
597*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_type(const struct btf_dumper * d,__u32 type_id,const void * data)598*858ea5e5SAndroid Build Coastguard Worker int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
599*858ea5e5SAndroid Build Coastguard Worker 		    const void *data)
600*858ea5e5SAndroid Build Coastguard Worker {
601*858ea5e5SAndroid Build Coastguard Worker 	return btf_dumper_do_type(d, type_id, 0, data);
602*858ea5e5SAndroid Build Coastguard Worker }
603*858ea5e5SAndroid Build Coastguard Worker 
604*858ea5e5SAndroid Build Coastguard Worker #define BTF_PRINT_ARG(...)						\
605*858ea5e5SAndroid Build Coastguard Worker 	do {								\
606*858ea5e5SAndroid Build Coastguard Worker 		pos += snprintf(func_sig + pos, size - pos,		\
607*858ea5e5SAndroid Build Coastguard Worker 				__VA_ARGS__);				\
608*858ea5e5SAndroid Build Coastguard Worker 		if (pos >= size)					\
609*858ea5e5SAndroid Build Coastguard Worker 			return -1;					\
610*858ea5e5SAndroid Build Coastguard Worker 	} while (0)
611*858ea5e5SAndroid Build Coastguard Worker #define BTF_PRINT_TYPE(type)					\
612*858ea5e5SAndroid Build Coastguard Worker 	do {								\
613*858ea5e5SAndroid Build Coastguard Worker 		pos = __btf_dumper_type_only(btf, type, func_sig,	\
614*858ea5e5SAndroid Build Coastguard Worker 					     pos, size);		\
615*858ea5e5SAndroid Build Coastguard Worker 		if (pos == -1)						\
616*858ea5e5SAndroid Build Coastguard Worker 			return -1;					\
617*858ea5e5SAndroid Build Coastguard Worker 	} while (0)
618*858ea5e5SAndroid Build Coastguard Worker 
__btf_dumper_type_only(const struct btf * btf,__u32 type_id,char * func_sig,int pos,int size)619*858ea5e5SAndroid Build Coastguard Worker static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
620*858ea5e5SAndroid Build Coastguard Worker 				  char *func_sig, int pos, int size)
621*858ea5e5SAndroid Build Coastguard Worker {
622*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *proto_type;
623*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_array *array;
624*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_var *var;
625*858ea5e5SAndroid Build Coastguard Worker 	const struct btf_type *t;
626*858ea5e5SAndroid Build Coastguard Worker 
627*858ea5e5SAndroid Build Coastguard Worker 	if (!type_id) {
628*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("void ");
629*858ea5e5SAndroid Build Coastguard Worker 		return pos;
630*858ea5e5SAndroid Build Coastguard Worker 	}
631*858ea5e5SAndroid Build Coastguard Worker 
632*858ea5e5SAndroid Build Coastguard Worker 	t = btf__type_by_id(btf, type_id);
633*858ea5e5SAndroid Build Coastguard Worker 
634*858ea5e5SAndroid Build Coastguard Worker 	switch (BTF_INFO_KIND(t->info)) {
635*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_INT:
636*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_TYPEDEF:
637*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_FLOAT:
638*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off));
639*858ea5e5SAndroid Build Coastguard Worker 		break;
640*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_STRUCT:
641*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("struct %s ",
642*858ea5e5SAndroid Build Coastguard Worker 			      btf__name_by_offset(btf, t->name_off));
643*858ea5e5SAndroid Build Coastguard Worker 		break;
644*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_UNION:
645*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("union %s ",
646*858ea5e5SAndroid Build Coastguard Worker 			      btf__name_by_offset(btf, t->name_off));
647*858ea5e5SAndroid Build Coastguard Worker 		break;
648*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_ENUM:
649*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_ENUM64:
650*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("enum %s ",
651*858ea5e5SAndroid Build Coastguard Worker 			      btf__name_by_offset(btf, t->name_off));
652*858ea5e5SAndroid Build Coastguard Worker 		break;
653*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_ARRAY:
654*858ea5e5SAndroid Build Coastguard Worker 		array = (struct btf_array *)(t + 1);
655*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_TYPE(array->type);
656*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("[%d]", array->nelems);
657*858ea5e5SAndroid Build Coastguard Worker 		break;
658*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_PTR:
659*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_TYPE(t->type);
660*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("* ");
661*858ea5e5SAndroid Build Coastguard Worker 		break;
662*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_FWD:
663*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("%s %s ",
664*858ea5e5SAndroid Build Coastguard Worker 			      BTF_INFO_KFLAG(t->info) ? "union" : "struct",
665*858ea5e5SAndroid Build Coastguard Worker 			      btf__name_by_offset(btf, t->name_off));
666*858ea5e5SAndroid Build Coastguard Worker 		break;
667*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_VOLATILE:
668*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("volatile ");
669*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_TYPE(t->type);
670*858ea5e5SAndroid Build Coastguard Worker 		break;
671*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_CONST:
672*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("const ");
673*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_TYPE(t->type);
674*858ea5e5SAndroid Build Coastguard Worker 		break;
675*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_RESTRICT:
676*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("restrict ");
677*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_TYPE(t->type);
678*858ea5e5SAndroid Build Coastguard Worker 		break;
679*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_FUNC_PROTO:
680*858ea5e5SAndroid Build Coastguard Worker 		pos = btf_dump_func(btf, func_sig, t, NULL, pos, size);
681*858ea5e5SAndroid Build Coastguard Worker 		if (pos == -1)
682*858ea5e5SAndroid Build Coastguard Worker 			return -1;
683*858ea5e5SAndroid Build Coastguard Worker 		break;
684*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_FUNC:
685*858ea5e5SAndroid Build Coastguard Worker 		proto_type = btf__type_by_id(btf, t->type);
686*858ea5e5SAndroid Build Coastguard Worker 		pos = btf_dump_func(btf, func_sig, proto_type, t, pos, size);
687*858ea5e5SAndroid Build Coastguard Worker 		if (pos == -1)
688*858ea5e5SAndroid Build Coastguard Worker 			return -1;
689*858ea5e5SAndroid Build Coastguard Worker 		break;
690*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_VAR:
691*858ea5e5SAndroid Build Coastguard Worker 		var = (struct btf_var *)(t + 1);
692*858ea5e5SAndroid Build Coastguard Worker 		if (var->linkage == BTF_VAR_STATIC)
693*858ea5e5SAndroid Build Coastguard Worker 			BTF_PRINT_ARG("static ");
694*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_TYPE(t->type);
695*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG(" %s",
696*858ea5e5SAndroid Build Coastguard Worker 			      btf__name_by_offset(btf, t->name_off));
697*858ea5e5SAndroid Build Coastguard Worker 		break;
698*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_DATASEC:
699*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("section (\"%s\") ",
700*858ea5e5SAndroid Build Coastguard Worker 			      btf__name_by_offset(btf, t->name_off));
701*858ea5e5SAndroid Build Coastguard Worker 		break;
702*858ea5e5SAndroid Build Coastguard Worker 	case BTF_KIND_UNKN:
703*858ea5e5SAndroid Build Coastguard Worker 	default:
704*858ea5e5SAndroid Build Coastguard Worker 		return -1;
705*858ea5e5SAndroid Build Coastguard Worker 	}
706*858ea5e5SAndroid Build Coastguard Worker 
707*858ea5e5SAndroid Build Coastguard Worker 	return pos;
708*858ea5e5SAndroid Build Coastguard Worker }
709*858ea5e5SAndroid Build Coastguard Worker 
btf_dump_func(const struct btf * btf,char * func_sig,const struct btf_type * func_proto,const struct btf_type * func,int pos,int size)710*858ea5e5SAndroid Build Coastguard Worker static int btf_dump_func(const struct btf *btf, char *func_sig,
711*858ea5e5SAndroid Build Coastguard Worker 			 const struct btf_type *func_proto,
712*858ea5e5SAndroid Build Coastguard Worker 			 const struct btf_type *func, int pos, int size)
713*858ea5e5SAndroid Build Coastguard Worker {
714*858ea5e5SAndroid Build Coastguard Worker 	int i, vlen;
715*858ea5e5SAndroid Build Coastguard Worker 
716*858ea5e5SAndroid Build Coastguard Worker 	BTF_PRINT_TYPE(func_proto->type);
717*858ea5e5SAndroid Build Coastguard Worker 	if (func)
718*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("%s(", btf__name_by_offset(btf, func->name_off));
719*858ea5e5SAndroid Build Coastguard Worker 	else
720*858ea5e5SAndroid Build Coastguard Worker 		BTF_PRINT_ARG("(");
721*858ea5e5SAndroid Build Coastguard Worker 	vlen = BTF_INFO_VLEN(func_proto->info);
722*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < vlen; i++) {
723*858ea5e5SAndroid Build Coastguard Worker 		struct btf_param *arg = &((struct btf_param *)(func_proto + 1))[i];
724*858ea5e5SAndroid Build Coastguard Worker 
725*858ea5e5SAndroid Build Coastguard Worker 		if (i)
726*858ea5e5SAndroid Build Coastguard Worker 			BTF_PRINT_ARG(", ");
727*858ea5e5SAndroid Build Coastguard Worker 		if (arg->type) {
728*858ea5e5SAndroid Build Coastguard Worker 			BTF_PRINT_TYPE(arg->type);
729*858ea5e5SAndroid Build Coastguard Worker 			if (arg->name_off)
730*858ea5e5SAndroid Build Coastguard Worker 				BTF_PRINT_ARG("%s",
731*858ea5e5SAndroid Build Coastguard Worker 					      btf__name_by_offset(btf, arg->name_off));
732*858ea5e5SAndroid Build Coastguard Worker 			else if (pos && func_sig[pos - 1] == ' ')
733*858ea5e5SAndroid Build Coastguard Worker 				/* Remove unnecessary space for
734*858ea5e5SAndroid Build Coastguard Worker 				 * FUNC_PROTO that does not have
735*858ea5e5SAndroid Build Coastguard Worker 				 * arg->name_off
736*858ea5e5SAndroid Build Coastguard Worker 				 */
737*858ea5e5SAndroid Build Coastguard Worker 				func_sig[--pos] = '\0';
738*858ea5e5SAndroid Build Coastguard Worker 		} else {
739*858ea5e5SAndroid Build Coastguard Worker 			BTF_PRINT_ARG("...");
740*858ea5e5SAndroid Build Coastguard Worker 		}
741*858ea5e5SAndroid Build Coastguard Worker 	}
742*858ea5e5SAndroid Build Coastguard Worker 	BTF_PRINT_ARG(")");
743*858ea5e5SAndroid Build Coastguard Worker 
744*858ea5e5SAndroid Build Coastguard Worker 	return pos;
745*858ea5e5SAndroid Build Coastguard Worker }
746*858ea5e5SAndroid Build Coastguard Worker 
btf_dumper_type_only(const struct btf * btf,__u32 type_id,char * func_sig,int size)747*858ea5e5SAndroid Build Coastguard Worker void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig,
748*858ea5e5SAndroid Build Coastguard Worker 			  int size)
749*858ea5e5SAndroid Build Coastguard Worker {
750*858ea5e5SAndroid Build Coastguard Worker 	int err;
751*858ea5e5SAndroid Build Coastguard Worker 
752*858ea5e5SAndroid Build Coastguard Worker 	func_sig[0] = '\0';
753*858ea5e5SAndroid Build Coastguard Worker 	if (!btf)
754*858ea5e5SAndroid Build Coastguard Worker 		return;
755*858ea5e5SAndroid Build Coastguard Worker 
756*858ea5e5SAndroid Build Coastguard Worker 	err = __btf_dumper_type_only(btf, type_id, func_sig, 0, size);
757*858ea5e5SAndroid Build Coastguard Worker 	if (err < 0)
758*858ea5e5SAndroid Build Coastguard Worker 		func_sig[0] = '\0';
759*858ea5e5SAndroid Build Coastguard Worker }
760*858ea5e5SAndroid Build Coastguard Worker 
ltrim(const char * s)761*858ea5e5SAndroid Build Coastguard Worker static const char *ltrim(const char *s)
762*858ea5e5SAndroid Build Coastguard Worker {
763*858ea5e5SAndroid Build Coastguard Worker 	while (isspace(*s))
764*858ea5e5SAndroid Build Coastguard Worker 		s++;
765*858ea5e5SAndroid Build Coastguard Worker 
766*858ea5e5SAndroid Build Coastguard Worker 	return s;
767*858ea5e5SAndroid Build Coastguard Worker }
768*858ea5e5SAndroid Build Coastguard Worker 
btf_dump_linfo_plain(const struct btf * btf,const struct bpf_line_info * linfo,const char * prefix,bool linum)769*858ea5e5SAndroid Build Coastguard Worker void btf_dump_linfo_plain(const struct btf *btf,
770*858ea5e5SAndroid Build Coastguard Worker 			  const struct bpf_line_info *linfo,
771*858ea5e5SAndroid Build Coastguard Worker 			  const char *prefix, bool linum)
772*858ea5e5SAndroid Build Coastguard Worker {
773*858ea5e5SAndroid Build Coastguard Worker 	const char *line = btf__name_by_offset(btf, linfo->line_off);
774*858ea5e5SAndroid Build Coastguard Worker 
775*858ea5e5SAndroid Build Coastguard Worker 	if (!line)
776*858ea5e5SAndroid Build Coastguard Worker 		return;
777*858ea5e5SAndroid Build Coastguard Worker 	line = ltrim(line);
778*858ea5e5SAndroid Build Coastguard Worker 
779*858ea5e5SAndroid Build Coastguard Worker 	if (!prefix)
780*858ea5e5SAndroid Build Coastguard Worker 		prefix = "";
781*858ea5e5SAndroid Build Coastguard Worker 
782*858ea5e5SAndroid Build Coastguard Worker 	if (linum) {
783*858ea5e5SAndroid Build Coastguard Worker 		const char *file = btf__name_by_offset(btf, linfo->file_name_off);
784*858ea5e5SAndroid Build Coastguard Worker 
785*858ea5e5SAndroid Build Coastguard Worker 		/* More forgiving on file because linum option is
786*858ea5e5SAndroid Build Coastguard Worker 		 * expected to provide more info than the already
787*858ea5e5SAndroid Build Coastguard Worker 		 * available src line.
788*858ea5e5SAndroid Build Coastguard Worker 		 */
789*858ea5e5SAndroid Build Coastguard Worker 		if (!file)
790*858ea5e5SAndroid Build Coastguard Worker 			file = "";
791*858ea5e5SAndroid Build Coastguard Worker 
792*858ea5e5SAndroid Build Coastguard Worker 		printf("%s%s [file:%s line_num:%u line_col:%u]\n",
793*858ea5e5SAndroid Build Coastguard Worker 		       prefix, line, file,
794*858ea5e5SAndroid Build Coastguard Worker 		       BPF_LINE_INFO_LINE_NUM(linfo->line_col),
795*858ea5e5SAndroid Build Coastguard Worker 		       BPF_LINE_INFO_LINE_COL(linfo->line_col));
796*858ea5e5SAndroid Build Coastguard Worker 	} else {
797*858ea5e5SAndroid Build Coastguard Worker 		printf("%s%s\n", prefix, line);
798*858ea5e5SAndroid Build Coastguard Worker 	}
799*858ea5e5SAndroid Build Coastguard Worker }
800*858ea5e5SAndroid Build Coastguard Worker 
btf_dump_linfo_json(const struct btf * btf,const struct bpf_line_info * linfo,bool linum)801*858ea5e5SAndroid Build Coastguard Worker void btf_dump_linfo_json(const struct btf *btf,
802*858ea5e5SAndroid Build Coastguard Worker 			 const struct bpf_line_info *linfo, bool linum)
803*858ea5e5SAndroid Build Coastguard Worker {
804*858ea5e5SAndroid Build Coastguard Worker 	const char *line = btf__name_by_offset(btf, linfo->line_off);
805*858ea5e5SAndroid Build Coastguard Worker 
806*858ea5e5SAndroid Build Coastguard Worker 	if (line)
807*858ea5e5SAndroid Build Coastguard Worker 		jsonw_string_field(json_wtr, "src", ltrim(line));
808*858ea5e5SAndroid Build Coastguard Worker 
809*858ea5e5SAndroid Build Coastguard Worker 	if (linum) {
810*858ea5e5SAndroid Build Coastguard Worker 		const char *file = btf__name_by_offset(btf, linfo->file_name_off);
811*858ea5e5SAndroid Build Coastguard Worker 
812*858ea5e5SAndroid Build Coastguard Worker 		if (file)
813*858ea5e5SAndroid Build Coastguard Worker 			jsonw_string_field(json_wtr, "file", file);
814*858ea5e5SAndroid Build Coastguard Worker 
815*858ea5e5SAndroid Build Coastguard Worker 		if (BPF_LINE_INFO_LINE_NUM(linfo->line_col))
816*858ea5e5SAndroid Build Coastguard Worker 			jsonw_int_field(json_wtr, "line_num",
817*858ea5e5SAndroid Build Coastguard Worker 					BPF_LINE_INFO_LINE_NUM(linfo->line_col));
818*858ea5e5SAndroid Build Coastguard Worker 
819*858ea5e5SAndroid Build Coastguard Worker 		if (BPF_LINE_INFO_LINE_COL(linfo->line_col))
820*858ea5e5SAndroid Build Coastguard Worker 			jsonw_int_field(json_wtr, "line_col",
821*858ea5e5SAndroid Build Coastguard Worker 					BPF_LINE_INFO_LINE_COL(linfo->line_col));
822*858ea5e5SAndroid Build Coastguard Worker 	}
823*858ea5e5SAndroid Build Coastguard Worker }
824*858ea5e5SAndroid Build Coastguard Worker 
dotlabel_puts(const char * s)825*858ea5e5SAndroid Build Coastguard Worker static void dotlabel_puts(const char *s)
826*858ea5e5SAndroid Build Coastguard Worker {
827*858ea5e5SAndroid Build Coastguard Worker 	for (; *s; ++s) {
828*858ea5e5SAndroid Build Coastguard Worker 		switch (*s) {
829*858ea5e5SAndroid Build Coastguard Worker 		case '\\':
830*858ea5e5SAndroid Build Coastguard Worker 		case '"':
831*858ea5e5SAndroid Build Coastguard Worker 		case '{':
832*858ea5e5SAndroid Build Coastguard Worker 		case '}':
833*858ea5e5SAndroid Build Coastguard Worker 		case '<':
834*858ea5e5SAndroid Build Coastguard Worker 		case '>':
835*858ea5e5SAndroid Build Coastguard Worker 		case '|':
836*858ea5e5SAndroid Build Coastguard Worker 		case ' ':
837*858ea5e5SAndroid Build Coastguard Worker 			putchar('\\');
838*858ea5e5SAndroid Build Coastguard Worker 			fallthrough;
839*858ea5e5SAndroid Build Coastguard Worker 		default:
840*858ea5e5SAndroid Build Coastguard Worker 			putchar(*s);
841*858ea5e5SAndroid Build Coastguard Worker 		}
842*858ea5e5SAndroid Build Coastguard Worker 	}
843*858ea5e5SAndroid Build Coastguard Worker }
844*858ea5e5SAndroid Build Coastguard Worker 
shorten_path(const char * path)845*858ea5e5SAndroid Build Coastguard Worker static const char *shorten_path(const char *path)
846*858ea5e5SAndroid Build Coastguard Worker {
847*858ea5e5SAndroid Build Coastguard Worker 	const unsigned int MAX_PATH_LEN = 32;
848*858ea5e5SAndroid Build Coastguard Worker 	size_t len = strlen(path);
849*858ea5e5SAndroid Build Coastguard Worker 	const char *shortpath;
850*858ea5e5SAndroid Build Coastguard Worker 
851*858ea5e5SAndroid Build Coastguard Worker 	if (len <= MAX_PATH_LEN)
852*858ea5e5SAndroid Build Coastguard Worker 		return path;
853*858ea5e5SAndroid Build Coastguard Worker 
854*858ea5e5SAndroid Build Coastguard Worker 	/* Search for last '/' under the MAX_PATH_LEN limit */
855*858ea5e5SAndroid Build Coastguard Worker 	shortpath = strchr(path + len - MAX_PATH_LEN, '/');
856*858ea5e5SAndroid Build Coastguard Worker 	if (shortpath) {
857*858ea5e5SAndroid Build Coastguard Worker 		if (shortpath < path + strlen("..."))
858*858ea5e5SAndroid Build Coastguard Worker 			/* We removed a very short prefix, e.g. "/w", and we'll
859*858ea5e5SAndroid Build Coastguard Worker 			 * make the path longer by prefixing with the ellipsis.
860*858ea5e5SAndroid Build Coastguard Worker 			 * Not worth it, keep initial path.
861*858ea5e5SAndroid Build Coastguard Worker 			 */
862*858ea5e5SAndroid Build Coastguard Worker 			return path;
863*858ea5e5SAndroid Build Coastguard Worker 		return shortpath;
864*858ea5e5SAndroid Build Coastguard Worker 	}
865*858ea5e5SAndroid Build Coastguard Worker 
866*858ea5e5SAndroid Build Coastguard Worker 	/* File base name length is > MAX_PATH_LEN, search for last '/' */
867*858ea5e5SAndroid Build Coastguard Worker 			shortpath = strrchr(path, '/');
868*858ea5e5SAndroid Build Coastguard Worker 	if (shortpath)
869*858ea5e5SAndroid Build Coastguard Worker 		return shortpath;
870*858ea5e5SAndroid Build Coastguard Worker 
871*858ea5e5SAndroid Build Coastguard Worker 	return path;
872*858ea5e5SAndroid Build Coastguard Worker }
873*858ea5e5SAndroid Build Coastguard Worker 
btf_dump_linfo_dotlabel(const struct btf * btf,const struct bpf_line_info * linfo,bool linum)874*858ea5e5SAndroid Build Coastguard Worker void btf_dump_linfo_dotlabel(const struct btf *btf,
875*858ea5e5SAndroid Build Coastguard Worker 			     const struct bpf_line_info *linfo, bool linum)
876*858ea5e5SAndroid Build Coastguard Worker {
877*858ea5e5SAndroid Build Coastguard Worker 	const char *line = btf__name_by_offset(btf, linfo->line_off);
878*858ea5e5SAndroid Build Coastguard Worker 
879*858ea5e5SAndroid Build Coastguard Worker 	if (!line || !strlen(line))
880*858ea5e5SAndroid Build Coastguard Worker 		return;
881*858ea5e5SAndroid Build Coastguard Worker 	line = ltrim(line);
882*858ea5e5SAndroid Build Coastguard Worker 
883*858ea5e5SAndroid Build Coastguard Worker 	if (linum) {
884*858ea5e5SAndroid Build Coastguard Worker 		const char *file = btf__name_by_offset(btf, linfo->file_name_off);
885*858ea5e5SAndroid Build Coastguard Worker 		const char *shortfile;
886*858ea5e5SAndroid Build Coastguard Worker 
887*858ea5e5SAndroid Build Coastguard Worker 		/* More forgiving on file because linum option is
888*858ea5e5SAndroid Build Coastguard Worker 		 * expected to provide more info than the already
889*858ea5e5SAndroid Build Coastguard Worker 		 * available src line.
890*858ea5e5SAndroid Build Coastguard Worker 		 */
891*858ea5e5SAndroid Build Coastguard Worker 		if (!file)
892*858ea5e5SAndroid Build Coastguard Worker 			shortfile = "";
893*858ea5e5SAndroid Build Coastguard Worker 		else
894*858ea5e5SAndroid Build Coastguard Worker 			shortfile = shorten_path(file);
895*858ea5e5SAndroid Build Coastguard Worker 
896*858ea5e5SAndroid Build Coastguard Worker 		printf("; [%s", shortfile > file ? "..." : "");
897*858ea5e5SAndroid Build Coastguard Worker 		dotlabel_puts(shortfile);
898*858ea5e5SAndroid Build Coastguard Worker 		printf(" line:%u col:%u]\\l\\\n",
899*858ea5e5SAndroid Build Coastguard Worker 		       BPF_LINE_INFO_LINE_NUM(linfo->line_col),
900*858ea5e5SAndroid Build Coastguard Worker 		       BPF_LINE_INFO_LINE_COL(linfo->line_col));
901*858ea5e5SAndroid Build Coastguard Worker 	}
902*858ea5e5SAndroid Build Coastguard Worker 
903*858ea5e5SAndroid Build Coastguard Worker 	printf("; ");
904*858ea5e5SAndroid Build Coastguard Worker 	dotlabel_puts(line);
905*858ea5e5SAndroid Build Coastguard Worker 	printf("\\l\\\n");
906*858ea5e5SAndroid Build Coastguard Worker }
907