libbpf: Add enum64 support for btf_dump
authorYonghong Song <yhs@fb.com>
Tue, 7 Jun 2022 06:26:31 +0000 (23:26 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 7 Jun 2022 17:20:43 +0000 (10:20 -0700)
Add enum64 btf dumping support. For long long and unsigned long long
dump, suffixes 'LL' and 'ULL' are added to avoid compilation errors
in some cases.

Acked-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20220607062631.3720526-1-yhs@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/lib/bpf/btf.h
tools/lib/bpf/btf_dump.c

index c7e8b1fdfe2492de547e71d008975f3c6ebfd81c..dcb3f575a281f1d2a8cf06772fdf54ba1e0d1fde 100644 (file)
@@ -566,6 +566,11 @@ static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
        return (struct btf_enum64 *)(t + 1);
 }
 
+static inline __u64 btf_enum64_value(const struct btf_enum64 *e)
+{
+       return ((__u64)e->val_hi32 << 32) | e->val_lo32;
+}
+
 static inline struct btf_member *btf_members(const struct btf_type *t)
 {
        return (struct btf_member *)(t + 1);
index 6b1bc1f43728c78be7fe5f8849c3aed5ab90d7a8..f5275f8190275984eea3eff64e205227343614e4 100644 (file)
@@ -318,6 +318,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d)
                switch (btf_kind(t)) {
                case BTF_KIND_INT:
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                case BTF_KIND_FWD:
                case BTF_KIND_FLOAT:
                        break;
@@ -538,6 +539,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
                return 1;
        }
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
        case BTF_KIND_FWD:
                /*
                 * non-anonymous or non-referenced enums are top-level
@@ -739,6 +741,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
                tstate->emit_state = EMITTED;
                break;
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                if (top_level_def) {
                        btf_dump_emit_enum_def(d, id, t, 0);
                        btf_dump_printf(d, ";\n\n");
@@ -989,38 +992,81 @@ static void btf_dump_emit_enum_fwd(struct btf_dump *d, __u32 id,
        btf_dump_printf(d, "enum %s", btf_dump_type_name(d, id));
 }
 
-static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
-                                  const struct btf_type *t,
-                                  int lvl)
+static void btf_dump_emit_enum32_val(struct btf_dump *d,
+                                    const struct btf_type *t,
+                                    int lvl, __u16 vlen)
 {
        const struct btf_enum *v = btf_enum(t);
-       __u16 vlen = btf_vlen(t);
+       bool is_signed = btf_kflag(t);
+       const char *fmt_str;
        const char *name;
        size_t dup_cnt;
        int i;
 
+       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) {
+                       fmt_str = is_signed ? "\n%s%s___%zd = %d," : "\n%s%s___%zd = %u,";
+                       btf_dump_printf(d, fmt_str, pfx(lvl + 1), name, dup_cnt, v->val);
+               } else {
+                       fmt_str = is_signed ? "\n%s%s = %d," : "\n%s%s = %u,";
+                       btf_dump_printf(d, fmt_str, pfx(lvl + 1), name, v->val);
+               }
+       }
+}
+
+static void btf_dump_emit_enum64_val(struct btf_dump *d,
+                                    const struct btf_type *t,
+                                    int lvl, __u16 vlen)
+{
+       const struct btf_enum64 *v = btf_enum64(t);
+       bool is_signed = btf_kflag(t);
+       const char *fmt_str;
+       const char *name;
+       size_t dup_cnt;
+       __u64 val;
+       int i;
+
+       for (i = 0; i < vlen; i++, v++) {
+               name = btf_name_of(d, v->name_off);
+               dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
+               val = btf_enum64_value(v);
+               if (dup_cnt > 1) {
+                       fmt_str = is_signed ? "\n%s%s___%zd = %lldLL,"
+                                           : "\n%s%s___%zd = %lluULL,";
+                       btf_dump_printf(d, fmt_str,
+                                       pfx(lvl + 1), name, dup_cnt,
+                                       (unsigned long long)val);
+               } else {
+                       fmt_str = is_signed ? "\n%s%s = %lldLL,"
+                                           : "\n%s%s = %lluULL,";
+                       btf_dump_printf(d, fmt_str,
+                                       pfx(lvl + 1), name,
+                                       (unsigned long long)val);
+               }
+       }
+}
+static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
+                                  const struct btf_type *t,
+                                  int lvl)
+{
+       __u16 vlen = btf_vlen(t);
+
        btf_dump_printf(d, "enum%s%s",
                        t->name_off ? " " : "",
                        btf_dump_type_name(d, id));
 
-       if (vlen) {
-               btf_dump_printf(d, " {");
-               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,
-                                               (__u32)v->val);
-                       } else {
-                               btf_dump_printf(d, "\n%s%s = %u,",
-                                               pfx(lvl + 1), name,
-                                               (__u32)v->val);
-                       }
-               }
-               btf_dump_printf(d, "\n%s}", pfx(lvl));
-       }
+       if (!vlen)
+               return;
+
+       btf_dump_printf(d, " {");
+       if (btf_is_enum(t))
+               btf_dump_emit_enum32_val(d, t, lvl, vlen);
+       else
+               btf_dump_emit_enum64_val(d, t, lvl, vlen);
+       btf_dump_printf(d, "\n%s}", pfx(lvl));
 }
 
 static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
@@ -1178,6 +1224,7 @@ skip_mod:
                        break;
                case BTF_KIND_INT:
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                case BTF_KIND_FWD:
                case BTF_KIND_STRUCT:
                case BTF_KIND_UNION:
@@ -1312,6 +1359,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
                                btf_dump_emit_struct_fwd(d, id, t);
                        break;
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                        btf_dump_emit_mods(d, decls);
                        /* inline anonymous enum */
                        if (t->name_off == 0 && !d->skip_anon_defs)
