Skip to content

Commit 5420f32

Browse files
author
Alexei Starovoitov
committed
Merge branch 'btf2c-converter'
Andrii Nakryiko says: ==================== This patch set adds BTF-to-C dumping APIs to libbpf, allowing to output a subset of BTF types as a compilable C type definitions. This is useful by itself, as raw BTF output is not easy to inspect and comprehend. But it's also a big part of BPF CO-RE (compile once - run everywhere) initiative aimed at allowing to write relocatable BPF programs, that won't require on-the-host kernel headers (and would be able to inspect internal kernel structures, not exposed through kernel headers). This patch set consists of three groups of patches and one pre-patch, with the BTF-to-C dumper API depending on the first two groups. Pre-patch #1 fixes issue with libbpf_internal.h. btf__parse_elf() API patches: - patch #2 adds btf__parse_elf() API to libbpf, allowing to load BTF and/or BTF.ext from ELF file; - patch #3 utilizies btf__parse_elf() from bpftool for `btf dump file` command; - patch #4 switches test_btf.c to use btf__parse_elf() to check for presence of BTF data in object file. libbpf's internal hashmap patches: - patch #5 adds resizeable non-thread safe generic hashmap to libbpf; - patch #6 adds tests for that hashmap; - patch #7 migrates btf_dedup()'s dedup_table to use hashmap w/ APPEND. BTF-to-C dumper API patches: - patch #8 adds btf_dump APIs with all the logic for laying out type definitions in correct order and emitting C syntax for them; - patch #9 adds lots of tests for common and quirky parts of C type system; - patch #10 adds support for C-syntax btf dumping to bpftool; - patch #11 updates bpftool documentation to mention C-syntax dump option; - patch #12 update bash-completion for btf dump sub-command. v2->v3: - fix bpftool-btf.rst formatting (Quentin); - simplify bash autocompletion script (Quentin); - better error message in btf dump (Quentin); v1->v2: - removed unuseful file header (Jakub); - removed inlines in .c (Jakub); - added 'format {c|raw}' keyword/option (Jakub); - re-use i var for iteration in btf_dump_c() (Jakub); - bumped libbpf version to 0.0.4; v0->v1: - fix bug in hashmap__for_each_bucket_entry() not handling empty hashmap; - removed `btf dump`-specific libbpf logging hook up (Quentin has more generic patchset); - change btf__parse_elf() to always load .BTF and return it as a result, with .BTF.ext being optional and returned through struct btf_ext** arg (Alexei); - endianness check to use __BYTE_ORDER__ (Alexei); - bool:1 to __u8:1 in type_aux_state (Alexei); - added HASHMAP_APPEND strategy to hashmap, changed hashmap__for_each_key_entry() to also check for key equality during iteration (multimap iteration for key); - added new tests for empty hashmap and hashmap as a multimap; - tried to clarify weak/strong dependency ordering comments (Alexei) - btf dump test's expected output - support better commenting aproach (Alexei); - added bash-completion for a new "c" option (Alexei). ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents c87f60a + 90eea40 commit 5420f32

23 files changed

+3306
-291
lines changed

tools/bpf/bpftool/Documentation/bpftool-btf.rst

+20-15
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ SYNOPSIS
1919
BTF COMMANDS
2020
=============
2121

22-
| **bpftool** **btf dump** *BTF_SRC*
22+
| **bpftool** **btf dump** *BTF_SRC* [**format** *FORMAT*]
2323
| **bpftool** **btf help**
2424
|
2525
| *BTF_SRC* := { **id** *BTF_ID* | **prog** *PROG* | **map** *MAP* [{**key** | **value** | **kv** | **all**}] | **file** *FILE* }
26+
| *FORMAT* := { **raw** | **c** }
2627
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
2728
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
2829
@@ -31,23 +32,27 @@ DESCRIPTION
3132
**bpftool btf dump** *BTF_SRC*
3233
Dump BTF entries from a given *BTF_SRC*.
3334

34-
When **id** is specified, BTF object with that ID will be
35-
loaded and all its BTF types emitted.
35+
When **id** is specified, BTF object with that ID will be
36+
loaded and all its BTF types emitted.
3637

37-
When **map** is provided, it's expected that map has
38-
associated BTF object with BTF types describing key and
39-
value. It's possible to select whether to dump only BTF
40-
type(s) associated with key (**key**), value (**value**),
41-
both key and value (**kv**), or all BTF types present in
42-
associated BTF object (**all**). If not specified, **kv**
43-
is assumed.
38+
When **map** is provided, it's expected that map has
39+
associated BTF object with BTF types describing key and
40+
value. It's possible to select whether to dump only BTF
41+
type(s) associated with key (**key**), value (**value**),
42+
both key and value (**kv**), or all BTF types present in
43+
associated BTF object (**all**). If not specified, **kv**
44+
is assumed.
4445

45-
When **prog** is provided, it's expected that program has
46-
associated BTF object with BTF types.
46+
When **prog** is provided, it's expected that program has
47+
associated BTF object with BTF types.
4748

48-
When specifying *FILE*, an ELF file is expected, containing
49-
.BTF section with well-defined BTF binary format data,
50-
typically produced by clang or pahole.
49+
When specifying *FILE*, an ELF file is expected, containing
50+
.BTF section with well-defined BTF binary format data,
51+
typically produced by clang or pahole.
52+
53+
**format** option can be used to override default (raw)
54+
output format. Raw (**raw**) or C-syntax (**c**) output
55+
formats are supported.
5156

5257
**bpftool btf help**
5358
Print short help message.

tools/bpf/bpftool/bash-completion/bpftool

