Em Mon, Aug 24, 2020 at 05:45:23PM -0700, Hao Luo escreveu: > It is found on gcc 8.2 that global percpu variables generate the > following dwarf entry in the cu where the variable is defined[1]. > > Take the global variable "bpf_prog_active" defined in > kernel/bpf/syscall.c as an example. The debug info for syscall.c > has two dwarf entries for "bpf_prog_active". > > > readelf -wi kernel/bpf/syscall.o > > 0x00013534: DW_TAG_variable > DW_AT_name ("bpf_prog_active") > DW_AT_decl_file > ("/data/users/yhs/work/net-next/include/linux/bpf.h") > DW_AT_decl_line (1074) > DW_AT_decl_column (0x01) > DW_AT_type (0x000000d6 "int") > DW_AT_external (true) > DW_AT_declaration (true) > > 0x00021a25: DW_TAG_variable > DW_AT_specification (0x00013534 "bpf_prog_active") > DW_AT_decl_file > ("/data/users/yhs/work/net-next/kernel/bpf/syscall.c") > DW_AT_decl_line (43) > DW_AT_location (DW_OP_addr 0x0) Interesting, here I get, with binutils' readelf: [root@quaco perf]# readelf -wi ../build/v5.8-rc5+/kernel/bpf/syscall.o | grep bpf_prog_active <f6a1> DW_AT_name : (indirect string, offset: 0xb70d): bpf_prog_active [root@quaco perf]# Just one, as: [root@quaco perf]# readelf -wi ../build/v5.8-rc5+/kernel/bpf/syscall.o | grep bpf_prog_active -B1 -A8 <1><f6a0>: Abbrev Number: 103 (DW_TAG_variable) <f6a1> DW_AT_name : (indirect string, offset: 0xb70d): bpf_prog_active <f6a5> DW_AT_decl_file : 11 <f6a6> DW_AT_decl_line : 1008 <f6a8> DW_AT_decl_column : 1 <f6a9> DW_AT_type : <0xcf> <f6ad> DW_AT_external : 1 <f6ad> DW_AT_declaration : 1 <1><f6ad>: Abbrev Number: 103 (DW_TAG_variable) <f6ae> DW_AT_name : (indirect string, offset: 0x3a5d): bpf_stats_enabled_mutex [root@quaco perf]# I get what you have when I use elfutils' readelf: [root@quaco perf]# eu-readelf -winfo ../build/v5.8-rc5+/kernel/bpf/syscall.o | grep bpf_prog_active name (strp) "bpf_prog_active" [ 0] addr .data..percpu+0 <bpf_prog_active> [root@quaco perf]# [root@quaco perf]# eu-readelf -winfo ../build/v5.8-rc5+/kernel/bpf/syscall.o | grep -B1 -A8 \"bpf_prog_active\" [ f6a0] variable abbrev: 103 name (strp) "bpf_prog_active" decl_file (data1) bpf.h (11) decl_line (data2) 1008 decl_column (data1) 1 type (ref4) [ cf] external (flag_present) yes declaration (flag_present) yes [ f6ad] variable abbrev: 103 name (strp) "bpf_stats_enabled_mutex" [root@quaco perf]# And: [root@quaco perf]# eu-readelf -winfo ../build/v5.8-rc5+/kernel/bpf/syscall.o | grep -B5 \<bpf_prog_active\> [ 1bdf5] variable abbrev: 212 specification (ref4) [ f6a0] decl_file (data1) syscall.c (1) decl_line (data1) 43 location (exprloc) [ 0] addr .data..percpu+0 <bpf_prog_active> [root@quaco perf]# > Note that second DW_TAG_variable entry contains specification that > points to the first entry. So you are not considering the first when encoding since it is just a DW_AT_declaration, considers the second, as it should be, and then needs to go see its DW_AT_specification, right? Sounds correct, applying, will test further and then push out, Thanks, - Arnaldo > This causes problem for btf_encoder when > encoding global variables. The tag generated for the second entry > doesn't have the type and scope info. Therefore the BTF VARs encoded > using this tag has incorrect type_id and scope. > > As fix, when creating variable, examine the dwarf entry. If it has > a DW_AT_specification, store the referred struct variable in a 'spec' > field. When encoding VARs, check this 'spec', if it's non-empty, follow > the pointer to use the referred var. > > [1] https://www.mail-archive.com/netdev@xxxxxxxxxxxxxxx/msg348144.html > > Tested: Tested using gcc 4.9 and gcc 8.2. The types and scopes of global > vars are now generated correctly. > > [21] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED > [21102] VAR 'bpf_prog_active' type_id=21, linkage=global-alloc > > Signed-off-by: Hao Luo <haoluo@xxxxxxxxxx> > --- > btf_encoder.c | 16 +++++++++++++--- > dwarf_loader.c | 25 ++++++++++++++++++++++++- > dwarves.h | 1 + > libbtf.c | 4 +++- > 4 files changed, 41 insertions(+), 5 deletions(-) > > diff --git a/btf_encoder.c b/btf_encoder.c > index 982f59d..29b2095 100644 > --- a/btf_encoder.c > +++ b/btf_encoder.c > @@ -329,10 +329,10 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force) > struct hlist_head *head; > > var = tag__variable(pos); > - if (var->declaration) > + if (var->declaration && !var->spec) > continue; > /* percpu variables are allocated in global space */ > - if (variable__scope(var) != VSCOPE_GLOBAL) > + if (variable__scope(var) != VSCOPE_GLOBAL && !var->spec) > continue; > has_global_var = true; > head = &hash_addr[hashaddr__fn(var->ip.addr)]; > @@ -376,6 +376,8 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force) > var = hashaddr__find_variable(hash_addr, addr); > if (var == NULL) > continue; > + if (var->spec) > + var = var->spec; > > sym_name = elf_sym__name(&sym, btfe->symtab); > if (!btf_name_valid(sym_name)) { > @@ -387,7 +389,15 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force) > break; > } > name = strings__add(strings, sym_name); > - type = var->ip.tag.type + type_id_off; > + if (var->ip.tag.type == 0) { > + dump_invalid_symbol("Found symbol of void type when encoding btf", > + sym_name, cu->name, verbose, force); > + if (force) > + continue; > + err = -1; > + break; > + } > + type = type_id_off + var->ip.tag.type; > size = elf_sym__size(&sym); > if (!size) { > dump_invalid_symbol("Found symbol of zero size when encoding btf", > diff --git a/dwarf_loader.c b/dwarf_loader.c > index b8d7b35..46f86cb 100644 > --- a/dwarf_loader.c > +++ b/dwarf_loader.c > @@ -576,7 +576,15 @@ const char *variable__scope_str(const struct variable *var) > > static struct variable *variable__new(Dwarf_Die *die, struct cu *cu) > { > - struct variable *var = tag__alloc(cu, sizeof(*var)); > + struct variable *var; > + bool has_specification; > + > + has_specification = dwarf_hasattr(die, DW_AT_specification); > + if (has_specification) { > + var = tag__alloc_with_spec(cu, sizeof(*var)); > + } else { > + var = tag__alloc(cu, sizeof(*var)); > + } > > if (var != NULL) { > tag__init(&var->ip.tag, cu, die); > @@ -589,6 +597,10 @@ static struct variable *variable__new(Dwarf_Die *die, struct cu *cu) > var->ip.addr = 0; > if (!var->declaration && cu->has_addr_info) > var->scope = dwarf__location(die, &var->ip.addr, &var->location); > + if (has_specification) { > + dwarf_tag__set_spec(var->ip.tag.priv, > + attr_type(die, DW_AT_specification)); > + } > } > > return var; > @@ -2008,6 +2020,17 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu) > if (dtype != NULL) > goto out; > goto find_type; > + case DW_TAG_variable: { > + struct variable *var = tag__variable(tag); > + dwarf_off_ref specification = dwarf_tag__spec(dtag); > + > + if (specification.off) { > + dtype = dwarf_cu__find_tag_by_ref(cu->priv, &specification); > + if (dtype) > + var->spec = tag__variable(dtype->tag); > + } > + } > + > } > > if (dtag->type.off == 0) { > diff --git a/dwarves.h b/dwarves.h > index 771a02c..bbd5478 100644 > --- a/dwarves.h > +++ b/dwarves.h > @@ -679,6 +679,7 @@ struct variable { > enum vscope scope; > struct location location; > struct hlist_node tool_hnode; > + struct variable *spec; > }; > > static inline struct variable *tag__variable(const struct tag *tag) > diff --git a/libbtf.c b/libbtf.c > index 7a01ded..ac06b79 100644 > --- a/libbtf.c > +++ b/libbtf.c > @@ -304,6 +304,8 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { > [BTF_KIND_RESTRICT] = "RESTRICT", > [BTF_KIND_FUNC] = "FUNC", > [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO", > + [BTF_KIND_VAR] = "VAR", > + [BTF_KIND_DATASEC] = "DATASEC", > }; > > static const char *btf_elf__name_in_gobuf(const struct btf_elf *btfe, uint32_t offset) > @@ -671,7 +673,7 @@ int32_t btf_elf__add_var_type(struct btf_elf *btfe, uint32_t type, uint32_t name > return -1; > } > > - btf_elf__log_type(btfe, &t.type, false, false, "type=%u name=%s", > + btf_elf__log_type(btfe, &t.type, false, false, "type=%u name=%s\n", > t.type.type, btf_elf__name_in_gobuf(btfe, t.type.name_off)); > > return btfe->type_index; > -- > 2.28.0.297.g1956fa8f8d-goog > -- - Arnaldo