diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -355,6 +355,7 @@ private: DWARFUnit *prepareToParse(uint64_t Offset); void moveToNextTable(uint64_t OldOffset, const Prologue &P); + bool lineTableHeaderHasValidVersion(uint64_t Offset); LineToUnitMap LineToUnit; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -1505,6 +1505,15 @@ return U; } +bool DWARFDebugLine::SectionParser::lineTableHeaderHasValidVersion( + uint64_t Offset) { + DataExtractor::Cursor Cursor(Offset); + auto [TotalLength, _] = DebugLineData.getInitialLength(Cursor); + DWARFDataExtractor HeaderData(DebugLineData, Cursor.tell() + TotalLength); + uint16_t Version = DebugLineData.getU16(Cursor); + return versionIsSupported(Version); +} + void DWARFDebugLine::SectionParser::moveToNextTable(uint64_t OldOffset, const Prologue &P) { // If the length field is not valid, we don't know where the next table is, so @@ -1518,5 +1527,30 @@ Offset = OldOffset + P.TotalLength + P.sizeofTotalLength(); if (!DebugLineData.isValidOffset(Offset)) { Done = true; + return; + } + + // Heuristic: If the version is valid, then this is probably a line table, + // otherwise the offset might need alignment. + if (lineTableHeaderHasValidVersion(Offset)) + return; + + // Certain compilers align each line table to word boundaries and pad out the + // .debug_line section to a word multiple. Note that in the specification this + // does not seem forbidden since each unit as a DW_AT_stmt_list. + std::array PossibleAlignments{4, 8}; + for (unsigned Align : PossibleAlignments) { + uint64_t AlignedOffset = + (Offset + (Align - 1)) & ~static_cast(Align - 1); + if (!DebugLineData.isValidOffset(AlignedOffset)) { + // This is almost certainly not another line table but some alignment + // padding. + Done = true; + return; + } + if (lineTableHeaderHasValidVersion(AlignedOffset)) { + Offset = AlignedOffset; + break; + } } }