Commit d90ec262 authored by Yonghong Song's avatar Yonghong Song Committed by Alexei Starovoitov

libbpf: Add enum64 support for btf_dump

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: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarYonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20220607062631.3720526-1-yhs@fb.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 2ef20263
...@@ -566,6 +566,11 @@ static inline struct btf_enum64 *btf_enum64(const struct btf_type *t) ...@@ -566,6 +566,11 @@ static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
return (struct btf_enum64 *)(t + 1); 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) static inline struct btf_member *btf_members(const struct btf_type *t)
{ {
return (struct btf_member *)(t + 1); return (struct btf_member *)(t + 1);
......
...@@ -318,6 +318,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d) ...@@ -318,6 +318,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d)
switch (btf_kind(t)) { switch (btf_kind(t)) {
case BTF_KIND_INT: case BTF_KIND_INT:
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
case BTF_KIND_ENUM64:
case BTF_KIND_FWD: case BTF_KIND_FWD:
case BTF_KIND_FLOAT: case BTF_KIND_FLOAT:
break; break;
...@@ -538,6 +539,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr) ...@@ -538,6 +539,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
return 1; return 1;
} }
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
case BTF_KIND_ENUM64:
case BTF_KIND_FWD: case BTF_KIND_FWD:
/* /*
* non-anonymous or non-referenced enums are top-level * 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) ...@@ -739,6 +741,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
tstate->emit_state = EMITTED; tstate->emit_state = EMITTED;
break; break;
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
case BTF_KIND_ENUM64:
if (top_level_def) { if (top_level_def) {
btf_dump_emit_enum_def(d, id, t, 0); btf_dump_emit_enum_def(d, id, t, 0);
btf_dump_printf(d, ";\n\n"); btf_dump_printf(d, ";\n\n");
...@@ -989,38 +992,81 @@ static void btf_dump_emit_enum_fwd(struct btf_dump *d, __u32 id, ...@@ -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)); 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, static void btf_dump_emit_enum32_val(struct btf_dump *d,
const struct btf_type *t, const struct btf_type *t,
int lvl) int lvl, __u16 vlen)
{ {
const struct btf_enum *v = btf_enum(t); 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; const char *name;
size_t dup_cnt; size_t dup_cnt;
int i; 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", btf_dump_printf(d, "enum%s%s",
t->name_off ? " " : "", t->name_off ? " " : "",
btf_dump_type_name(d, id)); btf_dump_type_name(d, id));
if (vlen) { if (!vlen)
btf_dump_printf(d, " {"); return;
for (i = 0; i < vlen; i++, v++) {
name = btf_name_of(d, v->name_off); btf_dump_printf(d, " {");
/* enumerators share namespace with typedef idents */ if (btf_is_enum(t))
dup_cnt = btf_dump_name_dups(d, d->ident_names, name); btf_dump_emit_enum32_val(d, t, lvl, vlen);
if (dup_cnt > 1) { else
btf_dump_printf(d, "\n%s%s___%zu = %u,", btf_dump_emit_enum64_val(d, t, lvl, vlen);
pfx(lvl + 1), name, dup_cnt, btf_dump_printf(d, "\n%s}", pfx(lvl));
(__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));
}
} }
static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id, static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
...@@ -1178,6 +1224,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id, ...@@ -1178,6 +1224,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
break; break;
case BTF_KIND_INT: case BTF_KIND_INT:
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
case BTF_KIND_ENUM64:
case BTF_KIND_FWD: case BTF_KIND_FWD:
case BTF_KIND_STRUCT: case BTF_KIND_STRUCT:
case BTF_KIND_UNION: case BTF_KIND_UNION:
...@@ -1312,6 +1359,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d, ...@@ -1312,6 +1359,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
btf_dump_emit_struct_fwd(d, id, t); btf_dump_emit_struct_fwd(d, id, t);
break; break;
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
case BTF_KIND_ENUM64:
btf_dump_emit_mods(d, decls); btf_dump_emit_mods(d, decls);
/* inline anonymous enum */ /* inline anonymous enum */
if (t->name_off == 0 && !d->skip_anon_defs) if (t->name_off == 0 && !d->skip_anon_defs)
...@@ -1988,7 +2036,8 @@ static int btf_dump_get_enum_value(struct btf_dump *d, ...@@ -1988,7 +2036,8 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
__u32 id, __u32 id,
__s64 *value) __s64 *value)
{ {
/* handle unaligned enum value */ bool is_signed = btf_kflag(t);
if (!ptr_is_aligned(d->btf, id, data)) { if (!ptr_is_aligned(d->btf, id, data)) {
__u64 val; __u64 val;
int err; int err;
...@@ -2005,13 +2054,13 @@ static int btf_dump_get_enum_value(struct btf_dump *d, ...@@ -2005,13 +2054,13 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
*value = *(__s64 *)data; *value = *(__s64 *)data;
return 0; return 0;
case 4: case 4:
*value = *(__s32 *)data; *value = is_signed ? *(__s32 *)data : *(__u32 *)data;
return 0; return 0;
case 2: case 2:
*value = *(__s16 *)data; *value = is_signed ? *(__s16 *)data : *(__u16 *)data;
return 0; return 0;
case 1: case 1:
*value = *(__s8 *)data; *value = is_signed ? *(__s8 *)data : *(__u8 *)data;
return 0; return 0;
default: default:
pr_warn("unexpected size %d for enum, id:[%u]\n", t->size, id); 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, ...@@ -2024,7 +2073,7 @@ static int btf_dump_enum_data(struct btf_dump *d,
__u32 id, __u32 id,
const void *data) const void *data)
{ {
const struct btf_enum *e; bool is_signed;
__s64 value; __s64 value;
int i, err; int i, err;
...@@ -2032,14 +2081,31 @@ static int btf_dump_enum_data(struct btf_dump *d, ...@@ -2032,14 +2081,31 @@ static int btf_dump_enum_data(struct btf_dump *d,
if (err) if (err)
return err; return err;
for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) { is_signed = btf_kflag(t);
if (value != e->val) if (btf_is_enum(t)) {
continue; const struct btf_enum *e;
btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
return 0; 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; return 0;
} }
...@@ -2099,6 +2165,7 @@ static int btf_dump_type_data_check_overflow(struct btf_dump *d, ...@@ -2099,6 +2165,7 @@ static int btf_dump_type_data_check_overflow(struct btf_dump *d,
case BTF_KIND_FLOAT: case BTF_KIND_FLOAT:
case BTF_KIND_PTR: case BTF_KIND_PTR:
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
case BTF_KIND_ENUM64:
if (data + bits_offset / 8 + size > d->typed_dump->data_end) if (data + bits_offset / 8 + size > d->typed_dump->data_end)
return -E2BIG; return -E2BIG;
break; break;
...@@ -2203,6 +2270,7 @@ static int btf_dump_type_data_check_zero(struct btf_dump *d, ...@@ -2203,6 +2270,7 @@ static int btf_dump_type_data_check_zero(struct btf_dump *d,
return -ENODATA; return -ENODATA;
} }
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
case BTF_KIND_ENUM64:
err = btf_dump_get_enum_value(d, t, data, id, &value); err = btf_dump_get_enum_value(d, t, data, id, &value);
if (err) if (err)
return err; return err;
...@@ -2275,6 +2343,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d, ...@@ -2275,6 +2343,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d,
err = btf_dump_struct_data(d, t, id, data); err = btf_dump_struct_data(d, t, id, data);
break; break;
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
case BTF_KIND_ENUM64:
/* handle bitfield and int enum values */ /* handle bitfield and int enum values */
if (bit_sz) { if (bit_sz) {
__u64 print_num; __u64 print_num;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment