Skip to content

pfelf: load section names without mmap, and intern them - #1698

Draft
fabled wants to merge 1 commit into
open-telemetry:mainfrom
fabled:tt-pfelf-section-names
Draft

pfelf: load section names without mmap, and intern them#1698
fabled wants to merge 1 commit into
open-telemetry:mainfrom
fabled:tt-pfelf-section-names

Conversation

@fabled

@fabled fabled commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Memory and CPU benchmark of the coredump test suite indicates that interning the section names is a worthwhile action. The cost of interning is returned by reduced GC stress.

small step towards #1577

@fabled
fabled marked this pull request as ready for review July 29, 2026 14:22
@fabled
fabled requested review from a team as code owners July 29, 2026 14:23
Comment thread libpf/pfelf/file.go
return err
}

nameIndexToSection := make(map[uint32]*Section, hdr.Shnum)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep track of the section?

Suggested change
nameIndexToSection := make(map[uint32]*Section, hdr.Shnum)
nameIndexToSection := make(map[uint32][]*Section, hdr.Shnum)

I think, ELF files can have multiple sections that reference the same offset in shstrtab. Thinking about two .text sections produced by a linker script. The loop overwrites the map entry each time, so only the last *Section per uniquesh.Name offset is currently stored.

Comment thread libpf/pfelf/file.go
rdr := pfbufio.NewReader(f.elfReader, int64(strsh.Offset), int64(strsh.Size))
defer pfbufio.PutReader(rdr)

rdr.WalkAllStrings(func(offs int64, str string) error {

@christos68k christos68k Jul 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WalkAllStrings calls ReadString which advances the position in the buffer based on number of bytes read.

So the implicit assumption that WalkAllStrings makes is that strings are laid out cleanly one-after-another in memory, e.g.

FOO\0BAR\0BARBAR\0

But the indices into the section header string table don't require this, as one can have overlapping strings, e.g.

FOO\0BARBAR\0

See the example here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was aware of this. But I real life this is not seen. Also sections we care about start with . and are not substrings of each other, so this cannot either happen.

If correctness is needed for the obscure/unused cases, we could sort the headers based on name index, and then PeekString() and Discard() the bytes until next string starts.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, we can add a comment to make this obvious here for future reference.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll need to think about this a bit further. Similar problem is with symbol names - and those probably need better solution than this. Probably makes sense to use same method for all string tables. Returning this to a draft state for now.

Comment thread libpf/pfelf/file.go
rdr := pfbufio.NewReader(f.elfReader, int64(strsh.Offset), int64(strsh.Size))
defer pfbufio.PutReader(rdr)

rdr.WalkAllStrings(func(offs int64, str string) error {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, we can add a comment to make this obvious here for future reference.

@fabled
fabled marked this pull request as draft July 29, 2026 19:57
@christos68k
christos68k self-requested a review July 29, 2026 20:55
@fabled

fabled commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

So I've been studying this and the symbol table layout, as getting symbol and dynamic symbol names are similar problem.

It seems that the string tabs are as follows:

  • .shstrtab is typically individual strings in linear layout. Maximum I've seen is just under 0x200 bytes
  • .strtab is typically individual strings in linear layout. In debug info dumps they can be large, I've seen up to some megabytes.
  • .dynstr for the dynamic symbols is typically individual strings, but in completely random looking layout. Possibly due to the hashing requirement. The largest I found so far is libLLVM with about 3.5MB size.

I'm currently thinking to just cap the sizes at 4 MB or so, and load them directly to a temporary byte buffer. And arrange the code so that if strings are kept, they either are interned or cloned so the kept strings will not refer to the big buffer. If the temporary peaks or memory usage, or the string tab size limitation becomes an issue, it can be improved in the future.

The exceptions being likely the TLS visitor which likely should read individual strings (as it ever tries to read a few of them).

@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Aug 26, 2026

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-09-02 16:31 UTC

Move out of draft to request review.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants