aboutsummaryrefslogtreecommitdiffstats
path: root/tools/bpf/bpftool/btf.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/bpf/bpftool/btf.c')
-rw-r--r--tools/bpf/bpftool/btf.c162
1 files changed, 66 insertions, 96 deletions
diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
index 7317438ecd9e..1b8ec91899e6 100644
--- a/tools/bpf/bpftool/btf.c
+++ b/tools/bpf/bpftool/btf.c
@@ -8,8 +8,8 @@
8#include <stdio.h> 8#include <stdio.h>
9#include <string.h> 9#include <string.h>
10#include <unistd.h> 10#include <unistd.h>
11#include <gelf.h>
12#include <bpf.h> 11#include <bpf.h>
12#include <libbpf.h>
13#include <linux/btf.h> 13#include <linux/btf.h>
14 14
15#include "btf.h" 15#include "btf.h"
@@ -340,109 +340,40 @@ static int dump_btf_raw(const struct btf *btf,
340 return 0; 340 return 0;
341} 341}
342 342
343static bool check_btf_endianness(GElf_Ehdr *ehdr) 343static void __printf(2, 0) btf_dump_printf(void *ctx,
344 const char *fmt, va_list args)
344{ 345{
345 static unsigned int const endian = 1; 346 vfprintf(stdout, fmt, args);
346
347 switch (ehdr->e_ident[EI_DATA]) {
348 case ELFDATA2LSB:
349 return *(unsigned char const *)&endian == 1;
350 case ELFDATA2MSB:
351 return *(unsigned char const *)&endian == 0;
352 default:
353 return 0;
354 }
355} 347}
356 348
357static int btf_load_from_elf(const char *path, struct btf **btf) 349static int dump_btf_c(const struct btf *btf,
350 __u32 *root_type_ids, int root_type_cnt)
358{ 351{
359 int err = -1, fd = -1, idx = 0; 352 struct btf_dump *d;
360 Elf_Data *btf_data = NULL; 353 int err = 0, i;
361 Elf_Scn *scn = NULL;
362 Elf *elf = NULL;
363 GElf_Ehdr ehdr;
364
365 if (elf_version(EV_CURRENT) == EV_NONE) {
366 p_err("failed to init libelf for %s", path);
367 return -1;
368 }
369
370 fd = open(path, O_RDONLY);
371 if (fd < 0) {
372 p_err("failed to open %s: %s", path, strerror(errno));
373 return -1;
374 }
375
376 elf = elf_begin(fd, ELF_C_READ, NULL);
377 if (!elf) {
378 p_err("failed to open %s as ELF file", path);
379 goto done;
380 }
381 if (!gelf_getehdr(elf, &ehdr)) {
382 p_err("failed to get EHDR from %s", path);
383 goto done;
384 }
385 if (!check_btf_endianness(&ehdr)) {
386 p_err("non-native ELF endianness is not supported");
387 goto done;
388 }
389 if (!elf_rawdata(elf_getscn(elf, ehdr.e_shstrndx), NULL)) {
390 p_err("failed to get e_shstrndx from %s\n", path);
391 goto done;
392 }
393 354
394 while ((scn = elf_nextscn(elf, scn)) != NULL) { 355 d = btf_dump__new(btf, NULL, NULL, btf_dump_printf);
395 GElf_Shdr sh; 356 if (IS_ERR(d))
396 char *name; 357 return PTR_ERR(d);
397 358
398 idx++; 359 if (root_type_cnt) {
399 if (gelf_getshdr(scn, &sh) != &sh) { 360 for (i = 0; i < root_type_cnt; i++) {
400 p_err("failed to get section(%d) header from %s", 361 err = btf_dump__dump_type(d, root_type_ids[i]);
401 idx, path); 362 if (err)
402 goto done;
403 }
404 name = elf_strptr(elf, ehdr.e_shstrndx, sh.sh_name);
405 if (!name) {
406 p_err("failed to get section(%d) name from %s",
407 idx, path);
408 goto done;
409 }
410 if (strcmp(name, BTF_ELF_SEC) == 0) {
411 btf_data = elf_getdata(scn, 0);
412 if (!btf_data) {
413 p_err("failed to get section(%d, %s) data from %s",
414 idx, name, path);
415 goto done; 363 goto done;
416 }
417 break;
418 } 364 }
419 } 365 } else {
420 366 int cnt = btf__get_nr_types(btf);
421 if (!btf_data) {
422 p_err("%s ELF section not found in %s", BTF_ELF_SEC, path);
423 goto done;
424 }
425 367
426 *btf = btf__new(btf_data->d_buf, btf_data->d_size); 368 for (i = 1; i <= cnt; i++) {
427 if (IS_ERR(*btf)) { 369 err = btf_dump__dump_type(d, i);
428 err = PTR_ERR(*btf); 370 if (err)
429 *btf = NULL; 371 goto done;
430 p_err("failed to load BTF data from %s: %s", 372 }
431 path, strerror(err));
432 goto done;
433 } 373 }
434 374
435 err = 0;
436done: 375done:
437 if (err) { 376 btf_dump__free(d);
438 if (*btf) {
439 btf__free(*btf);
440 *btf = NULL;
441 }
442 }
443 if (elf)
444 elf_end(elf);
445 close(fd);
446 return err; 377 return err;
447} 378}
448 379
@@ -451,6 +382,7 @@ static int do_dump(int argc, char **argv)
451 struct btf *btf = NULL; 382 struct btf *btf = NULL;
452 __u32 root_type_ids[2]; 383 __u32 root_type_ids[2];
453 int root_type_cnt = 0; 384 int root_type_cnt = 0;
385 bool dump_c = false;
454 __u32 btf_id = -1; 386 __u32 btf_id = -1;
455 const char *src; 387 const char *src;
456 int fd = -1; 388 int fd = -1;
@@ -522,9 +454,14 @@ static int do_dump(int argc, char **argv)
522 } 454 }
523 NEXT_ARG(); 455 NEXT_ARG();
524 } else if (is_prefix(src, "file")) { 456 } else if (is_prefix(src, "file")) {
525 err = btf_load_from_elf(*argv, &btf); 457 btf = btf__parse_elf(*argv, NULL);
526 if (err) 458 if (IS_ERR(btf)) {
459 err = PTR_ERR(btf);
460 btf = NULL;
461 p_err("failed to load BTF from %s: %s",
462 *argv, strerror(err));
527 goto done; 463 goto done;
464 }
528 NEXT_ARG(); 465 NEXT_ARG();
529 } else { 466 } else {
530 err = -1; 467 err = -1;
@@ -532,6 +469,29 @@ static int do_dump(int argc, char **argv)
532 goto done; 469 goto done;
533 } 470 }
534 471
472 while (argc) {
473 if (is_prefix(*argv, "format")) {
474 NEXT_ARG();
475 if (argc < 1) {
476 p_err("expecting value for 'format' option\n");
477 goto done;
478 }
479 if (strcmp(*argv, "c") == 0) {
480 dump_c = true;
481 } else if (strcmp(*argv, "raw") == 0) {
482 dump_c = false;
483 } else {
484 p_err("unrecognized format specifier: '%s', possible values: raw, c",
485 *argv);
486 goto done;
487 }
488 NEXT_ARG();
489 } else {
490 p_err("unrecognized option: '%s'", *argv);
491 goto done;
492 }
493 }
494
535 if (!btf) { 495 if (!btf) {
536 err = btf__get_from_id(btf_id, &btf); 496 err = btf__get_from_id(btf_id, &btf);
537 if (err) { 497 if (err) {
@@ -545,7 +505,16 @@ static int do_dump(int argc, char **argv)
545 } 505 }
546 } 506 }
547 507
548 dump_btf_raw(btf, root_type_ids, root_type_cnt); 508 if (dump_c) {
509 if (json_output) {
510 p_err("JSON output for C-syntax dump is not supported");
511 err = -ENOTSUP;
512 goto done;
513 }
514 err = dump_btf_c(btf, root_type_ids, root_type_cnt);
515 } else {
516 err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
517 }
549 518
550done: 519done:
551 close(fd); 520 close(fd);
@@ -561,10 +530,11 @@ static int do_help(int argc, char **argv)
561 } 530 }
562 531
563 fprintf(stderr, 532 fprintf(stderr,
564 "Usage: %s btf dump BTF_SRC\n" 533 "Usage: %s btf dump BTF_SRC [format FORMAT]\n"
565 " %s btf help\n" 534 " %s btf help\n"
566 "\n" 535 "\n"
567 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n" 536 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
537 " FORMAT := { raw | c }\n"
568 " " HELP_SPEC_MAP "\n" 538 " " HELP_SPEC_MAP "\n"
569 " " HELP_SPEC_PROGRAM "\n" 539 " " HELP_SPEC_PROGRAM "\n"
570 " " HELP_SPEC_OPTIONS "\n" 540 " " HELP_SPEC_OPTIONS "\n"