From: Stephen Brennan <stephen.s.brennan@oracle.com>
To: Alan Maguire <alan.maguire@oracle.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: dwarves@vger.kernel.org, linux-debuggers@vger.kernel.org
Subject: Re: [PATCH dwarves 3/4] btf_encoder: cache all ELF section info
Date: Fri, 13 Sep 2024 10:05:51 -0700 [thread overview]
Message-ID: <87wmjfmqkw.fsf@oracle.com> (raw)
In-Reply-To: <bf2a075b-1f30-475e-9d64-c96bbf646454@oracle.com>
Alan Maguire <alan.maguire@oracle.com> writes:
> On 12/09/2024 20:08, Stephen Brennan wrote:
>> 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, not just the percpu section.
>>
>> Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
>> ---
>> btf_encoder.c | 50 ++++++++++++++++++++++++++++++++++++--------------
>> 1 file changed, 36 insertions(+), 14 deletions(-)
>>
>> diff --git a/btf_encoder.c b/btf_encoder.c
>> index 8a2d92e..e3384e5 100644
>> --- a/btf_encoder.c
>> +++ b/btf_encoder.c
>> @@ -65,12 +65,20 @@ struct elf_function {
>> struct btf_encoder_state state;
>> };
>>
>> +#define MAX_ELF_SEC_CNT 128
>> +
>> struct var_info {
>> uint64_t addr;
>> const char *name;
>> uint32_t sz;
>> };
>>
>> +struct elf_secinfo {
>> + uint64_t addr;
>> + const char *name;
>> + uint64_t sz;
>> +};
>> +
>
> One thing we've run into before is hardcoded limits get exceeded on
> systems, and while it seems unlikely for 128 ELF sections, I think it'd
> be better to make this dynamic just in case. Also for parallel mode we
> have N encoders so it might same some memory (which we're pretty
> profligate with in other areas). I'd suggest using reallocarray_grow()
> as we do for functions. One thing we may want to tweak is that
> reallocarray_grow() will grow by 1000 or 1.5 x the current size;
> starting with 1000 ELF sections is a bit much. We could perhaps
> tweak reallocarray_grow() to have a min_growth parameter to control this
> and set it to something smaller for ELF sections, what do you think?
I agree that the static allocation doesn't make a ton of sense. To be
quite honest, I was lazy during the initial implementation and intended
to come back around to make this dynamically allocated.
I think the answer is to simply use elf_getshdrnum and directly allocate
the array to the size we need. I'll definitely do that in the next
version.
>> /*
>> * cu: cu being processed.
>> */
>> @@ -95,13 +103,13 @@ struct btf_encoder {
>> is_rel,
>> gen_distilled_base;
>> uint32_t array_index_id;
>> + struct elf_secinfo secinfo[MAX_ELF_SEC_CNT];
>
> ...so here we'd have a substructure like this
>
> struct {
> int allocated;
> int sec_cnt;
> struct elf_secinfo *sections;
> } elf_sections;
>
>> + size_t seccnt;
>> struct {
>> struct var_info *vars;
>> int var_cnt;
>> int allocated;
>> uint32_t shndx;
>> - uint64_t base_addr;
>> - uint64_t sec_sz;
>> } percpu;
>> struct {
>> struct elf_function *entries;
>> @@ -1849,7 +1857,7 @@ static int btf_encoder__collect_percpu_var(struct btf_encoder *encoder, GElf_Sym
>> * ET_EXEC file) we need to subtract the section address.
>> */
>> if (!encoder->is_rel)
>> - addr -= encoder->percpu.base_addr;
>> + addr -= encoder->secinfo[encoder->percpu.shndx].addr;
>>
> We will need some of these mechanics later when we encode function
> addresses; great to have this!
Ironically enough, this code (and especially, the is_rel field referred
to here) gets deleted in patch 4. Maybe I should have left is_rel if you
think we're going to need function addresses from the symbol table.
But patch 4 fully embraces simply using DWARF to get the variable
addresses, and it stops using the ELF symbol table for variables. The
DWARF addresses are always absolute. I couldn't really find a good
reason for using the symbol table, except maybe as a decent way to
filter out bogus variables that didn't actually become real data. For
example, the x86_64 percpu region starts at address 0, and many bogus
DWARF variables have address 0, so making sure the variable matched the
symbol at address 0 was a good way to filter bogus variables.
I didn't think it was a big deal that I removed this behavior, because
with improved variable filtering, this code continues to produce nearly
identical percpu DATASECs, with the only difference being that we now
(correctly) include the fixed_percpu_data variable for x86_64, which was
omitted before. So there's no regression in functionality.
Stephen
>> if (encoder->percpu.var_cnt == encoder->percpu.allocated) {
>> struct var_info *new;
>> @@ -1923,6 +1931,7 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder)
>> uint32_t core_id;
>> struct tag *pos;
>> int err = -1;
>> + struct elf_secinfo *pcpu_scn = &encoder->secinfo[encoder->percpu.shndx];
>>
>> if (encoder->percpu.shndx == 0 || !encoder->symtab)
>> return 0;
>> @@ -1954,9 +1963,9 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder)
>> * always contains virtual symbol addresses, so subtract
>> * the section address unconditionally.
>> */
>> - if (addr < encoder->percpu.base_addr || addr >= encoder->percpu.base_addr + encoder->percpu.sec_sz)
>> + if (addr < pcpu_scn->addr || addr >= pcpu_scn->addr + pcpu_scn->sz)
>> continue;
>> - addr -= encoder->percpu.base_addr;
>> + addr -= pcpu_scn->addr;
>>
>> if (!btf_encoder__percpu_var_exists(encoder, addr, &size, &name))
>> continue; /* not a per-CPU variable */
>> @@ -2099,20 +2108,33 @@ 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;
>> + }
>>
> as above we should just reallocarray_grow() more space.
>
>> - if (!sec) {
>> - if (encoder->verbose)
>> - printf("%s: '%s' doesn't have '%s' section\n", __func__, cu->filename, PERCPU_SECTION);
>> - } else {
>> - encoder->percpu.shndx = elf_ndxscn(sec);
>> - encoder->percpu.base_addr = shdr.sh_addr;
>> - encoder->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->percpu.shndx = shndx;
>> }
>>
>> + if (!encoder->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;
>>
next prev parent reply other threads:[~2024-09-13 17:06 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-12 19:08 [PATCH dwarves 0/4] Emit global variables in BTF Stephen Brennan
2024-09-12 19:08 ` [PATCH dwarves 1/4] dutil: return ELF section name when looked up by index Stephen Brennan
2024-09-13 13:26 ` Alan Maguire
2024-09-13 17:06 ` Stephen Brennan
2024-09-12 19:08 ` [PATCH dwarves 2/4] dwarf_loader: add "artificial" and "top_level" variable flags Stephen Brennan
2024-09-13 13:35 ` Alan Maguire
2024-09-13 17:16 ` Stephen Brennan
2024-09-12 19:08 ` [PATCH dwarves 3/4] btf_encoder: cache all ELF section info Stephen Brennan
2024-09-13 15:25 ` Alan Maguire
2024-09-13 17:05 ` Stephen Brennan [this message]
2024-09-15 11:26 ` Alan Maguire
2024-09-12 19:08 ` [PATCH dwarves 4/4] btf_encoder: add global_var feature to encode globals Stephen Brennan
2024-09-15 11:49 ` Alan Maguire
2024-09-20 8:18 ` Stephen Brennan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87wmjfmqkw.fsf@oracle.com \
--to=stephen.s.brennan@oracle.com \
--cc=acme@kernel.org \
--cc=alan.maguire@oracle.com \
--cc=dwarves@vger.kernel.org \
--cc=linux-debuggers@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).