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