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