Currently we maintain one buffer of DATASEC entries that describe the offsets for variables in the percpu ELF section. In order to make it possible to output all global variables, we'll need to output a DATASEC for each ELF section containing variables, and we'll need to control whether or not to encode variables on a per-section basis. With this change, the ability to emit VARs from multiple sections is technically present, but not enabled, so pahole still only emits percpu variables. A subsequent change will enable emitting all global variables. Signed-off-by: Stephen Brennan <stephen.s.brennan@xxxxxxxxxx> --- btf_encoder.c | 90 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/btf_encoder.c b/btf_encoder.c index 1872e00..2fd1648 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -98,6 +98,8 @@ struct elf_secinfo { const char *name; uint64_t sz; uint32_t type; + bool include; + struct gobuffer secinfo; }; /* @@ -107,7 +109,6 @@ struct btf_encoder { struct list_head node; struct btf *btf; struct cu *cu; - struct gobuffer percpu_secinfo; const char *source_filename; const char *filename; struct elf_symtab *symtab; @@ -124,7 +125,6 @@ struct btf_encoder { uint32_t array_index_id; struct elf_secinfo *secinfo; size_t seccnt; - size_t percpu_shndx; int encode_vars; struct { struct elf_function *entries; @@ -784,46 +784,56 @@ static int32_t btf_encoder__add_var(struct btf_encoder *encoder, uint32_t type, return id; } -static int32_t btf_encoder__add_var_secinfo(struct btf_encoder *encoder, uint32_t type, - uint32_t offset, uint32_t size) +static int32_t btf_encoder__add_var_secinfo(struct btf_encoder *encoder, size_t shndx, + uint32_t type, uint32_t offset, uint32_t size) { struct btf_var_secinfo si = { .type = type, .offset = offset, .size = size, }; - return gobuffer__add(&encoder->percpu_secinfo, &si, sizeof(si)); + return gobuffer__add(&encoder->secinfo[shndx].secinfo, &si, sizeof(si)); } int32_t btf_encoder__add_encoder(struct btf_encoder *encoder, struct btf_encoder *other) { - struct gobuffer *var_secinfo_buf = &other->percpu_secinfo; - size_t sz = gobuffer__size(var_secinfo_buf); - uint16_t nr_var_secinfo = sz / sizeof(struct btf_var_secinfo); - uint32_t type_id; - uint32_t next_type_id = btf__type_cnt(encoder->btf); - int32_t i, id; - struct btf_var_secinfo *vsi; - + size_t shndx; if (encoder == other) return 0; btf_encoder__add_saved_funcs(other); - for (i = 0; i < nr_var_secinfo; i++) { - vsi = (struct btf_var_secinfo *)var_secinfo_buf->entries + i; - type_id = next_type_id + vsi->type - 1; /* Type ID starts from 1 */ - id = btf_encoder__add_var_secinfo(encoder, type_id, vsi->offset, vsi->size); - if (id < 0) - return id; + for (shndx = 0; shndx < other->seccnt; shndx++) { + struct gobuffer *var_secinfo_buf = &other->secinfo[shndx].secinfo; + size_t sz = gobuffer__size(var_secinfo_buf); + uint16_t nr_var_secinfo = sz / sizeof(struct btf_var_secinfo); + uint32_t type_id; + uint32_t next_type_id = btf__type_cnt(encoder->btf); + int32_t i, id; + struct btf_var_secinfo *vsi; + + if (strcmp(encoder->secinfo[shndx].name, other->secinfo[shndx].name)) { + fprintf(stderr, "mismatched ELF sections at index %zu: \"%s\", \"%s\"\n", + shndx, encoder->secinfo[shndx].name, other->secinfo[shndx].name); + return -1; + } + + for (i = 0; i < nr_var_secinfo; i++) { + vsi = (struct btf_var_secinfo *)var_secinfo_buf->entries + i; + type_id = next_type_id + vsi->type - 1; /* Type ID starts from 1 */ + id = btf_encoder__add_var_secinfo(encoder, shndx, type_id, vsi->offset, vsi->size); + if (id < 0) + return id; + } } return btf__add_btf(encoder->btf, other->btf); } -static int32_t btf_encoder__add_datasec(struct btf_encoder *encoder, const char *section_name) +static int32_t btf_encoder__add_datasec(struct btf_encoder *encoder, size_t shndx) { - struct gobuffer *var_secinfo_buf = &encoder->percpu_secinfo; + struct gobuffer *var_secinfo_buf = &encoder->secinfo[shndx].secinfo; + const char *section_name = encoder->secinfo[shndx].name; struct btf *btf = encoder->btf; size_t sz = gobuffer__size(var_secinfo_buf); uint16_t nr_var_secinfo = sz / sizeof(struct btf_var_secinfo); @@ -2032,12 +2042,14 @@ int btf_encoder__encode(struct btf_encoder *encoder) { bool should_tag_kfuncs; int err; + size_t shndx; /* for single-threaded case, saved funcs are added here */ btf_encoder__add_saved_funcs(encoder); - if (gobuffer__size(&encoder->percpu_secinfo) != 0) - btf_encoder__add_datasec(encoder, PERCPU_SECTION); + for (shndx = 0; shndx < encoder->seccnt; shndx++) + if (gobuffer__size(&encoder->secinfo[shndx].secinfo)) + btf_encoder__add_datasec(encoder, shndx); /* Empty file, nothing to do, so... done! */ if (btf__type_cnt(encoder->btf) == 1) @@ -2167,7 +2179,7 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) struct tag *pos; int err = -1; - if (encoder->percpu_shndx == 0 || !encoder->symtab) + if (!encoder->symtab) return 0; if (encoder->verbose) @@ -2180,6 +2192,7 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) struct llvm_annotation *annot; const struct tag *tag; size_t shndx, size; + struct elf_secinfo *sec = NULL; uint64_t addr; int id; @@ -2211,7 +2224,9 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) /* Get the ELF section info for the variable */ shndx = get_elf_section(encoder, addr); - if (shndx != encoder->percpu_shndx) + if (shndx >= 0 && shndx < encoder->seccnt) + sec = &encoder->secinfo[shndx]; + if (!sec || !sec->include) continue; /* Convert addr to section relative */ @@ -2252,7 +2267,7 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) size = tag__size(tag, cu); if (size == 0 || size > UINT32_MAX) { if (encoder->verbose) - fprintf(stderr, "Ignoring %s-sized per-CPU variable '%s'...\n", + fprintf(stderr, "Ignoring %s-sized variable '%s'...\n", size == 0 ? "zero" : "over", name); continue; } @@ -2289,13 +2304,14 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) } /* - * add a BTF_VAR_SECINFO in encoder->percpu_secinfo, which will be added into - * encoder->types later when we add BTF_VAR_DATASEC. + * Add the variable to the secinfo for the section it appears in. + * Later we will generate a BTF_VAR_DATASEC for all any section with + * an encoded variable. */ - id = btf_encoder__add_var_secinfo(encoder, id, (uint32_t)addr, (uint32_t)size); + id = btf_encoder__add_var_secinfo(encoder, shndx, id, (uint32_t)addr, (uint32_t)size); if (id < 0) { fprintf(stderr, "error: failed to encode section info for variable '%s' at addr 0x%" PRIx64 "\n", - name, addr); + name, addr); goto out; } } @@ -2373,6 +2389,7 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam goto out_delete; } + bool found_percpu = false; for (shndx = 0; shndx < encoder->seccnt; shndx++) { const char *secname = NULL; Elf_Scn *sec = elf_section_by_idx(cu->elf, &shdr, shndx, &secname); @@ -2383,11 +2400,14 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam encoder->secinfo[shndx].name = secname; encoder->secinfo[shndx].type = shdr.sh_type; - if (strcmp(secname, PERCPU_SECTION) == 0) - encoder->percpu_shndx = shndx; + if (strcmp(secname, PERCPU_SECTION) == 0) { + found_percpu = true; + if (encoder->encode_vars & BTF_VAR_PERCPU) + encoder->secinfo[shndx].include = true; + } } - if (!encoder->percpu_shndx && encoder->verbose) + if (!found_percpu && encoder->verbose) printf("%s: '%s' doesn't have '%s' section\n", __func__, cu->filename, PERCPU_SECTION); if (btf_encoder__collect_symbols(encoder)) @@ -2415,12 +2435,14 @@ void btf_encoder__delete_func(struct elf_function *func) void btf_encoder__delete(struct btf_encoder *encoder) { int i; + size_t shndx; if (encoder == NULL) return; btf_encoders__delete(encoder); - __gobuffer__delete(&encoder->percpu_secinfo); + for (shndx = 0; shndx < encoder->seccnt; shndx++) + __gobuffer__delete(&encoder->secinfo[shndx].secinfo); zfree(&encoder->filename); zfree(&encoder->source_filename); btf__free(encoder->btf); -- 2.43.5