Em Wed, Jun 29, 2022 at 12:12:24AM -0700, Yonghong Song escreveu: > BTF_KIND_ENUM64 is supported with latest libbpf, which > supports 64-bit enum values. Latest libbpf also supports > signedness for enum values. Add enum64 support in > dwarf-to-btf conversion. > > The following is an example of new encoding which covers > signed/unsigned enum64/enum variations. So, testing this with torvalds/master I'm getting: FAILED: load BTF from vmlinux: Invalid argument make[1]: *** [/var/home/acme/git/linux/Makefile:1164: vmlinux] Error 255 make[1]: *** Deleting file 'vmlinux' make[1]: Leaving directory '/var/home/acme/git/build/v5.19-rc4+' make: *** [Makefile:219: __sub-make] Error 2 real 8m12.396s user 183m18.009s sys 44m27.085s ⬢[acme@toolbox linux]$ find . -name "*.c" | xargs grep "load BTF from vmlinux" ⬢[acme@toolbox linux]$ find . -name "*.c" | xargs grep "load BTF from" ./tools/bpf/bpftool/btf.c: p_err("failed to load BTF from %s: %s", ./tools/bpf/resolve_btfids/main.c: pr_err("FAILED: load BTF from %s: %s\n", ./tools/testing/selftests/bpf/prog_tests/resolve_btfids.c: "Failed to load BTF from btf_data.o\n")) ⬢[acme@toolbox linux]$ vim ./tools/bpf/resolve_btfids/main.c Which is: btf = btf__parse_split(obj->btf ?: obj->path, base_btf); err = libbpf_get_error(btf); if (err) { pr_err("FAILED: load BTF from %s: %s\n", obj->btf ?: obj->path, strerror(-err)); goto out; } I.e. tools/lib/bpf in torvalds/master doesn´t support BTF_KIND_ENUM64, right? So to build it with a new pahole one needs to ask for --skip_encoding_btf_enum64? How to do this automagically? I.e. its a matter of checking if the in-kernel libbpf has support for it and if not use --skip_encoding_btf_enum64? I'm now going to try with bpf-next/master - Arnaldo > $cat t.c > enum { /* signed, enum64 */ > A = -1, > B = 0xffffffff, > } g1; > enum { /* unsigned, enum64 */ > C = 1, > D = 0xfffffffff, > } g2; > enum { /* signed, enum */ > E = -1, > F = 0xfffffff, > } g3; > enum { /* unsigned, enum */ > G = 1, > H = 0xfffffff, > } g4; > $ clang -g -c t.c > $ pahole -JV t.o > btf_encoder__new: 't.o' doesn't have '.data..percpu' section > Found 0 per-CPU variables! > File t.o: > [1] ENUM64 (anon) size=8 > A val=-1 > B val=4294967295 > [2] INT long size=8 nr_bits=64 encoding=SIGNED > [3] ENUM64 (anon) size=8 > C val=1 > D val=68719476735 > [4] INT unsigned long size=8 nr_bits=64 encoding=(none) > [5] ENUM (anon) size=4 > E val=-1 > F val=268435455 > [6] INT int size=4 nr_bits=32 encoding=SIGNED > [7] ENUM (anon) size=4 > G val=1 > H val=268435455 > [8] INT unsigned int size=4 nr_bits=32 encoding=(none) > > With the flag to skip enum64 encoding, > > $ pahole -JV t.o --skip_encoding_btf_enum64 > btf_encoder__new: 't.o' doesn't have '.data..percpu' section > Found 0 per-CPU variables! > File t.o: > [1] ENUM (anon) size=8 > A val=4294967295 > B val=4294967295 > [2] INT long size=8 nr_bits=64 encoding=SIGNED > [3] ENUM (anon) size=8 > C val=1 > D val=4294967295 > [4] INT unsigned long size=8 nr_bits=64 encoding=(none) > [5] ENUM (anon) size=4 > E val=4294967295 > F val=268435455 > [6] INT int size=4 nr_bits=32 encoding=SIGNED > [7] ENUM (anon) size=4 > G val=1 > H val=268435455 > [8] INT unsigned int size=4 nr_bits=32 encoding=(none) > > In the above btf encoding without enum64, all enum types > with the same type size as the corresponding enum64. All these > enum types have unsigned type (kflag = 0) which is required > before kernel enum64 support. > > Acked-by: Andrii Nakryiko <andrii@xxxxxxxxxx> > Signed-off-by: Yonghong Song <yhs@xxxxxx> > --- > btf_encoder.c | 67 +++++++++++++++++++++++++++++++++++------------ > btf_encoder.h | 2 +- > dwarf_loader.c | 12 +++++++++ > dwarves.h | 4 ++- > dwarves_fprintf.c | 6 ++++- > pahole.c | 10 ++++++- > 6 files changed, 80 insertions(+), 21 deletions(-) > > diff --git a/btf_encoder.c b/btf_encoder.c > index 9e708e4..daa8e3b 100644 > --- a/btf_encoder.c > +++ b/btf_encoder.c > @@ -144,6 +144,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", > }; > > static const char *btf__printable_name(const struct btf *btf, uint32_t offset) > @@ -490,34 +491,64 @@ static int32_t btf_encoder__add_struct(struct btf_encoder *encoder, uint8_t kind > return id; > } > > -static int32_t btf_encoder__add_enum(struct btf_encoder *encoder, const char *name, uint32_t bit_size) > +static int32_t btf_encoder__add_enum(struct btf_encoder *encoder, const char *name, struct type *etype, > + struct conf_load *conf_load) > { > struct btf *btf = encoder->btf; > const struct btf_type *t; > int32_t id, size; > + bool is_enum32; > > - size = BITS_ROUNDUP_BYTES(bit_size); > - id = btf__add_enum(btf, name, size); > + size = BITS_ROUNDUP_BYTES(etype->size); > + is_enum32 = size <= 4 || conf_load->skip_encoding_btf_enum64; > + if (is_enum32) > + id = btf__add_enum(btf, name, size); > + else > + id = btf__add_enum64(btf, name, size, etype->is_signed_enum); > if (id > 0) { > t = btf__type_by_id(btf, id); > btf_encoder__log_type(encoder, t, false, true, "size=%u", t->size); > } else { > - btf__log_err(btf, BTF_KIND_ENUM, name, true, > + btf__log_err(btf, is_enum32 ? BTF_KIND_ENUM : BTF_KIND_ENUM64, name, true, > "size=%u Error emitting BTF type", size); > } > return id; > } > > -static int btf_encoder__add_enum_val(struct btf_encoder *encoder, const char *name, int32_t value) > +static int btf_encoder__add_enum_val(struct btf_encoder *encoder, const char *name, int64_t value, > + struct type *etype, struct conf_load *conf_load) > { > - int err = btf__add_enum_value(encoder->btf, name, value); > + const char *fmt_str; > + int err; > + > + /* If enum64 is not allowed, generate enum32 with unsigned int value. In enum64-supported > + * libbpf library, btf__add_enum_value() will set the kflag (sign bit) in common_type > + * if the value is negative. > + */ > + if (conf_load->skip_encoding_btf_enum64) > + err = btf__add_enum_value(encoder->btf, name, (uint32_t)value); > + else if (etype->size > 32) > + err = btf__add_enum64_value(encoder->btf, name, value); > + else > + err = btf__add_enum_value(encoder->btf, name, value); > > if (!err) { > - if (encoder->verbose) > - printf("\t%s val=%d\n", name, value); > + if (encoder->verbose) { > + if (conf_load->skip_encoding_btf_enum64) { > + printf("\t%s val=%u\n", name, (uint32_t)value); > + } else { > + fmt_str = etype->is_signed_enum ? "\t%s val=%lld\n" : "\t%s val=%llu\n"; > + printf(fmt_str, name, (unsigned long long)value); > + } > + } > } else { > - fprintf(stderr, "\t%s val=%d Error emitting BTF enum value\n", > - name, value); > + if (conf_load->skip_encoding_btf_enum64) { > + fprintf(stderr, "\t%s val=%u Error emitting BTF enum value\n", name, (uint32_t)value); > + } else { > + fmt_str = etype->is_signed_enum ? "\t%s val=%lld Error emitting BTF enum value\n" > + : "\t%s val=%llu Error emitting BTF enum value\n"; > + fprintf(stderr, fmt_str, name, (unsigned long long)value); > + } > } > return err; > } > @@ -844,27 +875,29 @@ static uint32_t array_type__nelems(struct tag *tag) > return nelem; > } > > -static int32_t btf_encoder__add_enum_type(struct btf_encoder *encoder, struct tag *tag) > +static int32_t btf_encoder__add_enum_type(struct btf_encoder *encoder, struct tag *tag, > + struct conf_load *conf_load) > { > struct type *etype = tag__type(tag); > struct enumerator *pos; > const char *name = type__name(etype); > int32_t type_id; > > - type_id = btf_encoder__add_enum(encoder, name, etype->size); > + type_id = btf_encoder__add_enum(encoder, name, etype, conf_load); > if (type_id < 0) > return type_id; > > type__for_each_enumerator(etype, pos) { > name = enumerator__name(pos); > - if (btf_encoder__add_enum_val(encoder, name, pos->value)) > + if (btf_encoder__add_enum_val(encoder, name, pos->value, etype, conf_load)) > return -1; > } > > return type_id; > } > > -static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag, uint32_t type_id_off) > +static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag, uint32_t type_id_off, > + struct conf_load *conf_load) > { > /* single out type 0 as it represents special type "void" */ > uint32_t ref_type_id = tag->type == 0 ? 0 : type_id_off + tag->type; > @@ -903,7 +936,7 @@ static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag, > encoder->need_index_type = true; > return btf_encoder__add_array(encoder, ref_type_id, encoder->array_index_id, array_type__nelems(tag)); > case DW_TAG_enumeration_type: > - return btf_encoder__add_enum_type(encoder, tag); > + return btf_encoder__add_enum_type(encoder, tag, conf_load); > case DW_TAG_subroutine_type: > return btf_encoder__add_func_proto(encoder, tag__ftype(tag), type_id_off); > default: > @@ -1422,7 +1455,7 @@ void btf_encoder__delete(struct btf_encoder *encoder) > free(encoder); > } > > -int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu) > +int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct conf_load *conf_load) > { > uint32_t type_id_off = btf__type_cnt(encoder->btf) - 1; > struct llvm_annotation *annot; > @@ -1446,7 +1479,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu) > } > > cu__for_each_type(cu, core_id, pos) { > - btf_type_id = btf_encoder__encode_tag(encoder, pos, type_id_off); > + btf_type_id = btf_encoder__encode_tag(encoder, pos, type_id_off, conf_load); > > if (btf_type_id < 0 || > tag__check_id_drift(pos, core_id, btf_type_id, type_id_off)) { > diff --git a/btf_encoder.h b/btf_encoder.h > index 339fae2..a65120c 100644 > --- a/btf_encoder.h > +++ b/btf_encoder.h > @@ -21,7 +21,7 @@ void btf_encoder__delete(struct btf_encoder *encoder); > > int btf_encoder__encode(struct btf_encoder *encoder); > > -int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu); > +int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct conf_load *conf_load); > > void btf_encoders__add(struct list_head *encoders, struct btf_encoder *encoder); > > diff --git a/dwarf_loader.c b/dwarf_loader.c > index a0d964b..4767602 100644 > --- a/dwarf_loader.c > +++ b/dwarf_loader.c > @@ -632,6 +632,18 @@ static void type__init(struct type *type, Dwarf_Die *die, struct cu *cu, struct > type->resized = 0; > type->nr_members = 0; > type->nr_static_members = 0; > + type->is_signed_enum = 0; > + > + Dwarf_Attribute attr; > + if (dwarf_attr(die, DW_AT_type, &attr) != NULL) { > + Dwarf_Die type_die; > + if (dwarf_formref_die(&attr, &type_die) != NULL) { > + uint64_t encoding = attr_numeric(&type_die, DW_AT_encoding); > + > + if (encoding == DW_ATE_signed || encoding == DW_ATE_signed_char) > + type->is_signed_enum = 1; > + } > + } > } > > static struct type *type__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf) > diff --git a/dwarves.h b/dwarves.h > index 4d0e4b6..bec9f08 100644 > --- a/dwarves.h > +++ b/dwarves.h > @@ -65,6 +65,7 @@ struct conf_load { > bool skip_encoding_btf_decl_tag; > bool skip_missing; > bool skip_encoding_btf_type_tag; > + bool skip_encoding_btf_enum64; > uint8_t hashtable_bits; > uint8_t max_hashtable_bits; > uint16_t kabi_prefix_len; > @@ -1046,6 +1047,7 @@ struct type { > uint8_t definition_emitted:1; > uint8_t fwd_decl_emitted:1; > uint8_t resized:1; > + uint8_t is_signed_enum:1; > }; > > void __type__init(struct type *type); > @@ -1365,7 +1367,7 @@ static inline struct string_type *tag__string_type(const struct tag *tag) > struct enumerator { > struct tag tag; > const char *name; > - uint32_t value; > + uint64_t value; > struct tag_cu type_enum; // To cache the type_enum searches > }; > > diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c > index 2cec584..ce64c79 100644 > --- a/dwarves_fprintf.c > +++ b/dwarves_fprintf.c > @@ -437,7 +437,11 @@ size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *co > type__for_each_enumerator(type, pos) { > printed += fprintf(fp, "%.*s\t%-*s = ", indent, tabs, > max_entry_name_len, enumerator__name(pos)); > - printed += fprintf(fp, conf->hex_fmt ? "%#x" : "%u", pos->value); > + if (conf->hex_fmt) > + printed += fprintf(fp, "%#llx", (unsigned long long)pos->value); > + else > + printed += fprintf(fp, type->is_signed_enum ? "%lld" : "%llu", > + (unsigned long long)pos->value); > printed += fprintf(fp, ",\n"); > } > > diff --git a/pahole.c b/pahole.c > index 78caa08..e87d9a4 100644 > --- a/pahole.c > +++ b/pahole.c > @@ -1220,6 +1220,7 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; > #define ARGP_compile 334 > #define ARGP_languages 335 > #define ARGP_languages_exclude 336 > +#define ARGP_skip_encoding_btf_enum64 337 > > static const struct argp_option pahole__options[] = { > { > @@ -1622,6 +1623,11 @@ static const struct argp_option pahole__options[] = { > .arg = "LANGUAGES", > .doc = "Don't consider compilation units written in these languages" > }, > + { > + .name = "skip_encoding_btf_enum64", > + .key = ARGP_skip_encoding_btf_enum64, > + .doc = "Do not encode ENUM64sin BTF." > + }, > { > .name = NULL, > } > @@ -1787,6 +1793,8 @@ static error_t pahole__options_parser(int key, char *arg, > /* fallthru */ > case ARGP_languages: > languages.str = arg; break; > + case ARGP_skip_encoding_btf_enum64: > + conf_load.skip_encoding_btf_enum64 = true; break; > default: > return ARGP_ERR_UNKNOWN; > } > @@ -3067,7 +3075,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu, > encoder = btf_encoder; > } > > - if (btf_encoder__encode_cu(encoder, cu)) { > + if (btf_encoder__encode_cu(encoder, cu, conf_load)) { > fprintf(stderr, "Encountered error while encoding BTF.\n"); > exit(1); > } > -- > 2.30.2 -- - Arnaldo