@@ -1988,7 +2036,8 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
                                   __u32 id,
                                   __s64 *value)
 {
-       /* handle unaligned enum value */
+       bool is_signed = btf_kflag(t);
+
        if (!ptr_is_aligned(d->btf, id, data)) {
                __u64 val;
                int err;
@@ -2005,13 +2054,13 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
                *value = *(__s64 *)data;
                return 0;
        case 4:
-               *value = *(__s32 *)data;
+               *value = is_signed ? *(__s32 *)data : *(__u32 *)data;
                return 0;
        case 2:
-               *value = *(__s16 *)data;
+               *value = is_signed ? *(__s16 *)data : *(__u16 *)data;
                return 0;
        case 1:
-               *value = *(__s8 *)data;
+               *value = is_signed ? *(__s8 *)data : *(__u8 *)data;
                return 0;
        default:
                pr_warn("unexpected size %d for enum, id:[%u]\n", t->size, id);
@@ -2024,7 +2073,7 @@ static int btf_dump_enum_data(struct btf_dump *d,
                              __u32 id,
                              const void *data)
 {
-       const struct btf_enum *e;
+       bool is_signed;
        __s64 value;
        int i, err;
 
@@ -2032,14 +2081,31 @@ static int btf_dump_enum_data(struct btf_dump *d,
        if (err)
                return err;
 
-       for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) {
-               if (value != e->val)
-                       continue;
-               btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
-               return 0;
-       }
+       is_signed = btf_kflag(t);
+       if (btf_is_enum(t)) {
+               const struct btf_enum *e;
+
+               for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) {
+                       if (value != e->val)
+                               continue;
+                       btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
+                       return 0;
+               }
 
-       btf_dump_type_values(d, "%d", value);
+               btf_dump_type_values(d, is_signed ? "%d" : "%u", value);
+       } else {
+               const struct btf_enum64 *e;
+
+               for (i = 0, e = btf_enum64(t); i < btf_vlen(t); i++, e++) {
+                       if (value != btf_enum64_value(e))
+                               continue;
+                       btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
+                       return 0;
+               }
+
+               btf_dump_type_values(d, is_signed ? "%lldLL" : "%lluULL",
+                                    (unsigned long long)value);
+       }
        return 0;
 }
 
@@ -2099,6 +2165,7 @@ static int btf_dump_type_data_check_overflow(struct btf_dump *d,
        case BTF_KIND_FLOAT:
        case BTF_KIND_PTR:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                if (data + bits_offset / 8 + size > d->typed_dump->data_end)
                        return -E2BIG;
                break;
@@ -2203,6 +2270,7 @@ static int btf_dump_type_data_check_zero(struct btf_dump *d,
                return -ENODATA;
        }
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                err = btf_dump_get_enum_value(d, t, data, id, &value);
                if (err)
                        return err;
@@ -2275,6 +2343,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d,
                err = btf_dump_struct_data(d, t, id, data);
                break;
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                /* handle bitfield and int enum values */
                if (bit_sz) {
                        __u64 print_num;