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