forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/tools/bpf/bpftool/btf_dumper.c
....@@ -1,15 +1,17 @@
1
-// SPDX-License-Identifier: GPL-2.0
1
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
22 /* Copyright (c) 2018 Facebook */
33
44 #include <ctype.h>
55 #include <stdio.h> /* for (FILE *) used by json_writer */
66 #include <string.h>
7
+#include <unistd.h>
78 #include <asm/byteorder.h>
89 #include <linux/bitops.h>
910 #include <linux/btf.h>
1011 #include <linux/err.h>
12
+#include <bpf/btf.h>
13
+#include <bpf/bpf.h>
1114
12
-#include "btf.h"
1315 #include "json_writer.h"
1416 #include "main.h"
1517
....@@ -22,13 +24,102 @@
2224 static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
2325 __u8 bit_offset, const void *data);
2426
25
-static void btf_dumper_ptr(const void *data, json_writer_t *jw,
26
- bool is_plain_text)
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
+
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)
2734 {
28
- if (is_plain_text)
29
- jsonw_printf(jw, "%p", *(void **)data);
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
+ btf__get_from_id(info->btf_id, &prog_btf))
69
+ goto print;
70
+ finfo = u64_to_ptr(info->func_info);
71
+ func_type = btf__type_by_id(prog_btf, finfo->type_id);
72
+ if (!func_type || !btf_is_func(func_type))
73
+ goto print;
74
+
75
+ prog_name = btf__name_by_offset(prog_btf, func_type->name_off);
76
+
77
+print:
78
+ if (!prog_id)
79
+ snprintf(&prog_str[func_sig_len],
80
+ sizeof(prog_str) - func_sig_len, " 0");
81
+ else if (prog_name)
82
+ snprintf(&prog_str[func_sig_len],
83
+ sizeof(prog_str) - func_sig_len,
84
+ " %s/prog_id:%u", prog_name, prog_id);
3085 else
31
- jsonw_printf(jw, "%lu", *(unsigned long *)data);
86
+ snprintf(&prog_str[func_sig_len],
87
+ sizeof(prog_str) - func_sig_len,
88
+ " <unknown_prog_name>/prog_id:%u", prog_id);
89
+
90
+ prog_str[sizeof(prog_str) - 1] = '\0';
91
+ jsonw_string(d->jw, prog_str);
92
+ btf__free(prog_btf);
93
+ free(prog_info);
94
+ return 0;
95
+}
96
+
97
+static void btf_dumper_ptr(const struct btf_dumper *d,
98
+ const struct btf_type *t,
99
+ const void *data)
100
+{
101
+ unsigned long value = *(unsigned long *)data;
102
+ const struct btf_type *ptr_type;
103
+ __s32 ptr_type_id;
104
+
105
+ if (!d->prog_id_as_func_ptr || value > UINT32_MAX)
106
+ goto print_ptr_value;
107
+
108
+ ptr_type_id = btf__resolve_type(d->btf, t->type);
109
+ if (ptr_type_id < 0)
110
+ goto print_ptr_value;
111
+ ptr_type = btf__type_by_id(d->btf, ptr_type_id);
112
+ if (!ptr_type || !btf_is_func_proto(ptr_type))
113
+ goto print_ptr_value;
114
+
115
+ if (!dump_prog_id_as_func_ptr(d, ptr_type, value))
116
+ return;
117
+
118
+print_ptr_value:
119
+ if (d->is_plain_text)
120
+ jsonw_printf(d->jw, "%p", (void *)value);
121
+ else
122
+ jsonw_printf(d->jw, "%lu", value);
32123 }
33124
34125 static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id,
....@@ -43,9 +134,78 @@
43134 return btf_dumper_do_type(d, actual_type_id, bit_offset, data);
44135 }
45136
46
-static void btf_dumper_enum(const void *data, json_writer_t *jw)
137
+static int btf_dumper_enum(const struct btf_dumper *d,
138
+ const struct btf_type *t,
139
+ const void *data)
47140 {
48
- jsonw_printf(jw, "%d", *(int *)data);
141
+ const struct btf_enum *enums = btf_enum(t);
142
+ __s64 value;
143
+ __u16 i;
144
+
145
+ switch (t->size) {
146
+ case 8:
147
+ value = *(__s64 *)data;
148
+ break;
149
+ case 4:
150
+ value = *(__s32 *)data;
151
+ break;
152
+ case 2:
153
+ value = *(__s16 *)data;
154
+ break;
155
+ case 1:
156
+ value = *(__s8 *)data;
157
+ break;
158
+ default:
159
+ return -EINVAL;
160
+ }
161
+
162
+ for (i = 0; i < btf_vlen(t); i++) {
163
+ if (value == enums[i].val) {
164
+ jsonw_string(d->jw,
165
+ btf__name_by_offset(d->btf,
166
+ enums[i].name_off));
167
+ return 0;
168
+ }
169
+ }
170
+
171
+ jsonw_int(d->jw, value);
172
+ return 0;
173
+}
174
+
175
+static bool is_str_array(const struct btf *btf, const struct btf_array *arr,
176
+ const char *s)
177
+{
178
+ const struct btf_type *elem_type;
179
+ const char *end_s;
180
+
181
+ if (!arr->nelems)
182
+ return false;
183
+
184
+ elem_type = btf__type_by_id(btf, arr->type);
185
+ /* Not skipping typedef. typedef to char does not count as
186
+ * a string now.
187
+ */
188
+ while (elem_type && btf_is_mod(elem_type))
189
+ elem_type = btf__type_by_id(btf, elem_type->type);
190
+
191
+ if (!elem_type || !btf_is_int(elem_type) || elem_type->size != 1)
192
+ return false;
193
+
194
+ if (btf_int_encoding(elem_type) != BTF_INT_CHAR &&
195
+ strcmp("char", btf__name_by_offset(btf, elem_type->name_off)))
196
+ return false;
197
+
198
+ end_s = s + arr->nelems;
199
+ while (s < end_s) {
200
+ if (!*s)
201
+ return true;
202
+ if (*s <= 0x1f || *s >= 0x7f)
203
+ return false;
204
+ s++;
205
+ }
206
+
207
+ /* '\0' is not found */
208
+ return false;
49209 }
50210
51211 static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id,
....@@ -56,6 +216,11 @@
56216 long long elem_size;
57217 int ret = 0;
58218 __u32 i;
219
+
220
+ if (is_str_array(d->btf, arr, data)) {
221
+ jsonw_string(d->jw, data);
222
+ return 0;
223
+ }
59224
60225 elem_size = btf__resolve_size(d->btf, arr->type);
61226 if (elem_size < 0)
....@@ -73,40 +238,122 @@
73238 return ret;
74239 }
75240
76
-static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
241
+static void btf_int128_print(json_writer_t *jw, const void *data,
242
+ bool is_plain_text)
243
+{
244
+ /* data points to a __int128 number.
245
+ * Suppose
246
+ * int128_num = *(__int128 *)data;
247
+ * The below formulas shows what upper_num and lower_num represents:
248
+ * upper_num = int128_num >> 64;
249
+ * lower_num = int128_num & 0xffffffffFFFFFFFFULL;
250
+ */
251
+ __u64 upper_num, lower_num;
252
+
253
+#ifdef __BIG_ENDIAN_BITFIELD
254
+ upper_num = *(__u64 *)data;
255
+ lower_num = *(__u64 *)(data + 8);
256
+#else
257
+ upper_num = *(__u64 *)(data + 8);
258
+ lower_num = *(__u64 *)data;
259
+#endif
260
+
261
+ if (is_plain_text) {
262
+ if (upper_num == 0)
263
+ jsonw_printf(jw, "0x%llx", lower_num);
264
+ else
265
+ jsonw_printf(jw, "0x%llx%016llx", upper_num, lower_num);
266
+ } else {
267
+ if (upper_num == 0)
268
+ jsonw_printf(jw, "\"0x%llx\"", lower_num);
269
+ else
270
+ jsonw_printf(jw, "\"0x%llx%016llx\"", upper_num, lower_num);
271
+ }
272
+}
273
+
274
+static void btf_int128_shift(__u64 *print_num, __u16 left_shift_bits,
275
+ __u16 right_shift_bits)
276
+{
277
+ __u64 upper_num, lower_num;
278
+
279
+#ifdef __BIG_ENDIAN_BITFIELD
280
+ upper_num = print_num[0];
281
+ lower_num = print_num[1];
282
+#else
283
+ upper_num = print_num[1];
284
+ lower_num = print_num[0];
285
+#endif
286
+
287
+ /* shake out un-needed bits by shift/or operations */
288
+ if (left_shift_bits >= 64) {
289
+ upper_num = lower_num << (left_shift_bits - 64);
290
+ lower_num = 0;
291
+ } else {
292
+ upper_num = (upper_num << left_shift_bits) |
293
+ (lower_num >> (64 - left_shift_bits));
294
+ lower_num = lower_num << left_shift_bits;
295
+ }
296
+
297
+ if (right_shift_bits >= 64) {
298
+ lower_num = upper_num >> (right_shift_bits - 64);
299
+ upper_num = 0;
300
+ } else {
301
+ lower_num = (lower_num >> right_shift_bits) |
302
+ (upper_num << (64 - right_shift_bits));
303
+ upper_num = upper_num >> right_shift_bits;
304
+ }
305
+
306
+#ifdef __BIG_ENDIAN_BITFIELD
307
+ print_num[0] = upper_num;
308
+ print_num[1] = lower_num;
309
+#else
310
+ print_num[0] = lower_num;
311
+ print_num[1] = upper_num;
312
+#endif
313
+}
314
+
315
+static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset,
77316 const void *data, json_writer_t *jw,
78317 bool is_plain_text)
79318 {
80319 int left_shift_bits, right_shift_bits;
81
- int nr_bits = BTF_INT_BITS(int_type);
82
- int total_bits_offset;
320
+ __u64 print_num[2] = {};
83321 int bytes_to_copy;
84322 int bits_to_copy;
85
- __u64 print_num;
86323
87
- total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
88
- data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
89
- bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
90324 bits_to_copy = bit_offset + nr_bits;
91325 bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
92326
93
- print_num = 0;
94
- memcpy(&print_num, data, bytes_to_copy);
327
+ memcpy(print_num, data, bytes_to_copy);
95328 #if defined(__BIG_ENDIAN_BITFIELD)
96329 left_shift_bits = bit_offset;
97330 #elif defined(__LITTLE_ENDIAN_BITFIELD)
98
- left_shift_bits = 64 - bits_to_copy;
331
+ left_shift_bits = 128 - bits_to_copy;
99332 #else
100333 #error neither big nor little endian
101334 #endif
102
- right_shift_bits = 64 - nr_bits;
335
+ right_shift_bits = 128 - nr_bits;
103336
104
- print_num <<= left_shift_bits;
105
- print_num >>= right_shift_bits;
106
- if (is_plain_text)
107
- jsonw_printf(jw, "0x%llx", print_num);
108
- else
109
- jsonw_printf(jw, "%llu", print_num);
337
+ btf_int128_shift(print_num, left_shift_bits, right_shift_bits);
338
+ btf_int128_print(jw, print_num, is_plain_text);
339
+}
340
+
341
+
342
+static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
343
+ const void *data, json_writer_t *jw,
344
+ bool is_plain_text)
345
+{
346
+ int nr_bits = BTF_INT_BITS(int_type);
347
+ int total_bits_offset;
348
+
349
+ /* bits_offset is at most 7.
350
+ * BTF_INT_OFFSET() cannot exceed 128 bits.
351
+ */
352
+ total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
353
+ data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
354
+ bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
355
+ btf_dumper_bitfield(nr_bits, bit_offset, data, jw,
356
+ is_plain_text);
110357 }
111358
112359 static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset,
....@@ -123,6 +370,11 @@
123370 BITS_PER_BYTE_MASKED(nr_bits)) {
124371 btf_dumper_int_bits(*int_type, bit_offset, data, jw,
125372 is_plain_text);
373
+ return 0;
374
+ }
375
+
376
+ if (nr_bits == 128) {
377
+ btf_int128_print(jw, data, is_plain_text);
126378 return 0;
127379 }
128380
....@@ -164,7 +416,7 @@
164416 *(char *)data);
165417 break;
166418 case BTF_INT_BOOL:
167
- jsonw_bool(jw, *(int *)data);
419
+ jsonw_bool(jw, *(bool *)data);
168420 break;
169421 default:
170422 /* shouldn't happen */
....@@ -180,6 +432,7 @@
180432 const struct btf_type *t;
181433 struct btf_member *m;
182434 const void *data_off;
435
+ int kind_flag;
183436 int ret = 0;
184437 int i, vlen;
185438
....@@ -187,20 +440,77 @@
187440 if (!t)
188441 return -EINVAL;
189442
443
+ kind_flag = BTF_INFO_KFLAG(t->info);
190444 vlen = BTF_INFO_VLEN(t->info);
191445 jsonw_start_object(d->jw);
192446 m = (struct btf_member *)(t + 1);
193447
194448 for (i = 0; i < vlen; i++) {
195
- data_off = data + BITS_ROUNDDOWN_BYTES(m[i].offset);
449
+ __u32 bit_offset = m[i].offset;
450
+ __u32 bitfield_size = 0;
451
+
452
+ if (kind_flag) {
453
+ bitfield_size = BTF_MEMBER_BITFIELD_SIZE(bit_offset);
454
+ bit_offset = BTF_MEMBER_BIT_OFFSET(bit_offset);
455
+ }
456
+
196457 jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off));
197
- ret = btf_dumper_do_type(d, m[i].type,
198
- BITS_PER_BYTE_MASKED(m[i].offset),
199
- data_off);
458
+ data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset);
459
+ if (bitfield_size) {
460
+ btf_dumper_bitfield(bitfield_size,
461
+ BITS_PER_BYTE_MASKED(bit_offset),
462
+ data_off, d->jw, d->is_plain_text);
463
+ } else {
464
+ ret = btf_dumper_do_type(d, m[i].type,
465
+ BITS_PER_BYTE_MASKED(bit_offset),
466
+ data_off);
467
+ if (ret)
468
+ break;
469
+ }
470
+ }
471
+
472
+ jsonw_end_object(d->jw);
473
+
474
+ return ret;
475
+}
476
+
477
+static int btf_dumper_var(const struct btf_dumper *d, __u32 type_id,
478
+ __u8 bit_offset, const void *data)
479
+{
480
+ const struct btf_type *t = btf__type_by_id(d->btf, type_id);
481
+ int ret;
482
+
483
+ jsonw_start_object(d->jw);
484
+ jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off));
485
+ ret = btf_dumper_do_type(d, t->type, bit_offset, data);
486
+ jsonw_end_object(d->jw);
487
+
488
+ return ret;
489
+}
490
+
491
+static int btf_dumper_datasec(const struct btf_dumper *d, __u32 type_id,
492
+ const void *data)
493
+{
494
+ struct btf_var_secinfo *vsi;
495
+ const struct btf_type *t;
496
+ int ret = 0, i, vlen;
497
+
498
+ t = btf__type_by_id(d->btf, type_id);
499
+ if (!t)
500
+ return -EINVAL;
501
+
502
+ vlen = BTF_INFO_VLEN(t->info);
503
+ vsi = (struct btf_var_secinfo *)(t + 1);
504
+
505
+ jsonw_start_object(d->jw);
506
+ jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off));
507
+ jsonw_start_array(d->jw);
508
+ for (i = 0; i < vlen; i++) {
509
+ ret = btf_dumper_do_type(d, vsi[i].type, 0, data + vsi[i].offset);
200510 if (ret)
201511 break;
202512 }
203
-
513
+ jsonw_end_array(d->jw);
204514 jsonw_end_object(d->jw);
205515
206516 return ret;
....@@ -221,10 +531,9 @@
221531 case BTF_KIND_ARRAY:
222532 return btf_dumper_array(d, type_id, data);
223533 case BTF_KIND_ENUM:
224
- btf_dumper_enum(data, d->jw);
225
- return 0;
534
+ return btf_dumper_enum(d, t, data);
226535 case BTF_KIND_PTR:
227
- btf_dumper_ptr(data, d->jw, d->is_plain_text);
536
+ btf_dumper_ptr(d, t, data);
228537 return 0;
229538 case BTF_KIND_UNKN:
230539 jsonw_printf(d->jw, "(unknown)");
....@@ -238,6 +547,10 @@
238547 case BTF_KIND_CONST:
239548 case BTF_KIND_RESTRICT:
240549 return btf_dumper_modifier(d, type_id, bit_offset, data);
550
+ case BTF_KIND_VAR:
551
+ return btf_dumper_var(d, type_id, bit_offset, data);
552
+ case BTF_KIND_DATASEC:
553
+ return btf_dumper_datasec(d, type_id, data);
241554 default:
242555 jsonw_printf(d->jw, "(unsupported-kind");
243556 return -EINVAL;
....@@ -249,3 +562,222 @@
249562 {
250563 return btf_dumper_do_type(d, type_id, 0, data);
251564 }
565
+
566
+#define BTF_PRINT_ARG(...) \
567
+ do { \
568
+ pos += snprintf(func_sig + pos, size - pos, \
569
+ __VA_ARGS__); \
570
+ if (pos >= size) \
571
+ return -1; \
572
+ } while (0)
573
+#define BTF_PRINT_TYPE(type) \
574
+ do { \
575
+ pos = __btf_dumper_type_only(btf, type, func_sig, \
576
+ pos, size); \
577
+ if (pos == -1) \
578
+ return -1; \
579
+ } while (0)
580
+
581
+static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
582
+ char *func_sig, int pos, int size)
583
+{
584
+ const struct btf_type *proto_type;
585
+ const struct btf_array *array;
586
+ const struct btf_var *var;
587
+ const struct btf_type *t;
588
+
589
+ if (!type_id) {
590
+ BTF_PRINT_ARG("void ");
591
+ return pos;
592
+ }
593
+
594
+ t = btf__type_by_id(btf, type_id);
595
+
596
+ switch (BTF_INFO_KIND(t->info)) {
597
+ case BTF_KIND_INT:
598
+ case BTF_KIND_TYPEDEF:
599
+ BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off));
600
+ break;
601
+ case BTF_KIND_STRUCT:
602
+ BTF_PRINT_ARG("struct %s ",
603
+ btf__name_by_offset(btf, t->name_off));
604
+ break;
605
+ case BTF_KIND_UNION:
606
+ BTF_PRINT_ARG("union %s ",
607
+ btf__name_by_offset(btf, t->name_off));
608
+ break;
609
+ case BTF_KIND_ENUM:
610
+ BTF_PRINT_ARG("enum %s ",
611
+ btf__name_by_offset(btf, t->name_off));
612
+ break;
613
+ case BTF_KIND_ARRAY:
614
+ array = (struct btf_array *)(t + 1);
615
+ BTF_PRINT_TYPE(array->type);
616
+ BTF_PRINT_ARG("[%d]", array->nelems);
617
+ break;
618
+ case BTF_KIND_PTR:
619
+ BTF_PRINT_TYPE(t->type);
620
+ BTF_PRINT_ARG("* ");
621
+ break;
622
+ case BTF_KIND_FWD:
623
+ BTF_PRINT_ARG("%s %s ",
624
+ BTF_INFO_KFLAG(t->info) ? "union" : "struct",
625
+ btf__name_by_offset(btf, t->name_off));
626
+ break;
627
+ case BTF_KIND_VOLATILE:
628
+ BTF_PRINT_ARG("volatile ");
629
+ BTF_PRINT_TYPE(t->type);
630
+ break;
631
+ case BTF_KIND_CONST:
632
+ BTF_PRINT_ARG("const ");
633
+ BTF_PRINT_TYPE(t->type);
634
+ break;
635
+ case BTF_KIND_RESTRICT:
636
+ BTF_PRINT_ARG("restrict ");
637
+ BTF_PRINT_TYPE(t->type);
638
+ break;
639
+ case BTF_KIND_FUNC_PROTO:
640
+ pos = btf_dump_func(btf, func_sig, t, NULL, pos, size);
641
+ if (pos == -1)
642
+ return -1;
643
+ break;
644
+ case BTF_KIND_FUNC:
645
+ proto_type = btf__type_by_id(btf, t->type);
646
+ pos = btf_dump_func(btf, func_sig, proto_type, t, pos, size);
647
+ if (pos == -1)
648
+ return -1;
649
+ break;
650
+ case BTF_KIND_VAR:
651
+ var = (struct btf_var *)(t + 1);
652
+ if (var->linkage == BTF_VAR_STATIC)
653
+ BTF_PRINT_ARG("static ");
654
+ BTF_PRINT_TYPE(t->type);
655
+ BTF_PRINT_ARG(" %s",
656
+ btf__name_by_offset(btf, t->name_off));
657
+ break;
658
+ case BTF_KIND_DATASEC:
659
+ BTF_PRINT_ARG("section (\"%s\") ",
660
+ btf__name_by_offset(btf, t->name_off));
661
+ break;
662
+ case BTF_KIND_UNKN:
663
+ default:
664
+ return -1;
665
+ }
666
+
667
+ return pos;
668
+}
669
+
670
+static int btf_dump_func(const struct btf *btf, char *func_sig,
671
+ const struct btf_type *func_proto,
672
+ const struct btf_type *func, int pos, int size)
673
+{
674
+ int i, vlen;
675
+
676
+ BTF_PRINT_TYPE(func_proto->type);
677
+ if (func)
678
+ BTF_PRINT_ARG("%s(", btf__name_by_offset(btf, func->name_off));
679
+ else
680
+ BTF_PRINT_ARG("(");
681
+ vlen = BTF_INFO_VLEN(func_proto->info);
682
+ for (i = 0; i < vlen; i++) {
683
+ struct btf_param *arg = &((struct btf_param *)(func_proto + 1))[i];
684
+
685
+ if (i)
686
+ BTF_PRINT_ARG(", ");
687
+ if (arg->type) {
688
+ BTF_PRINT_TYPE(arg->type);
689
+ if (arg->name_off)
690
+ BTF_PRINT_ARG("%s",
691
+ btf__name_by_offset(btf, arg->name_off));
692
+ else if (pos && func_sig[pos - 1] == ' ')
693
+ /* Remove unnecessary space for
694
+ * FUNC_PROTO that does not have
695
+ * arg->name_off
696
+ */
697
+ func_sig[--pos] = '\0';
698
+ } else {
699
+ BTF_PRINT_ARG("...");
700
+ }
701
+ }
702
+ BTF_PRINT_ARG(")");
703
+
704
+ return pos;
705
+}
706
+
707
+void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig,
708
+ int size)
709
+{
710
+ int err;
711
+
712
+ func_sig[0] = '\0';
713
+ if (!btf)
714
+ return;
715
+
716
+ err = __btf_dumper_type_only(btf, type_id, func_sig, 0, size);
717
+ if (err < 0)
718
+ func_sig[0] = '\0';
719
+}
720
+
721
+static const char *ltrim(const char *s)
722
+{
723
+ while (isspace(*s))
724
+ s++;
725
+
726
+ return s;
727
+}
728
+
729
+void btf_dump_linfo_plain(const struct btf *btf,
730
+ const struct bpf_line_info *linfo,
731
+ const char *prefix, bool linum)
732
+{
733
+ const char *line = btf__name_by_offset(btf, linfo->line_off);
734
+
735
+ if (!line)
736
+ return;
737
+ line = ltrim(line);
738
+
739
+ if (!prefix)
740
+ prefix = "";
741
+
742
+ if (linum) {
743
+ const char *file = btf__name_by_offset(btf, linfo->file_name_off);
744
+
745
+ /* More forgiving on file because linum option is
746
+ * expected to provide more info than the already
747
+ * available src line.
748
+ */
749
+ if (!file)
750
+ file = "";
751
+
752
+ printf("%s%s [file:%s line_num:%u line_col:%u]\n",
753
+ prefix, line, file,
754
+ BPF_LINE_INFO_LINE_NUM(linfo->line_col),
755
+ BPF_LINE_INFO_LINE_COL(linfo->line_col));
756
+ } else {
757
+ printf("%s%s\n", prefix, line);
758
+ }
759
+}
760
+
761
+void btf_dump_linfo_json(const struct btf *btf,
762
+ const struct bpf_line_info *linfo, bool linum)
763
+{
764
+ const char *line = btf__name_by_offset(btf, linfo->line_off);
765
+
766
+ if (line)
767
+ jsonw_string_field(json_wtr, "src", ltrim(line));
768
+
769
+ if (linum) {
770
+ const char *file = btf__name_by_offset(btf, linfo->file_name_off);
771
+
772
+ if (file)
773
+ jsonw_string_field(json_wtr, "file", file);
774
+
775
+ if (BPF_LINE_INFO_LINE_NUM(linfo->line_col))
776
+ jsonw_int_field(json_wtr, "line_num",
777
+ BPF_LINE_INFO_LINE_NUM(linfo->line_col));
778
+
779
+ if (BPF_LINE_INFO_LINE_COL(linfo->line_col))
780
+ jsonw_int_field(json_wtr, "line_col",
781
+ BPF_LINE_INFO_LINE_COL(linfo->line_col));
782
+ }
783
+}