libbpf: Expose BTF-to-C type declaration emitting API
authorAndrii Nakryiko <andriin@fb.com>
Sat, 14 Dec 2019 01:43:31 +0000 (17:43 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Sun, 15 Dec 2019 23:58:05 +0000 (15:58 -0800)
Expose API that allows to emit type declaration and field/variable definition
(if optional field name is specified) in valid C syntax for any provided BTF
type. This is going to be used by bpftool when emitting data section layout as
a struct. As part of making this API useful in a stand-alone fashion, move
initialization of some of the internal btf_dump state to earlier phase.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/bpf/20191214014341.3442258-8-andriin@fb.com
tools/lib/bpf/btf.h
tools/lib/bpf/btf_dump.c
tools/lib/bpf/libbpf.map

index a114c8e..8d73f7f 100644 (file)
@@ -126,6 +126,28 @@ LIBBPF_API void btf_dump__free(struct btf_dump *d);
 
 LIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);
 
+struct btf_dump_emit_type_decl_opts {
+       /* size of this struct, for forward/backward compatiblity */
+       size_t sz;
+       /* optional field name for type declaration, e.g.:
+        * - struct my_struct <FNAME>
+        * - void (*<FNAME>)(int)
+        * - char (*<FNAME>)[123]
+        */
+       const char *field_name;
+       /* extra indentation level (in number of tabs) to emit for multi-line
+        * type declarations (e.g., anonymous struct); applies for lines
+        * starting from the second one (first line is assumed to have
+        * necessary indentation already
+        */
+       int indent_level;
+};
+#define btf_dump_emit_type_decl_opts__last_field indent_level
+
+LIBBPF_API int
+btf_dump__emit_type_decl(struct btf_dump *d, __u32 id,
+                        const struct btf_dump_emit_type_decl_opts *opts);
+
 /*
  * A set of helpers for easier BTF types handling
  */
index 5339302..e95f771 100644 (file)
@@ -116,6 +116,8 @@ static void btf_dump_printf(const struct btf_dump *d, const char *fmt, ...)
        va_end(args);
 }
 
+static int btf_dump_mark_referenced(struct btf_dump *d);
+
 struct btf_dump *btf_dump__new(const struct btf *btf,
                               const struct btf_ext *btf_ext,
                               const struct btf_dump_opts *opts,
@@ -137,18 +139,39 @@ struct btf_dump *btf_dump__new(const struct btf *btf,
        if (IS_ERR(d->type_names)) {
                err = PTR_ERR(d->type_names);
                d->type_names = NULL;
-               btf_dump__free(d);
-               return ERR_PTR(err);
        }
        d->ident_names = hashmap__new(str_hash_fn, str_equal_fn, NULL);
        if (IS_ERR(d->ident_names)) {
                err = PTR_ERR(d->ident_names);
                d->ident_names = NULL;
-               btf_dump__free(d);
-               return ERR_PTR(err);
+               goto err;
+       }
+       d->type_states = calloc(1 + btf__get_nr_types(d->btf),
+                               sizeof(d->type_states[0]));
+       if (!d->type_states) {
+               err = -ENOMEM;
+               goto err;
+       }
+       d->cached_names = calloc(1 + btf__get_nr_types(d->btf),
+                                sizeof(d->cached_names[0]));
+       if (!d->cached_names) {
+               err = -ENOMEM;
+               goto err;
        }
 
+       /* VOID is special */
+       d->type_states[0].order_state = ORDERED;
+       d->type_states[0].emit_state = EMITTED;
+
+       /* eagerly determine referenced types for anon enums */
+       err = btf_dump_mark_referenced(d);
+       if (err)
+               goto err;
+
        return d;
+err:
+       btf_dump__free(d);
+       return ERR_PTR(err);
 }
 
 void btf_dump__free(struct btf_dump *d)
@@ -175,7 +198,6 @@ void btf_dump__free(struct btf_dump *d)
        free(d);
 }
 
-static int btf_dump_mark_referenced(struct btf_dump *d);
 static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr);
 static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id);
 
@@ -202,27 +224,6 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
        if (id > btf__get_nr_types(d->btf))
                return -EINVAL;
 
-       /* type states are lazily allocated, as they might not be needed */
-       if (!d->type_states) {
-               d->type_states = calloc(1 + btf__get_nr_types(d->btf),
-                                       sizeof(d->type_states[0]));
-               if (!d->type_states)
-                       return -ENOMEM;
-               d->cached_names = calloc(1 + btf__get_nr_types(d->btf),
-                                        sizeof(d->cached_names[0]));
-               if (!d->cached_names)
-                       return -ENOMEM;
-
-               /* VOID is special */
-               d->type_states[0].order_state = ORDERED;
-               d->type_states[0].emit_state = EMITTED;
-
-               /* eagerly determine referenced types for anon enums */
-               err = btf_dump_mark_referenced(d);
-               if (err)
-                       return err;
-       }
-
        d->emit_queue_cnt = 0;
        err = btf_dump_order_type(d, id, false);
        if (err < 0)
@@ -1016,6 +1017,21 @@ static int btf_dump_push_decl_stack_id(struct btf_dump *d, __u32 id)
  * of a stack frame. Some care is required to "pop" stack frames after
  * processing type declaration chain.
  */
+int btf_dump__emit_type_decl(struct btf_dump *d, __u32 id,
+                            const struct btf_dump_emit_type_decl_opts *opts)
+{
+       const char *fname;
+       int lvl;
+
+       if (!OPTS_VALID(opts, btf_dump_emit_type_decl_opts))
+               return -EINVAL;
+
+       fname = OPTS_GET(opts, field_name, NULL);
+       lvl = OPTS_GET(opts, indent_level, 0);
+       btf_dump_emit_type_decl(d, id, fname, lvl);
+       return 0;
+}
+
 static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
                                    const char *fname, int lvl)
 {
index e7fcca3..990c7c0 100644 (file)
@@ -211,6 +211,7 @@ LIBBPF_0.0.6 {
 
 LIBBPF_0.0.7 {
        global:
+               btf_dump__emit_type_decl;
                bpf_program__attach;
                btf__align_of;
 } LIBBPF_0.0.6;