btf_dumper.c (19534B)
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 24static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id, 25 __u8 bit_offset, const void *data); 26 27static 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 31static 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_obj_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_obj_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 (libbpf_get_error(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 86print: 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 107static 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 128print_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 135static 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 147static 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 185static bool is_str_array(const struct btf *btf, const struct btf_array *arr, 186 const char *s) 187{ 188 const struct btf_type *elem_type; 189 const char *end_s; 190 191 if (!arr->nelems) 192 return false; 193 194 elem_type = btf__type_by_id(btf, arr->type); 195 /* Not skipping typedef. typedef to char does not count as 196 * a string now. 197 */ 198 while (elem_type && btf_is_mod(elem_type)) 199 elem_type = btf__type_by_id(btf, elem_type->type); 200 201 if (!elem_type || !btf_is_int(elem_type) || elem_type->size != 1) 202 return false; 203 204 if (btf_int_encoding(elem_type) != BTF_INT_CHAR && 205 strcmp("char", btf__name_by_offset(btf, elem_type->name_off))) 206 return false; 207 208 end_s = s + arr->nelems; 209 while (s < end_s) { 210 if (!*s) 211 return true; 212 if (*s <= 0x1f || *s >= 0x7f) 213 return false; 214 s++; 215 } 216 217 /* '\0' is not found */ 218 return false; 219} 220 221static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id, 222 const void *data) 223{ 224 const struct btf_type *t = btf__type_by_id(d->btf, type_id); 225 struct btf_array *arr = (struct btf_array *)(t + 1); 226 long long elem_size; 227 int ret = 0; 228 __u32 i; 229 230 if (is_str_array(d->btf, arr, data)) { 231 jsonw_string(d->jw, data); 232 return 0; 233 } 234 235 elem_size = btf__resolve_size(d->btf, arr->type); 236 if (elem_size < 0) 237 return elem_size; 238 239 jsonw_start_array(d->jw); 240 for (i = 0; i < arr->nelems; i++) { 241 ret = btf_dumper_do_type(d, arr->type, 0, 242 data + i * elem_size); 243 if (ret) 244 break; 245 } 246 247 jsonw_end_array(d->jw); 248 return ret; 249} 250 251static void btf_int128_print(json_writer_t *jw, const void *data, 252 bool is_plain_text) 253{ 254 /* data points to a __int128 number. 255 * Suppose 256 * int128_num = *(__int128 *)data; 257 * The below formulas shows what upper_num and lower_num represents: 258 * upper_num = int128_num >> 64; 259 * lower_num = int128_num & 0xffffffffFFFFFFFFULL; 260 */ 261 __u64 upper_num, lower_num; 262 263#ifdef __BIG_ENDIAN_BITFIELD 264 upper_num = *(__u64 *)data; 265 lower_num = *(__u64 *)(data + 8); 266#else 267 upper_num = *(__u64 *)(data + 8); 268 lower_num = *(__u64 *)data; 269#endif 270 271 if (is_plain_text) { 272 if (upper_num == 0) 273 jsonw_printf(jw, "0x%llx", lower_num); 274 else 275 jsonw_printf(jw, "0x%llx%016llx", upper_num, lower_num); 276 } else { 277 if (upper_num == 0) 278 jsonw_printf(jw, "\"0x%llx\"", lower_num); 279 else 280 jsonw_printf(jw, "\"0x%llx%016llx\"", upper_num, lower_num); 281 } 282} 283 284static void btf_int128_shift(__u64 *print_num, __u16 left_shift_bits, 285 __u16 right_shift_bits) 286{ 287 __u64 upper_num, lower_num; 288 289#ifdef __BIG_ENDIAN_BITFIELD 290 upper_num = print_num[0]; 291 lower_num = print_num[1]; 292#else 293 upper_num = print_num[1]; 294 lower_num = print_num[0]; 295#endif 296 297 /* shake out un-needed bits by shift/or operations */ 298 if (left_shift_bits >= 64) { 299 upper_num = lower_num << (left_shift_bits - 64); 300 lower_num = 0; 301 } else { 302 upper_num = (upper_num << left_shift_bits) | 303 (lower_num >> (64 - left_shift_bits)); 304 lower_num = lower_num << left_shift_bits; 305 } 306 307 if (right_shift_bits >= 64) { 308 lower_num = upper_num >> (right_shift_bits - 64); 309 upper_num = 0; 310 } else { 311 lower_num = (lower_num >> right_shift_bits) | 312 (upper_num << (64 - right_shift_bits)); 313 upper_num = upper_num >> right_shift_bits; 314 } 315 316#ifdef __BIG_ENDIAN_BITFIELD 317 print_num[0] = upper_num; 318 print_num[1] = lower_num; 319#else 320 print_num[0] = lower_num; 321 print_num[1] = upper_num; 322#endif 323} 324 325static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset, 326 const void *data, json_writer_t *jw, 327 bool is_plain_text) 328{ 329 int left_shift_bits, right_shift_bits; 330 __u64 print_num[2] = {}; 331 int bytes_to_copy; 332 int bits_to_copy; 333 334 bits_to_copy = bit_offset + nr_bits; 335 bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy); 336 337 memcpy(print_num, data, bytes_to_copy); 338#if defined(__BIG_ENDIAN_BITFIELD) 339 left_shift_bits = bit_offset; 340#elif defined(__LITTLE_ENDIAN_BITFIELD) 341 left_shift_bits = 128 - bits_to_copy; 342#else 343#error neither big nor little endian 344#endif 345 right_shift_bits = 128 - nr_bits; 346 347 btf_int128_shift(print_num, left_shift_bits, right_shift_bits); 348 btf_int128_print(jw, print_num, is_plain_text); 349} 350 351 352static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset, 353 const void *data, json_writer_t *jw, 354 bool is_plain_text) 355{ 356 int nr_bits = BTF_INT_BITS(int_type); 357 int total_bits_offset; 358 359 /* bits_offset is at most 7. 360 * BTF_INT_OFFSET() cannot exceed 128 bits. 361 */ 362 total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type); 363 data += BITS_ROUNDDOWN_BYTES(total_bits_offset); 364 bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset); 365 btf_dumper_bitfield(nr_bits, bit_offset, data, jw, 366 is_plain_text); 367} 368 369static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset, 370 const void *data, json_writer_t *jw, 371 bool is_plain_text) 372{ 373 __u32 *int_type; 374 __u32 nr_bits; 375 376 int_type = (__u32 *)(t + 1); 377 nr_bits = BTF_INT_BITS(*int_type); 378 /* if this is bit field */ 379 if (bit_offset || BTF_INT_OFFSET(*int_type) || 380 BITS_PER_BYTE_MASKED(nr_bits)) { 381 btf_dumper_int_bits(*int_type, bit_offset, data, jw, 382 is_plain_text); 383 return 0; 384 } 385 386 if (nr_bits == 128) { 387 btf_int128_print(jw, data, is_plain_text); 388 return 0; 389 } 390 391 switch (BTF_INT_ENCODING(*int_type)) { 392 case 0: 393 if (BTF_INT_BITS(*int_type) == 64) 394 jsonw_printf(jw, "%llu", *(__u64 *)data); 395 else if (BTF_INT_BITS(*int_type) == 32) 396 jsonw_printf(jw, "%u", *(__u32 *)data); 397 else if (BTF_INT_BITS(*int_type) == 16) 398 jsonw_printf(jw, "%hu", *(__u16 *)data); 399 else if (BTF_INT_BITS(*int_type) == 8) 400 jsonw_printf(jw, "%hhu", *(__u8 *)data); 401 else 402 btf_dumper_int_bits(*int_type, bit_offset, data, jw, 403 is_plain_text); 404 break; 405 case BTF_INT_SIGNED: 406 if (BTF_INT_BITS(*int_type) == 64) 407 jsonw_printf(jw, "%lld", *(long long *)data); 408 else if (BTF_INT_BITS(*int_type) == 32) 409 jsonw_printf(jw, "%d", *(int *)data); 410 else if (BTF_INT_BITS(*int_type) == 16) 411 jsonw_printf(jw, "%hd", *(short *)data); 412 else if (BTF_INT_BITS(*int_type) == 8) 413 jsonw_printf(jw, "%hhd", *(char *)data); 414 else 415 btf_dumper_int_bits(*int_type, bit_offset, data, jw, 416 is_plain_text); 417 break; 418 case BTF_INT_CHAR: 419 if (isprint(*(char *)data)) 420 jsonw_printf(jw, "\"%c\"", *(char *)data); 421 else 422 if (is_plain_text) 423 jsonw_printf(jw, "0x%hhx", *(char *)data); 424 else 425 jsonw_printf(jw, "\"\\u00%02hhx\"", 426 *(char *)data); 427 break; 428 case BTF_INT_BOOL: 429 jsonw_bool(jw, *(int *)data); 430 break; 431 default: 432 /* shouldn't happen */ 433 return -EINVAL; 434 } 435 436 return 0; 437} 438 439static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id, 440 const void *data) 441{ 442 const struct btf_type *t; 443 struct btf_member *m; 444 const void *data_off; 445 int kind_flag; 446 int ret = 0; 447 int i, vlen; 448 449 t = btf__type_by_id(d->btf, type_id); 450 if (!t) 451 return -EINVAL; 452 453 kind_flag = BTF_INFO_KFLAG(t->info); 454 vlen = BTF_INFO_VLEN(t->info); 455 jsonw_start_object(d->jw); 456 m = (struct btf_member *)(t + 1); 457 458 for (i = 0; i < vlen; i++) { 459 __u32 bit_offset = m[i].offset; 460 __u32 bitfield_size = 0; 461 462 if (kind_flag) { 463 bitfield_size = BTF_MEMBER_BITFIELD_SIZE(bit_offset); 464 bit_offset = BTF_MEMBER_BIT_OFFSET(bit_offset); 465 } 466 467 jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off)); 468 data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset); 469 if (bitfield_size) { 470 btf_dumper_bitfield(bitfield_size, 471 BITS_PER_BYTE_MASKED(bit_offset), 472 data_off, d->jw, d->is_plain_text); 473 } else { 474 ret = btf_dumper_do_type(d, m[i].type, 475 BITS_PER_BYTE_MASKED(bit_offset), 476 data_off); 477 if (ret) 478 break; 479 } 480 } 481 482 jsonw_end_object(d->jw); 483 484 return ret; 485} 486 487static int btf_dumper_var(const struct btf_dumper *d, __u32 type_id, 488 __u8 bit_offset, const void *data) 489{ 490 const struct btf_type *t = btf__type_by_id(d->btf, type_id); 491 int ret; 492 493 jsonw_start_object(d->jw); 494 jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off)); 495 ret = btf_dumper_do_type(d, t->type, bit_offset, data); 496 jsonw_end_object(d->jw); 497 498 return ret; 499} 500 501static int btf_dumper_datasec(const struct btf_dumper *d, __u32 type_id, 502 const void *data) 503{ 504 struct btf_var_secinfo *vsi; 505 const struct btf_type *t; 506 int ret = 0, i, vlen; 507 508 t = btf__type_by_id(d->btf, type_id); 509 if (!t) 510 return -EINVAL; 511 512 vlen = BTF_INFO_VLEN(t->info); 513 vsi = (struct btf_var_secinfo *)(t + 1); 514 515 jsonw_start_object(d->jw); 516 jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off)); 517 jsonw_start_array(d->jw); 518 for (i = 0; i < vlen; i++) { 519 ret = btf_dumper_do_type(d, vsi[i].type, 0, data + vsi[i].offset); 520 if (ret) 521 break; 522 } 523 jsonw_end_array(d->jw); 524 jsonw_end_object(d->jw); 525 526 return ret; 527} 528 529static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id, 530 __u8 bit_offset, const void *data) 531{ 532 const struct btf_type *t = btf__type_by_id(d->btf, type_id); 533 534 switch (BTF_INFO_KIND(t->info)) { 535 case BTF_KIND_INT: 536 return btf_dumper_int(t, bit_offset, data, d->jw, 537 d->is_plain_text); 538 case BTF_KIND_STRUCT: 539 case BTF_KIND_UNION: 540 return btf_dumper_struct(d, type_id, data); 541 case BTF_KIND_ARRAY: 542 return btf_dumper_array(d, type_id, data); 543 case BTF_KIND_ENUM: 544 return btf_dumper_enum(d, t, data); 545 case BTF_KIND_PTR: 546 btf_dumper_ptr(d, t, data); 547 return 0; 548 case BTF_KIND_UNKN: 549 jsonw_printf(d->jw, "(unknown)"); 550 return 0; 551 case BTF_KIND_FWD: 552 /* map key or value can't be forward */ 553 jsonw_printf(d->jw, "(fwd-kind-invalid)"); 554 return -EINVAL; 555 case BTF_KIND_TYPEDEF: 556 case BTF_KIND_VOLATILE: 557 case BTF_KIND_CONST: 558 case BTF_KIND_RESTRICT: 559 return btf_dumper_modifier(d, type_id, bit_offset, data); 560 case BTF_KIND_VAR: 561 return btf_dumper_var(d, type_id, bit_offset, data); 562 case BTF_KIND_DATASEC: 563 return btf_dumper_datasec(d, type_id, data); 564 default: 565 jsonw_printf(d->jw, "(unsupported-kind"); 566 return -EINVAL; 567 } 568} 569 570int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, 571 const void *data) 572{ 573 return btf_dumper_do_type(d, type_id, 0, data); 574} 575 576#define BTF_PRINT_ARG(...) \ 577 do { \ 578 pos += snprintf(func_sig + pos, size - pos, \ 579 __VA_ARGS__); \ 580 if (pos >= size) \ 581 return -1; \ 582 } while (0) 583#define BTF_PRINT_TYPE(type) \ 584 do { \ 585 pos = __btf_dumper_type_only(btf, type, func_sig, \ 586 pos, size); \ 587 if (pos == -1) \ 588 return -1; \ 589 } while (0) 590 591static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id, 592 char *func_sig, int pos, int size) 593{ 594 const struct btf_type *proto_type; 595 const struct btf_array *array; 596 const struct btf_var *var; 597 const struct btf_type *t; 598 599 if (!type_id) { 600 BTF_PRINT_ARG("void "); 601 return pos; 602 } 603 604 t = btf__type_by_id(btf, type_id); 605 606 switch (BTF_INFO_KIND(t->info)) { 607 case BTF_KIND_INT: 608 case BTF_KIND_TYPEDEF: 609 case BTF_KIND_FLOAT: 610 BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off)); 611 break; 612 case BTF_KIND_STRUCT: 613 BTF_PRINT_ARG("struct %s ", 614 btf__name_by_offset(btf, t->name_off)); 615 break; 616 case BTF_KIND_UNION: 617 BTF_PRINT_ARG("union %s ", 618 btf__name_by_offset(btf, t->name_off)); 619 break; 620 case BTF_KIND_ENUM: 621 BTF_PRINT_ARG("enum %s ", 622 btf__name_by_offset(btf, t->name_off)); 623 break; 624 case BTF_KIND_ARRAY: 625 array = (struct btf_array *)(t + 1); 626 BTF_PRINT_TYPE(array->type); 627 BTF_PRINT_ARG("[%d]", array->nelems); 628 break; 629 case BTF_KIND_PTR: 630 BTF_PRINT_TYPE(t->type); 631 BTF_PRINT_ARG("* "); 632 break; 633 case BTF_KIND_FWD: 634 BTF_PRINT_ARG("%s %s ", 635 BTF_INFO_KFLAG(t->info) ? "union" : "struct", 636 btf__name_by_offset(btf, t->name_off)); 637 break; 638 case BTF_KIND_VOLATILE: 639 BTF_PRINT_ARG("volatile "); 640 BTF_PRINT_TYPE(t->type); 641 break; 642 case BTF_KIND_CONST: 643 BTF_PRINT_ARG("const "); 644 BTF_PRINT_TYPE(t->type); 645 break; 646 case BTF_KIND_RESTRICT: 647 BTF_PRINT_ARG("restrict "); 648 BTF_PRINT_TYPE(t->type); 649 break; 650 case BTF_KIND_FUNC_PROTO: 651 pos = btf_dump_func(btf, func_sig, t, NULL, pos, size); 652 if (pos == -1) 653 return -1; 654 break; 655 case BTF_KIND_FUNC: 656 proto_type = btf__type_by_id(btf, t->type); 657 pos = btf_dump_func(btf, func_sig, proto_type, t, pos, size); 658 if (pos == -1) 659 return -1; 660 break; 661 case BTF_KIND_VAR: 662 var = (struct btf_var *)(t + 1); 663 if (var->linkage == BTF_VAR_STATIC) 664 BTF_PRINT_ARG("static "); 665 BTF_PRINT_TYPE(t->type); 666 BTF_PRINT_ARG(" %s", 667 btf__name_by_offset(btf, t->name_off)); 668 break; 669 case BTF_KIND_DATASEC: 670 BTF_PRINT_ARG("section (\"%s\") ", 671 btf__name_by_offset(btf, t->name_off)); 672 break; 673 case BTF_KIND_UNKN: 674 default: 675 return -1; 676 } 677 678 return pos; 679} 680 681static int btf_dump_func(const struct btf *btf, char *func_sig, 682 const struct btf_type *func_proto, 683 const struct btf_type *func, int pos, int size) 684{ 685 int i, vlen; 686 687 BTF_PRINT_TYPE(func_proto->type); 688 if (func) 689 BTF_PRINT_ARG("%s(", btf__name_by_offset(btf, func->name_off)); 690 else 691 BTF_PRINT_ARG("("); 692 vlen = BTF_INFO_VLEN(func_proto->info); 693 for (i = 0; i < vlen; i++) { 694 struct btf_param *arg = &((struct btf_param *)(func_proto + 1))[i]; 695 696 if (i) 697 BTF_PRINT_ARG(", "); 698 if (arg->type) { 699 BTF_PRINT_TYPE(arg->type); 700 if (arg->name_off) 701 BTF_PRINT_ARG("%s", 702 btf__name_by_offset(btf, arg->name_off)); 703 else if (pos && func_sig[pos - 1] == ' ') 704 /* Remove unnecessary space for 705 * FUNC_PROTO that does not have 706 * arg->name_off 707 */ 708 func_sig[--pos] = '\0'; 709 } else { 710 BTF_PRINT_ARG("..."); 711 } 712 } 713 BTF_PRINT_ARG(")"); 714 715 return pos; 716} 717 718void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig, 719 int size) 720{ 721 int err; 722 723 func_sig[0] = '\0'; 724 if (!btf) 725 return; 726 727 err = __btf_dumper_type_only(btf, type_id, func_sig, 0, size); 728 if (err < 0) 729 func_sig[0] = '\0'; 730} 731 732static const char *ltrim(const char *s) 733{ 734 while (isspace(*s)) 735 s++; 736 737 return s; 738} 739 740void btf_dump_linfo_plain(const struct btf *btf, 741 const struct bpf_line_info *linfo, 742 const char *prefix, bool linum) 743{ 744 const char *line = btf__name_by_offset(btf, linfo->line_off); 745 746 if (!line) 747 return; 748 line = ltrim(line); 749 750 if (!prefix) 751 prefix = ""; 752 753 if (linum) { 754 const char *file = btf__name_by_offset(btf, linfo->file_name_off); 755 756 /* More forgiving on file because linum option is 757 * expected to provide more info than the already 758 * available src line. 759 */ 760 if (!file) 761 file = ""; 762 763 printf("%s%s [file:%s line_num:%u line_col:%u]\n", 764 prefix, line, file, 765 BPF_LINE_INFO_LINE_NUM(linfo->line_col), 766 BPF_LINE_INFO_LINE_COL(linfo->line_col)); 767 } else { 768 printf("%s%s\n", prefix, line); 769 } 770} 771 772void btf_dump_linfo_json(const struct btf *btf, 773 const struct bpf_line_info *linfo, bool linum) 774{ 775 const char *line = btf__name_by_offset(btf, linfo->line_off); 776 777 if (line) 778 jsonw_string_field(json_wtr, "src", ltrim(line)); 779 780 if (linum) { 781 const char *file = btf__name_by_offset(btf, linfo->file_name_off); 782 783 if (file) 784 jsonw_string_field(json_wtr, "file", file); 785 786 if (BPF_LINE_INFO_LINE_NUM(linfo->line_col)) 787 jsonw_int_field(json_wtr, "line_num", 788 BPF_LINE_INFO_LINE_NUM(linfo->line_col)); 789 790 if (BPF_LINE_INFO_LINE_COL(linfo->line_col)) 791 jsonw_int_field(json_wtr, "line_col", 792 BPF_LINE_INFO_LINE_COL(linfo->line_col)); 793 } 794}