fix(native): resolve symbols from split-debug files on Linux#1836
Open
tustanivsky wants to merge 6 commits into
Open
fix(native): resolve symbols from split-debug files on Linux#1836tustanivsky wants to merge 6 commits into
tustanivsky wants to merge 6 commits into
Conversation
The crash daemon resolved frame symbols by picking the nearest preceding entry from the module's .dynsym without bounding the match by st_size. For binaries stripped of their .symtab (the norm for release builds that ship a split-debug companion), most addresses fall into gaps between exported symbols and got attributed to unrelated neighboring functions, producing plausible-looking but wrong stacktraces. - Require the target address to lie within [st_value, st_value + st_size) instead of accepting the nearest preceding symbol; an unresolved frame beats a wrong name. - Prefer .symtab over .dynsym (it is a superset when present). - When the module has no .symtab, follow the .gnu_debuglink section per the GDB split-debug conventions (<dir>/<name>, <dir>/.debug/<name>, /usr/lib/debug/<dir>/<name>), validating candidates by GNU build-id equality, and read the full symbol table from the companion file. - Cache the resolved symbol-table source per module and scan the table in fixed-size chunks, reading only the winning name from the string table, so large debug companions are never loaded into memory wholesale.
4f51e99 to
190421f
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 190421f. Configure here.
The symbol-source cache was a bounded 64-slot table keyed by module name; once full, further modules got no symbolication. Direct-map it by module index instead, sized to the module cap. Being BSS, only touched slots are committed, and the name key (now redundant) is dropped.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

This PR fixes invalid stacktraces produced by the crash daemon on Linux for binaries that were stripped of their
.symtab- the standard layout for release builds that ship a separate debug file (e.g. Unreal Engine, which runsobjcopy --strip-allpost-link and stores symbols in a.gnu_debuglinkcompanion).Since #1764, the daemon resolved frame names by picking the nearest preceding entry from the module's
.dynsymwithout bounding the match byst_size. For stripped binaries the dynamic table covers only exported symbols (small fraction of all functions in a UE title), so most addresses fall into gaps between exported symbols and get attributed to unrelated neighboring functions.Key Changes
st_size: a symbol only matches when the target address lies within [st_value, st_value + st_size). An unresolved frame (bare instruction_addr) beats a wrong name..symtabover.dynsym: the full table is a superset when present; the previous preference order was backwards for executables..gnu_debuglink: when the module has no.symtab, search for the split-debug companion per the GDB conventions (<dir>/<name>,<dir>/.debug/<name>,/usr/lib/debug/<dir>/<name>) and read its full symbol table. Candidates are validated by GNU build-id equality; when either file lacks a build-id, the candidate is accepted without CRC verification.No changes to unwinding: the frame addresses were already correct (pre-captured DWARF backtrace), only their naming was wrong. #1747's remote unwinding for non-crashed threads is untouched (libunwind already bounds its lookups internally).
Testing
Checked manually against UE 5.7.4 sample project build on Ubuntu 26.04 LTS:
Related items