]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - tools/lib/bpf/btf_dump.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
[linux.git] / tools / lib / bpf / btf_dump.c
index 7065bb5b2752513f29dcac4b4c5e7c0d0dd1454a..ede55fec36184e5a8d83dcb4dd6932e632a5839c 100644 (file)
@@ -48,6 +48,8 @@ struct btf_dump_type_aux_state {
        __u8 fwd_emitted: 1;
        /* whether unique non-duplicate name was already assigned */
        __u8 name_resolved: 1;
+       /* whether type is referenced from any other type */
+       __u8 referenced: 1;
 };
 
 struct btf_dump {
@@ -100,21 +102,6 @@ static bool str_equal_fn(const void *a, const void *b, void *ctx)
        return strcmp(a, b) == 0;
 }
 
-static __u16 btf_kind_of(const struct btf_type *t)
-{
-       return BTF_INFO_KIND(t->info);
-}
-
-static __u16 btf_vlen_of(const struct btf_type *t)
-{
-       return BTF_INFO_VLEN(t->info);
-}
-
-static bool btf_kflag_of(const struct btf_type *t)
-{
-       return BTF_INFO_KFLAG(t->info);
-}
-
 static const char *btf_name_of(const struct btf_dump *d, __u32 name_off)
 {
        return btf__name_by_offset(d->btf, name_off);
@@ -188,6 +175,7 @@ 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);
 
@@ -228,6 +216,11 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
                /* 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;
@@ -241,6 +234,79 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
        return 0;
 }
 
+/*
+ * Mark all types that are referenced from any other type. This is used to
+ * determine top-level anonymous enums that need to be emitted as an
+ * independent type declarations.
+ * Anonymous enums come in two flavors: either embedded in a struct's field
+ * definition, in which case they have to be declared inline as part of field
+ * type declaration; or as a top-level anonymous enum, typically used for
+ * declaring global constants. It's impossible to distinguish between two
+ * without knowning whether given enum type was referenced from other type:
+ * top-level anonymous enum won't be referenced by anything, while embedded
+ * one will.
+ */
+static int btf_dump_mark_referenced(struct btf_dump *d)
+{
+       int i, j, n = btf__get_nr_types(d->btf);
+       const struct btf_type *t;
+       __u16 vlen;
+
+       for (i = 1; i <= n; i++) {
+               t = btf__type_by_id(d->btf, i);
+               vlen = btf_vlen(t);
+
+               switch (btf_kind(t)) {
+               case BTF_KIND_INT:
+               case BTF_KIND_ENUM:
+               case BTF_KIND_FWD:
+                       break;
+
+               case BTF_KIND_VOLATILE:
+               case BTF_KIND_CONST:
+               case BTF_KIND_RESTRICT:
+               case BTF_KIND_PTR:
+               case BTF_KIND_TYPEDEF:
+               case BTF_KIND_FUNC:
+               case BTF_KIND_VAR:
+                       d->type_states[t->type].referenced = 1;
+                       break;
+
+               case BTF_KIND_ARRAY: {
+                       const struct btf_array *a = btf_array(t);
+
+                       d->type_states[a->index_type].referenced = 1;
+                       d->type_states[a->type].referenced = 1;
+                       break;
+               }
+               case BTF_KIND_STRUCT:
+               case BTF_KIND_UNION: {
+                       const struct btf_member *m = btf_members(t);
+
+                       for (j = 0; j < vlen; j++, m++)
+                               d->type_states[m->type].referenced = 1;
+                       break;
+               }
+               case BTF_KIND_FUNC_PROTO: {
+                       const struct btf_param *p = btf_params(t);
+
+                       for (j = 0; j < vlen; j++, p++)
+                               d->type_states[p->type].referenced = 1;
+                       break;
+               }
+               case BTF_KIND_DATASEC: {
+                       const struct btf_var_secinfo *v = btf_var_secinfos(t);
+
+                       for (j = 0; j < vlen; j++, v++)
+                               d->type_states[v->type].referenced = 1;
+                       break;
+               }
+               default:
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
 static int btf_dump_add_emit_queue_id(struct btf_dump *d, __u32 id)
 {
        __u32 *new_queue;
@@ -349,7 +415,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
         */
        struct btf_dump_type_aux_state *tstate = &d->type_states[id];
        const struct btf_type *t;
-       __u16 kind, vlen;
+       __u16 vlen;
        int err, i;
 
        /* return true, letting typedefs know that it's ok to be emitted */
@@ -357,18 +423,16 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
                return 1;
 
        t = btf__type_by_id(d->btf, id);
-       kind = btf_kind_of(t);
 
        if (tstate->order_state == ORDERING) {
                /* type loop, but resolvable through fwd declaration */
-               if ((kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION) &&
-                   through_ptr && t->name_off != 0)
+               if (btf_is_composite(t) && through_ptr && t->name_off != 0)
                        return 0;
                pr_warning("unsatisfiable type cycle, id:[%u]\n", id);
                return -ELOOP;
        }
 
-       switch (kind) {
+       switch (btf_kind(t)) {
        case BTF_KIND_INT:
                tstate->order_state = ORDERED;
                return 0;
@@ -378,14 +442,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
                tstate->order_state = ORDERED;
                return err;
 
-       case BTF_KIND_ARRAY: {
-               const struct btf_array *a = (void *)(t + 1);
+       case BTF_KIND_ARRAY:
+               return btf_dump_order_type(d, btf_array(t)->type, through_ptr);
 
-               return btf_dump_order_type(d, a->type, through_ptr);
-       }
        case BTF_KIND_STRUCT:
        case BTF_KIND_UNION: {
-               const struct btf_member *m = (void *)(t + 1);
+               const struct btf_member *m = btf_members(t);
                /*
                 * struct/union is part of strong link, only if it's embedded
                 * (so no ptr in a path) or it's anonymous (so has to be
@@ -396,7 +458,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
 
                tstate->order_state = ORDERING;
 
-               vlen = btf_vlen_of(t);
+               vlen = btf_vlen(t);
                for (i = 0; i < vlen; i++, m++) {
                        err = btf_dump_order_type(d, m->type, false);
                        if (err < 0)
@@ -414,7 +476,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
        }
        case BTF_KIND_ENUM:
        case BTF_KIND_FWD:
-               if (t->name_off != 0) {
+               /*
+                * non-anonymous or non-referenced enums are top-level
+                * declarations and should be emitted. Same logic can be
+                * applied to FWDs, it won't hurt anyways.
+                */
+               if (t->name_off != 0 || !tstate->referenced) {
                        err = btf_dump_add_emit_queue_id(d, id);
                        if (err)
                                return err;
@@ -447,7 +514,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
                return btf_dump_order_type(d, t->type, through_ptr);
 
        case BTF_KIND_FUNC_PROTO: {
-               const struct btf_param *p = (void *)(t + 1);
+               const struct btf_param *p = btf_params(t);
                bool is_strong;
 
                err = btf_dump_order_type(d, t->type, through_ptr);
@@ -455,7 +522,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
                        return err;
                is_strong = err > 0;
 
-               vlen = btf_vlen_of(t);
+               vlen = btf_vlen(t);
                for (i = 0; i < vlen; i++, p++) {
                        err = btf_dump_order_type(d, p->type, through_ptr);
                        if (err < 0)
@@ -553,12 +620,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
                return;
 
        t = btf__type_by_id(d->btf, id);
-       kind = btf_kind_of(t);
-
-       if (top_level_def && t->name_off == 0) {
-               pr_warning("unexpected nameless definition, id:[%u]\n", id);
-               return;
-       }
+       kind = btf_kind(t);
 
        if (tstate->emit_state == EMITTING) {
                if (tstate->fwd_emitted)
@@ -618,12 +680,9 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
        case BTF_KIND_RESTRICT:
                btf_dump_emit_type(d, t->type, cont_id);
                break;
-       case BTF_KIND_ARRAY: {
-               const struct btf_array *a = (void *)(t + 1);
-
-               btf_dump_emit_type(d, a->type, cont_id);
+       case BTF_KIND_ARRAY:
+               btf_dump_emit_type(d, btf_array(t)->type, cont_id);
                break;
-       }
        case BTF_KIND_FWD:
                btf_dump_emit_fwd_def(d, id, t);
                btf_dump_printf(d, ";\n\n");
@@ -656,8 +715,8 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
                 * applicable
                 */
                if (top_level_def || t->name_off == 0) {
-                       const struct btf_member *m = (void *)(t + 1);
-                       __u16 vlen = btf_vlen_of(t);
+                       const struct btf_member *m = btf_members(t);
+                       __u16 vlen = btf_vlen(t);
                        int i, new_cont_id;
 
                        new_cont_id = t->name_off == 0 ? cont_id : id;
@@ -678,8 +737,8 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
                }
                break;
        case BTF_KIND_FUNC_PROTO: {
-               const struct btf_param *p = (void *)(t + 1);
-               __u16 vlen = btf_vlen_of(t);
+               const struct btf_param *p = btf_params(t);
+               __u16 vlen = btf_vlen(t);
                int i;
 
                btf_dump_emit_type(d, t->type, cont_id);
@@ -696,7 +755,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
 static int btf_align_of(const struct btf *btf, __u32 id)
 {
        const struct btf_type *t = btf__type_by_id(btf, id);
-       __u16 kind = btf_kind_of(t);
+       __u16 kind = btf_kind(t);
 
        switch (kind) {
        case BTF_KIND_INT:
@@ -709,15 +768,12 @@ static int btf_align_of(const struct btf *btf, __u32 id)
        case BTF_KIND_CONST:
        case BTF_KIND_RESTRICT:
                return btf_align_of(btf, t->type);
-       case BTF_KIND_ARRAY: {
-               const struct btf_array *a = (void *)(t + 1);
-
-               return btf_align_of(btf, a->type);
-       }
+       case BTF_KIND_ARRAY:
+               return btf_align_of(btf, btf_array(t)->type);
        case BTF_KIND_STRUCT:
        case BTF_KIND_UNION: {
-               const struct btf_member *m = (void *)(t + 1);
-               __u16 vlen = btf_vlen_of(t);
+               const struct btf_member *m = btf_members(t);
+               __u16 vlen = btf_vlen(t);
                int i, align = 1;
 
                for (i = 0; i < vlen; i++, m++)
@@ -726,7 +782,7 @@ static int btf_align_of(const struct btf *btf, __u32 id)
                return align;
        }
        default:
-               pr_warning("unsupported BTF_KIND:%u\n", btf_kind_of(t));
+               pr_warning("unsupported BTF_KIND:%u\n", btf_kind(t));
                return 1;
        }
 }
@@ -737,20 +793,18 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
        const struct btf_member *m;
        int align, i, bit_sz;
        __u16 vlen;
-       bool kflag;
 
        align = btf_align_of(btf, id);
        /* size of a non-packed struct has to be a multiple of its alignment*/
        if (t->size % align)
                return true;
 
-       m = (void *)(t + 1);
-       kflag = btf_kflag_of(t);
-       vlen = btf_vlen_of(t);
+       m = btf_members(t);
+       vlen = btf_vlen(t);
        /* all non-bitfield fields have to be naturally aligned */
        for (i = 0; i < vlen; i++, m++) {
                align = btf_align_of(btf, m->type);
-               bit_sz = kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
+               bit_sz = btf_member_bitfield_size(t, i);
                if (bit_sz == 0 && m->offset % (8 * align) != 0)
                        return true;
        }
@@ -807,7 +861,7 @@ static void btf_dump_emit_struct_fwd(struct btf_dump *d, __u32 id,
                                     const struct btf_type *t)
 {
        btf_dump_printf(d, "%s %s",
-                       btf_kind_of(t) == BTF_KIND_STRUCT ? "struct" : "union",
+                       btf_is_struct(t) ? "struct" : "union",
                        btf_dump_type_name(d, id));
 }
 
@@ -816,12 +870,11 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
                                     const struct btf_type *t,
                                     int lvl)
 {
-       const struct btf_member *m = (void *)(t + 1);
-       bool kflag = btf_kflag_of(t), is_struct;
+       const struct btf_member *m = btf_members(t);
+       bool is_struct = btf_is_struct(t);
        int align, i, packed, off = 0;
-       __u16 vlen = btf_vlen_of(t);
+       __u16 vlen = btf_vlen(t);
 
-       is_struct = btf_kind_of(t) == BTF_KIND_STRUCT;
        packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
        align = packed ? 1 : btf_align_of(d->btf, id);
 
@@ -835,8 +888,8 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
                int m_off, m_sz;
 
                fname = btf_name_of(d, m->name_off);
-               m_sz = kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
-               m_off = kflag ? BTF_MEMBER_BIT_OFFSET(m->offset) : m->offset;
+               m_sz = btf_member_bitfield_size(t, i);
+               m_off = btf_member_bit_offset(t, i);
                align = packed ? 1 : btf_align_of(d->btf, m->type);
 
                btf_dump_emit_bit_padding(d, off, m_off, m_sz, align, lvl + 1);
@@ -870,8 +923,8 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
                                   const struct btf_type *t,
                                   int lvl)
 {
-       const struct btf_enum *v = (void *)(t+1);
-       __u16 vlen = btf_vlen_of(t);
+       const struct btf_enum *v = btf_enum(t);
+       __u16 vlen = btf_vlen(t);
        const char *name;
        size_t dup_cnt;
        int i;
@@ -905,7 +958,7 @@ static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
 {
        const char *name = btf_dump_type_name(d, id);
 
-       if (btf_kflag_of(t))
+       if (btf_kflag(t))
                btf_dump_printf(d, "union %s", name);
        else
                btf_dump_printf(d, "struct %s", name);
@@ -987,7 +1040,6 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
        struct id_stack decl_stack;
        const struct btf_type *t;
        int err, stack_start;
-       __u16 kind;
 
        stack_start = d->decl_stack_cnt;
        for (;;) {
@@ -1008,8 +1060,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
                        break;
 
                t = btf__type_by_id(d->btf, id);
-               kind = btf_kind_of(t);
-               switch (kind) {
+               switch (btf_kind(t)) {
                case BTF_KIND_PTR:
                case BTF_KIND_VOLATILE:
                case BTF_KIND_CONST:
@@ -1017,12 +1068,9 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
                case BTF_KIND_FUNC_PROTO:
                        id = t->type;
                        break;
-               case BTF_KIND_ARRAY: {
-                       const struct btf_array *a = (void *)(t + 1);
-
-                       id = a->type;
+               case BTF_KIND_ARRAY:
+                       id = btf_array(t)->type;
                        break;
-               }
                case BTF_KIND_INT:
                case BTF_KIND_ENUM:
                case BTF_KIND_FWD:
@@ -1032,7 +1080,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
                        goto done;
                default:
                        pr_warning("unexpected type in decl chain, kind:%u, id:[%u]\n",
-                                  kind, id);
+                                  btf_kind(t), id);
                        goto done;
                }
        }
@@ -1070,7 +1118,7 @@ static void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)
                id = decl_stack->ids[decl_stack->cnt - 1];
                t = btf__type_by_id(d->btf, id);
 
-               switch (btf_kind_of(t)) {
+               switch (btf_kind(t)) {
                case BTF_KIND_VOLATILE:
                        btf_dump_printf(d, "volatile ");
                        break;
@@ -1087,20 +1135,6 @@ static void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)
        }
 }
 
-static bool btf_is_mod_kind(const struct btf *btf, __u32 id)
-{
-       const struct btf_type *t = btf__type_by_id(btf, id);
-
-       switch (btf_kind_of(t)) {
-       case BTF_KIND_VOLATILE:
-       case BTF_KIND_CONST:
-       case BTF_KIND_RESTRICT:
-               return true;
-       default:
-               return false;
-       }
-}
-
 static void btf_dump_emit_name(const struct btf_dump *d,
                               const char *name, bool last_was_ptr)
 {
@@ -1139,7 +1173,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
                }
 
                t = btf__type_by_id(d->btf, id);
-               kind = btf_kind_of(t);
+               kind = btf_kind(t);
 
                switch (kind) {
                case BTF_KIND_INT:
@@ -1185,7 +1219,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
                        btf_dump_printf(d, " restrict");
                        break;
                case BTF_KIND_ARRAY: {
-                       const struct btf_array *a = (void *)(t + 1);
+                       const struct btf_array *a = btf_array(t);
                        const struct btf_type *next_t;
                        __u32 next_id;
                        bool multidim;
@@ -1201,7 +1235,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
                         */
                        while (decls->cnt) {
                                next_id = decls->ids[decls->cnt - 1];
-                               if (btf_is_mod_kind(d->btf, next_id))
+                               next_t = btf__type_by_id(d->btf, next_id);
+                               if (btf_is_mod(next_t))
                                        decls->cnt--;
                                else
                                        break;
@@ -1213,8 +1248,9 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
                                return;
                        }
 
+                       next_id = decls->ids[decls->cnt - 1];
                        next_t = btf__type_by_id(d->btf, next_id);
-                       multidim = btf_kind_of(next_t) == BTF_KIND_ARRAY;
+                       multidim = btf_is_array(next_t);
                        /* we need space if we have named non-pointer */
                        if (fname[0] && !last_was_ptr)
                                btf_dump_printf(d, " ");
@@ -1228,8 +1264,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
                        return;
                }
                case BTF_KIND_FUNC_PROTO: {
-                       const struct btf_param *p = (void *)(t + 1);
-                       __u16 vlen = btf_vlen_of(t);
+                       const struct btf_param *p = btf_params(t);
+                       __u16 vlen = btf_vlen(t);
                        int i;
 
                        btf_dump_emit_mods(d, decls);