bpftool: Add btf enum64 support
authorYonghong Song <yhs@fb.com>
Tue, 7 Jun 2022 06:26:52 +0000 (23:26 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 7 Jun 2022 17:20:43 +0000 (10:20 -0700)
Add BTF_KIND_ENUM64 support.
For example, the following enum is defined in uapi bpf.h.
  $ cat core.c
  enum A {
        BPF_F_INDEX_MASK                = 0xffffffffULL,
        BPF_F_CURRENT_CPU               = BPF_F_INDEX_MASK,
        BPF_F_CTXLEN_MASK               = (0xfffffULL << 32),
  } g;
Compiled with
  clang -target bpf -O2 -g -c core.c
Using bpftool to dump types and generate format C file:
  $ bpftool btf dump file core.o
  ...
  [1] ENUM64 'A' encoding=UNSIGNED size=8 vlen=3
        'BPF_F_INDEX_MASK' val=4294967295ULL
        'BPF_F_CURRENT_CPU' val=4294967295ULL
        'BPF_F_CTXLEN_MASK' val=4503595332403200ULL
  $ bpftool btf dump file core.o format c
  ...
  enum A {
        BPF_F_INDEX_MASK = 4294967295ULL,
        BPF_F_CURRENT_CPU = 4294967295ULL,
        BPF_F_CTXLEN_MASK = 4503595332403200ULL,
  };
  ...

Note that for raw btf output, the encoding (UNSIGNED or SIGNED)
is printed out as well. The 64bit value is also represented properly
in BTF and C dump.

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

index 7e6accb..0744bd1 100644 (file)
@@ -40,6 +40,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
        [BTF_KIND_FLOAT]        = "FLOAT",
        [BTF_KIND_DECL_TAG]     = "DECL_TAG",
        [BTF_KIND_TYPE_TAG]     = "TYPE_TAG",
+       [BTF_KIND_ENUM64]       = "ENUM64",
 };
 
 struct btf_attach_point {
@@ -212,26 +213,76 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
        case BTF_KIND_ENUM: {
                const struct btf_enum *v = (const void *)(t + 1);
                __u16 vlen = BTF_INFO_VLEN(t->info);
+               const char *encoding;
                int i;
 
+               encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
                if (json_output) {
+                       jsonw_string_field(w, "encoding", encoding);
                        jsonw_uint_field(w, "size", t->size);
                        jsonw_uint_field(w, "vlen", vlen);
                        jsonw_name(w, "values");
                        jsonw_start_array(w);
                } else {
-                       printf(" size=%u vlen=%u", t->size, vlen);
+                       printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
+               }
+               for (i = 0; i < vlen; i++, v++) {
+                       const char *name = btf_str(btf, v->name_off);
+
+                       if (json_output) {
+                               jsonw_start_object(w);
+                               jsonw_string_field(w, "name", name);
+                               if (btf_kflag(t))
+                                       jsonw_int_field(w, "val", v->val);
+                               else
+                                       jsonw_uint_field(w, "val", v->val);
+                               jsonw_end_object(w);
+                       } else {
+                               if (btf_kflag(t))
+                                       printf("\n\t'%s' val=%d", name, v->val);
+                               else
+                                       printf("\n\t'%s' val=%u", name, v->val);
+                       }
+               }
+               if (json_output)
+                       jsonw_end_array(w);
+               break;
+       }
+       case BTF_KIND_ENUM64: {
+               const struct btf_enum64 *v = btf_enum64(t);
+               __u16 vlen = btf_vlen(t);
+               const char *encoding;
+               int i;
+
+               encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
+               if (json_output) {
+                       jsonw_string_field(w, "encoding", encoding);
+                       jsonw_uint_field(w, "size", t->size);
+                       jsonw_uint_field(w, "vlen", vlen);
+                       jsonw_name(w, "values");
+                       jsonw_start_array(w);
+               } else {
+                       printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
                }
                for (i = 0; i < vlen; i++, v++) {
                        const char *name = btf_str(btf, v->name_off);
+                       __u64 val = ((__u64)v->val_hi32 << 32) | v->val_lo32;
 
                        if (json_output) {
                                jsonw_start_object(w);
                                jsonw_string_field(w, "name", name);
-                               jsonw_uint_field(w, "val", v->val);
+                               if (btf_kflag(t))
+                                       jsonw_int_field(w, "val", val);
+                               else
+                                       jsonw_uint_field(w, "val", val);
                                jsonw_end_object(w);
                        } else {
-                               printf("\n\t'%s' val=%u", name, v->val);
+                               if (btf_kflag(t))
+                                       printf("\n\t'%s' val=%lldLL", name,
+                                              (unsigned long long)val);
+                               else
+                                       printf("\n\t'%s' val=%lluULL", name,
+                                              (unsigned long long)val);
                        }
                }
                if (json_output)
index f5dddf8..125798b 100644 (file)
@@ -182,6 +182,32 @@ static int btf_dumper_enum(const struct btf_dumper *d,
        return 0;
 }
 
+static int btf_dumper_enum64(const struct btf_dumper *d,
+                            const struct btf_type *t,
+                            const void *data)
+{
+       const struct btf_enum64 *enums = btf_enum64(t);
+       __u32 val_lo32, val_hi32;
+       __u64 value;
+       __u16 i;
+
+       value = *(__u64 *)data;
+       val_lo32 = (__u32)value;
+       val_hi32 = value >> 32;
+
+       for (i = 0; i < btf_vlen(t); i++) {
+               if (val_lo32 == enums[i].val_lo32 && val_hi32 == enums[i].val_hi32) {
+                       jsonw_string(d->jw,
+                                    btf__name_by_offset(d->btf,
+                                                        enums[i].name_off));
+                       return 0;
+               }
+       }
+
+       jsonw_int(d->jw, value);
+       return 0;
+}
+
 static bool is_str_array(const struct btf *btf, const struct btf_array *arr,
                         const char *s)
 {
@@ -542,6 +568,8 @@ static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
                return btf_dumper_array(d, type_id, data);
        case BTF_KIND_ENUM:
                return btf_dumper_enum(d, t, data);
+       case BTF_KIND_ENUM64:
+               return btf_dumper_enum64(d, t, data);
        case BTF_KIND_PTR:
                btf_dumper_ptr(d, t, data);
                return 0;
@@ -618,6 +646,7 @@ static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
                              btf__name_by_offset(btf, t->name_off));
                break;
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                BTF_PRINT_ARG("enum %s ",
                              btf__name_by_offset(btf, t->name_off));
                break;
index f158dc1..480cbd8 100644 (file)
@@ -1750,6 +1750,7 @@ btfgen_mark_type(struct btfgen_info *info, unsigned int type_id, bool follow_poi
        case BTF_KIND_INT:
        case BTF_KIND_FLOAT:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
        case BTF_KIND_STRUCT:
        case BTF_KIND_UNION:
                break;