+17-4
Original file line numberDiff line numberDiff line change
@@ -638,11 +638,24 @@ _bpftool()
638638
esac
639639
return 0
640640
;;
641+
format)
642+
COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
643+
;;
641644
*)
642-
if [[ $cword == 6 ]] && [[ ${words[3]} == "map" ]]; then
643-
COMPREPLY+=( $( compgen -W 'key value kv all' -- \
644-
"$cur" ) )
645-
fi
645+
# emit extra options
646+
case ${words[3]} in
647+
id|file)
648+
_bpftool_once_attr 'format'
649+
;;
650+
map|prog)
651+
if [[ ${words[3]} == "map" ]] && [[ $cword == 6 ]]; then
652+
COMPREPLY+=( $( compgen -W "key value kv all" -- "$cur" ) )
653+
fi
654+
_bpftool_once_attr 'format'
655+
;;
656+
*)
657+
;;
658+
esac
646659
return 0
647660
;;
648661
esac

tools/bpf/bpftool/btf.c

+66-96
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#include <stdio.h>
99
#include <string.h>
1010
#include <unistd.h>
11-
#include <gelf.h>
1211
#include <bpf.h>
12+
#include <libbpf.h>
1313
#include <linux/btf.h>
1414

1515
#include "btf.h"
@@ -340,109 +340,40 @@ static int dump_btf_raw(const struct btf *btf,
340340
return 0;
341341
}
342342

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)
344345
{
345-
static unsigned int const endian = 1;
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-
}
346+
vfprintf(stdout, fmt, args);
355347
}
356348

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)
358351
{
359-
int err = -1, fd = -1, idx = 0;
360-
Elf_Data *btf_data = NULL;
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-
}
352+
struct btf_dump *d;
353+
int err = 0, i;
393354

394-
while ((scn = elf_nextscn(elf, scn)) != NULL) {
395-
GElf_Shdr sh;
396-
char *name;
355+
d = btf_dump__new(btf, NULL, NULL, btf_dump_printf);
356+
if (IS_ERR(d))
357+
return PTR_ERR(d);
397358

398-
idx++;
399-
if (gelf_getshdr(scn, &sh) != &sh) {
400-
p_err("failed to get section(%d) header from %s",
401-
idx, path);
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);
359+
if (root_type_cnt) {
360+
for (i = 0; i < root_type_cnt; i++) {
361+
err = btf_dump__dump_type(d, root_type_ids[i]);
362+
if (err)
415363
goto done;
416-
}
417-
break;
418364
}
419-
}
420-
421-
if (!btf_data) {
422-
p_err("%s ELF section not found in %s", BTF_ELF_SEC, path);
423-
goto done;
424-
}
365+
} else {
366+
int cnt = btf__get_nr_types(btf);
425367

426-
*btf = btf__new(btf_data->d_buf, btf_data->d_size);
427-
if (IS_ERR(*btf)) {
428-
err = PTR_ERR(*btf);
429-
*btf = NULL;
430-
p_err("failed to load BTF data from %s: %s",
431-
path, strerror(err));
432-
goto done;
368+
for (i = 1; i <= cnt; i++) {
369+
err = btf_dump__dump_type(d, i);
370+
if (err)
371+
goto done;
372+
}
433373
}
434374

435-
err = 0;
436375
done:
437-
if (err) {
438-
if (*btf) {
439-
btf__free(*btf);
440-
*btf = NULL;
441-
}
442-
}
443-
if (elf)
444-
elf_end(elf);
445-
close(fd);
376+
btf_dump__free(d);
446377
return err;
447378
}
448379

@@ -451,6 +382,7 @@ static int do_dump(int argc, char **argv)
451382
struct btf *btf = NULL;
452383
__u32 root_type_ids[2];
453384
int root_type_cnt = 0;
385+
bool dump_c = false;
454386
__u32 btf_id = -1;
455387
const char *src;
456388
int fd = -1;
@@ -522,16 +454,44 @@ static int do_dump(int argc, char **argv)
522454
}
523455
NEXT_ARG();
524456
} else if (is_prefix(src, "file")) {
525-
err = btf_load_from_elf(*argv, &btf);
526-
if (err)
457+
btf = btf__parse_elf(*argv, NULL);
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));
527463
goto done;
464+
}
528465
NEXT_ARG();
529466
} else {
530467
err = -1;
531468
p_err("unrecognized BTF source specifier: '%s'", src);
532469
goto done;
533470
}
534471

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+
535495
if (!btf) {
536496
err = btf__get_from_id(btf_id, &btf);
537497
if (err) {
@@ -545,7 +505,16 @@ static int do_dump(int argc, char **argv)
545505
}
546506
}
547507

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+
}
549518

550519
done:
551520
close(fd);
@@ -561,10 +530,11 @@ static int do_help(int argc, char **argv)
561530
}
562531

563532
fprintf(stderr,
564-
"Usage: %s btf dump BTF_SRC\n"
533+
"Usage: %s btf dump BTF_SRC [format FORMAT]\n"
565534
" %s btf help\n"
566535
"\n"
567536
" BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
537+
" FORMAT := { raw | c }\n"
568538
" " HELP_SPEC_MAP "\n"
569539
" " HELP_SPEC_PROGRAM "\n"
570540
" " HELP_SPEC_OPTIONS "\n"

tools/lib/bpf/Build

+3-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o bpf_prog_linfo.o libbpf_probes.o xsk.o
1+
libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \
2+
netlink.o bpf_prog_linfo.o libbpf_probes.o xsk.o hashmap.o \
3+
btf_dump.o

0 commit comments

Comments
 (0)