[RFC PATCH] bpftool btf: Add prefix option to dump C

From: Ian Rogers
Date: Wed Jul 22 2020 - 01:43:28 EST


When bpftool dumps types and enum members into a header file for
inclusion the names match those in the original source. If the same
header file needs to be included in the original source and the bpf
program, the names of structs, unions, typedefs and enum members will
have naming collisions.

To avoid these collisions an approach is to redeclare the header file
types and enum members, which leads to duplication and possible
inconsistencies. Another approach is to use preprocessor macros
to rename conflicting names, but this can be cumbersome if there are
many conflicts.

This patch adds a prefix option for the dumped names. Use of this option
can avoid name conflicts and compile time errors.

Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
---
.../bpf/bpftool/Documentation/bpftool-btf.rst | 7 ++++++-
tools/bpf/bpftool/btf.c | 18 ++++++++++++++---
tools/lib/bpf/btf.h | 1 +
tools/lib/bpf/btf_dump.c | 20 +++++++++++++------
4 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-btf.rst b/tools/bpf/bpftool/Documentation/bpftool-btf.rst
index 896f4c6c2870..85d66bc69634 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-btf.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-btf.rst
@@ -20,7 +20,7 @@ BTF COMMANDS
=============

| **bpftool** **btf** { **show** | **list** } [**id** *BTF_ID*]
-| **bpftool** **btf dump** *BTF_SRC* [**format** *FORMAT*]
+| **bpftool** **btf dump** *BTF_SRC* [**format** *FORMAT*] [**prefix** *PREFIX*]
| **bpftool** **btf help**
|
| *BTF_SRC* := { **id** *BTF_ID* | **prog** *PROG* | **map** *MAP* [{**key** | **value** | **kv** | **all**}] | **file** *FILE* }
@@ -66,6 +66,11 @@ DESCRIPTION
output format. Raw (**raw**) or C-syntax (**c**) output
formats are supported.

+ With the C-syntax format the **prefix** option can
+ be used to prefix all identifiers and enum members
+ with *PREFIX*. This is useful to avoid naming
+ collisions.
+
**bpftool btf help**
Print short help message.

diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
index fc9bc7a23db6..6a428636fa6f 100644
--- a/tools/bpf/bpftool/btf.c
+++ b/tools/bpf/bpftool/btf.c
@@ -379,12 +379,15 @@ static void __printf(2, 0) btf_dump_printf(void *ctx,
}

static int dump_btf_c(const struct btf *btf,
- __u32 *root_type_ids, int root_type_cnt)
+ __u32 *root_type_ids, int root_type_cnt, const char *name_prefix)
{
struct btf_dump *d;
int err = 0, i;
+ struct btf_dump_opts opts = {
+ .name_prefix = name_prefix,
+ };

- d = btf_dump__new(btf, NULL, NULL, btf_dump_printf);
+ d = btf_dump__new(btf, NULL, &opts, btf_dump_printf);
if (IS_ERR(d))
return PTR_ERR(d);

@@ -478,6 +481,7 @@ static int do_dump(int argc, char **argv)
bool dump_c = false;
__u32 btf_id = -1;
const char *src;
+ const char *c_prefix = NULL;
int fd = -1;
int err;

@@ -583,6 +587,14 @@ static int do_dump(int argc, char **argv)
goto done;
}
NEXT_ARG();
+ } else if (is_prefix(*argv, "prefix")) {
+ NEXT_ARG();
+ if (argc < 1 || !*argv) {
+ p_err("expecting value for 'prefix' option\n");
+ goto done;
+ }
+ c_prefix = *argv;
+ NEXT_ARG();
} else {
p_err("unrecognized option: '%s'", *argv);
goto done;
@@ -608,7 +620,7 @@ static int do_dump(int argc, char **argv)
err = -ENOTSUP;
goto done;
}
- err = dump_btf_c(btf, root_type_ids, root_type_cnt);
+ err = dump_btf_c(btf, root_type_ids, root_type_cnt, c_prefix);
} else {
err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
}
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index 491c7b41ffdc..fea4baab00bd 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -117,6 +117,7 @@ struct btf_dump;

struct btf_dump_opts {
void *ctx;
+ const char *name_prefix;
};

typedef void (*btf_dump_printf_fn_t)(void *ctx, const char *fmt, va_list args);
diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
index e1c344504cae..baf2b4d82e1e 100644
--- a/tools/lib/bpf/btf_dump.c
+++ b/tools/lib/bpf/btf_dump.c
@@ -138,6 +138,7 @@ struct btf_dump *btf_dump__new(const struct btf *btf,
d->btf_ext = btf_ext;
d->printf_fn = printf_fn;
d->opts.ctx = opts ? opts->ctx : NULL;
+ d->opts.name_prefix = opts ? opts->name_prefix : NULL;

d->type_names = hashmap__new(str_hash_fn, str_equal_fn, NULL);
if (IS_ERR(d->type_names)) {
@@ -903,6 +904,7 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
const struct btf_enum *v = btf_enum(t);
__u16 vlen = btf_vlen(t);
const char *name;
+ const char *name_prefix = d->opts.name_prefix;
size_t dup_cnt;
int i;

@@ -912,17 +914,19 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,

if (vlen) {
btf_dump_printf(d, " {");
+ if (!name_prefix)
+ name_prefix = "";
for (i = 0; i < vlen; i++, v++) {
name = btf_name_of(d, v->name_off);
/* enumerators share namespace with typedef idents */
dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
if (dup_cnt > 1) {
- btf_dump_printf(d, "\n%s%s___%zu = %u,",
- pfx(lvl + 1), name, dup_cnt,
+ btf_dump_printf(d, "\n%s%s%s___%zu = %u,",
+ pfx(lvl + 1), name_prefix, name, dup_cnt,
(__u32)v->val);
} else {
- btf_dump_printf(d, "\n%s%s = %u,",
- pfx(lvl + 1), name,
+ btf_dump_printf(d, "\n%s%s%s = %u,",
+ pfx(lvl + 1), name_prefix, name,
(__u32)v->val);
}
}
@@ -1360,6 +1364,7 @@ static const char *btf_dump_resolve_name(struct btf_dump *d, __u32 id,
const struct btf_type *t = btf__type_by_id(d->btf, id);
const char *orig_name = btf_name_of(d, t->name_off);
const char **cached_name = &d->cached_names[id];
+ const char *prefix = d->opts.name_prefix;
size_t dup_cnt;

if (t->name_off == 0)
@@ -1369,11 +1374,14 @@ static const char *btf_dump_resolve_name(struct btf_dump *d, __u32 id,
return *cached_name ? *cached_name : orig_name;

dup_cnt = btf_dump_name_dups(d, name_map, orig_name);
- if (dup_cnt > 1) {
+ if (dup_cnt > 1 || prefix) {
const size_t max_len = 256;
char new_name[max_len];

- snprintf(new_name, max_len, "%s___%zu", orig_name, dup_cnt);
+ if (dup_cnt > 1)
+ snprintf(new_name, max_len, "%s%s___%zu", prefix, orig_name, dup_cnt);
+ else
+ snprintf(new_name, max_len, "%s%s", prefix, orig_name);
*cached_name = strdup(new_name);
}

--
2.28.0.rc0.105.gf9edc3c819-goog