To handle outputting all variables generally, we'll need to store more section data. Create a table of ELF sections so we can refer to all the cached data. Signed-off-by: Stephen Brennan <stephen.s.brennan@xxxxxxxxxx> --- btf_encoder.c | 68 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/btf_encoder.c b/btf_encoder.c index bf59962..f67738a 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -38,6 +38,7 @@ struct elf_function { }; #define MAX_VAR_CNT 4096 +#define MAX_ELF_SEC_CNT 128 struct var_info { uint64_t addr; @@ -45,6 +46,13 @@ struct var_info { uint32_t sz; }; +struct elf_secinfo { + uint64_t addr; + const char *name; + uint64_t sz; + bool include; +}; + struct btf_encoder { struct list_head node; struct btf *btf; @@ -60,12 +68,12 @@ struct btf_encoder { gen_floats, is_rel; uint32_t array_index_id; + struct elf_secinfo secinfo[MAX_ELF_SEC_CNT]; + size_t seccnt; struct { struct var_info vars[MAX_VAR_CNT]; int var_cnt; uint32_t percpu_shndx; - uint64_t percpu_base_addr; - uint64_t percpu_sec_sz; } variables; struct { struct elf_function *entries; @@ -1167,12 +1175,13 @@ static int btf_encoder__collect_percpu_var(struct btf_encoder *encoder, GElf_Sym if (encoder->verbose) printf("Found per-CPU symbol '%s' at address 0x%" PRIx64 "\n", sym_name, addr); - /* Make sure addr is section-relative. For kernel modules (which are - * ET_REL files) this is already the case. For vmlinux (which is an - * ET_EXEC file) we need to subtract the section address. + /* Make sure addr is absolute, so that we can compare it to DWARF + * absolute addresses. We can compute to section-relative addresses + * when necessary. */ - if (!encoder->is_rel) - addr -= encoder->variables.percpu_base_addr; + if (encoder->is_rel && sym->st_shndx < encoder->seccnt) { + addr += encoder->secinfo[sym->st_shndx].addr; + } if (encoder->variables.var_cnt == MAX_VAR_CNT) { fprintf(stderr, "Reached the limit of per-CPU variables: %d\n", @@ -1238,6 +1247,7 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder, struct uint32_t core_id; struct tag *pos; int err = -1; + struct elf_secinfo *pcpu_scn = &encoder->secinfo[encoder->variables.percpu_shndx]; if (encoder->variables.percpu_shndx == 0 || !encoder->symtab) return 0; @@ -1265,14 +1275,9 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder, struct addr = var->ip.addr; dwarf_name = variable__name(var); - /* Make sure addr is section-relative. DWARF, unlike ELF, - * always contains virtual symbol addresses, so subtract - * the section address unconditionally. - */ - if (addr < encoder->variables.percpu_base_addr || - addr >= encoder->variables.percpu_base_addr + encoder->variables.percpu_sec_sz) + /* Make sure addr is in the percpu section */ + if (addr < pcpu_scn->addr || addr >= pcpu_scn->addr + pcpu_scn->sz) continue; - addr -= encoder->variables.percpu_base_addr; if (!btf_encoder__percpu_var_exists(encoder, addr, &size, &name)) continue; /* not a per-CPU variable */ @@ -1347,7 +1352,7 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder, struct * add a BTF_VAR_SECINFO in encoder->percpu_secinfo, which will be added into * encoder->types later when we add BTF_VAR_DATASEC. */ - id = btf_encoder__add_var_secinfo(encoder, id, addr, size); + id = btf_encoder__add_var_secinfo(encoder, id, addr - pcpu_scn->addr, size); if (id < 0) { fprintf(stderr, "error: failed to encode section info for variable '%s' at addr 0x%" PRIx64 "\n", name, addr); @@ -1411,20 +1416,35 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam goto out; } - /* find percpu section's shndx */ + /* index the ELF sections for later lookup */ GElf_Shdr shdr; - Elf_Scn *sec = elf_section_by_name(cu->elf, &shdr, PERCPU_SECTION, NULL); + size_t shndx; + if (elf_getshdrnum(cu->elf, &encoder->seccnt)) + goto out_delete; + if (encoder->seccnt >= MAX_ELF_SEC_CNT) { + fprintf(stderr, "%s: reached limit of ELF sections\n", __func__); + goto out_delete; + } - if (!sec) { - if (encoder->verbose) - printf("%s: '%s' doesn't have '%s' section\n", __func__, cu->filename, PERCPU_SECTION); - } else { - encoder->variables.percpu_shndx = elf_ndxscn(sec); - encoder->variables.percpu_base_addr = shdr.sh_addr; - encoder->variables.percpu_sec_sz = shdr.sh_size; + for (shndx = 0; shndx < encoder->seccnt; shndx++) { + const char *secname = NULL; + Elf_Scn *sec = elf_section_by_idx(cu->elf, &shdr, shndx, &secname); + if (!sec) + goto out_delete; + encoder->secinfo[shndx].addr = shdr.sh_addr; + encoder->secinfo[shndx].sz = shdr.sh_size; + encoder->secinfo[shndx].name = secname; + + if (strcmp(secname, PERCPU_SECTION) == 0) { + encoder->variables.percpu_shndx = shndx; + encoder->secinfo[shndx].include = true; + } } + if (!encoder->variables.percpu_shndx && encoder->verbose) + printf("%s: '%s' doesn't have '%s' section\n", __func__, cu->filename, PERCPU_SECTION); + if (btf_encoder__collect_symbols(encoder, !encoder->skip_encoding_vars)) goto out_delete; -- 2.34.1