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