Repository navigation
symbolize: fix legacy DWARF 5 reader for clang -gline-tables-only binaries - #270
Open
akasakariko wants to merge 1 commit into
Open
akasakariko wants to merge 1 commit into
akasakariko wants to merge 1 commit into
Conversation
…aries create_gcov aborted with "Check failed: str_offsets_buffer_ != NULL" on DWARF 5 binaries built by clang (e.g. LLVM 19 with -gline-tables-only -fdebug-info-for-profiling), because Google3Addr2line::Prepare() never loaded .debug_str_offsets, so every DW_FORM_strx* attribute hit the CHECK. Loading the section exposes further gaps in the legacy DWARF 5 path, all of which are hit by the same clang binaries: - The line-table readers were handed .debug_line_str in place of .debug_str and .debug_str_offsets (and dereferenced end() when .debug_line_str was absent). - DW_AT_str_offsets_base and DW_AT_addr_base follow the unit DIE attributes that use them (DW_AT_name as strx, DW_AT_low_pc as addrx), so every unit after the first resolved them against the first unit's contributions. This produced a wrong unit base address and therefore wrong DW_RLE_offset_pair inline ranges. Read both bases from the unit DIE before processing it, as LLVM does. - DWARF 5 line tables with DW_LNCT_MD5 (emitted by clang by default) were rejected as malformed, leaving no line information. Skip content types that are not needed, as the DWARF 5 spec intends. - DWARF 5 directory and file indices are 0-based, but were stored 1-based. File 0 / DW_AT_call_file 0 (clang) were dropped, which made GetInlineStack() dereference a null callsite file name, and GCC DWARF 5 file names were off by one. - A unit-level DW_AT_ranges using DW_FORM_rnglistx (clang with -ffunction-sections, C++, LTO) hit a CHECK. - SkipAttribute() did not know DW_FORM_line_strp. Also skip, instead of CHECK-failing on, strx attributes when .debug_str or .debug_str_offsets is missing or the index is outside the section. With this change the legacy symbolizer's inline stacks for clang 19 and GCC 15 DWARF 5 binaries match those for the same code compiled with DWARF 4, and match llvm-symbolizer on the new test binary. Fixes google#255.
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.
symbolize: fix legacy DWARF 5 reader for clang -gline-tables-only binaries
Fixes #255.
Problem
create_gcovaborts on any DWARF 5 binary built by clang (for example LLVM 19 with-gdwarf-5 -gline-tables-only -fdebug-info-for-profiling):As noted in the issue,
Google3Addr2line::Prepare()never loads.debug_str_offsets, so the firstDW_FORM_strx*attribute fails the CHECK. GCC usesstrp/line_strpforms, so it does not hit this.Loading the section stops the crash, but the output is still wrong on the same binaries, because several DWARF 5 paths were never exercised before. This PR fixes them too:
addr2line_inlinestack.ccandfunctioninfo.ccpassed.debug_line_strtoLineInfoas both.debug_strand.debug_str_offsets, and dereferencedend()when.debug_line_strwas absent.DW_AT_str_offsets_base/DW_AT_addr_baseafterDW_AT_name(strx) andDW_AT_low_pc(addrx). Every unit after the first therefore used the first unit's tables. The result was a wrong unit base address and wrongDW_RLE_offset_pairinline ranges. Both bases are now read from the unit DIE first (CompilationUnit::ReadUnitBases), as LLVM does.DW_LNCT_MD5: clang emits it by default, and it made the v5 line header "malformed", so there was no line info. Content types that are not needed are now skipped (LineInfo::SkipForm).DW_AT_call_file 0were dropped (which then caused a NULLcallsite_filename()dereference inGetInlineStack), and GCC DWARF 5 file names were off by one.DW_AT_rangeswithDW_FORM_rnglistx: C++,-ffunction-sectionsand ThinLTO builds hit a CHECK here.SkipAttribute: it did not handleDW_FORM_line_strp..debug_str/.debug_str_offsetsis missing or the index is out of bounds.I also checked the other DWARF 5 sections.
.debug_addr,.debug_rnglistsand.debug_line_strwere already loaded..debug_loclistsis not used by the symbolizer, andDW_FORM_loclistxis already skipped.Testing
New tests in
addr2line_test.cc:Dwarf5ClangLineTablesOnlyBinary: newtestdata/dwarf5_line_tables_only.bin(18 KB, 3 units). It was built by clang 19 from the committedtestdata/dwarf5_line_tables_only_*.csources; the command is in the test comment. The test checks full inline stacks at 5 addresses against values fromllvm-symbolizer --inlining. Without this patch the test aborts with the Crashes with str_offsets_buffer_ = NULL #255 CHECK.Dwarf5StrxUsesLaterStrOffsetsBase,Dwarf5StrxWithoutStrOffsetsSectionIsSkipped,Dwarf5StrxOutOfRangeIndexIsSkipped: synthetic units. Without this patch they fail, abort and fail respectively.Results:
make, as in CI). In both,ctestpasses 4/4 andaddr2line_testpasses 9/9. The tests also pass under ASan+UBSan.-gdwarf64), the C++ googletest samples, and a GCC 15 DWARF 5 build of Lua.testdata/dwarf2_dwarf5.bin(GCC): wrong file names drop from 194,301 frames to 0.create_gcovrun end to end (text profile) on a clang DWARF 5 binary: it used to abort and now writes a correct profile.Not tested: the
ENABLE_TOOL=LLVMconfiguration (llvm-project submodule not fetched locally) and realperf.datainput.