diff options
Diffstat (limited to 'tools/bpf/bpftool/btf.c')
-rw-r--r-- | tools/bpf/bpftool/btf.c | 162 |
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 | ||
343 | static bool check_btf_endianness(GElf_Ehdr *ehdr) | 343 | static 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 | ||
357 | static int btf_load_from_elf(const char *path, struct btf **btf) | 349 | static 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; | ||
436 | done: | 375 | done: |
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 | ||
550 | done: | 519 | done: |
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" |