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 @@ -401,6 +401,7 @@ uint64_t LineTableOffset; bool ReportAdvanceAddrProblem = true; + bool ReportBadLineRange = true; function_ref ErrorHandler; }; 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 @@ -603,11 +603,27 @@ uint64_t OpcodeOffset) { assert(Opcode == DW_LNS_const_add_pc || Opcode >= LineTable->Prologue.OpcodeBase); + if (ReportBadLineRange && LineTable->Prologue.LineRange == 0) { + StringRef OpcodeName = + getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase); + ErrorHandler( + createStringError(errc::not_supported, + "line table program at offset 0x%8.8" PRIx64 + " contains a %s opcode at offset 0x%8.8" PRIx64 + ", but the prologue line_range value is 0. The " + "address and line will not be adjusted", + LineTableOffset, OpcodeName.data(), OpcodeOffset)); + ReportBadLineRange = false; + } + uint8_t OpcodeValue = Opcode; if (Opcode == DW_LNS_const_add_pc) OpcodeValue = 255; uint8_t AdjustedOpcode = OpcodeValue - LineTable->Prologue.OpcodeBase; - uint64_t OperationAdvance = AdjustedOpcode / LineTable->Prologue.LineRange; + uint64_t OperationAdvance = + LineTable->Prologue.LineRange != 0 + ? AdjustedOpcode / LineTable->Prologue.LineRange + : 0; uint64_t AddrOffset = advanceAddr(OperationAdvance, Opcode, OpcodeOffset); return {AddrOffset, AdjustedOpcode}; } @@ -648,9 +664,11 @@ DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode AddrAdvanceResult = advanceAddrForOpcode(Opcode, OpcodeOffset); - int32_t LineOffset = - LineTable->Prologue.LineBase + - (AddrAdvanceResult.AdjustedOpcode % LineTable->Prologue.LineRange); + int32_t LineOffset = 0; + if (LineTable->Prologue.LineRange != 0) + LineOffset = + LineTable->Prologue.LineBase + + (AddrAdvanceResult.AdjustedOpcode % LineTable->Prologue.LineRange); Row.Line += LineOffset; return {AddrAdvanceResult.AddrDelta, LineOffset}; } diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp @@ -961,6 +961,46 @@ std::make_tuple( 4, 2, true)), ); // Test one higher than permitted V4 (error). +struct LineRangeFixture : TestWithParam>, + AdjustAddressFixtureBase { + void SetUp() override { std::tie(LineRange, IsErrorExpected) = GetParam(); } + + uint64_t editPrologue(LineTable <) override { + DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue(); + Prologue.LineRange = LineRange; + LT.setPrologue(Prologue); + return Prologue.TotalLength + Prologue.sizeofTotalLength(); + } + + uint64_t getAdjustedAddr(uint64_t Base, uint64_t ConstIncr, + uint64_t SpecialIncr, + uint64_t AdvanceIncr) override { + if (LineRange == 0) + return Base + AdvanceIncr; + return AdjustAddressFixtureBase::getAdjustedAddr(Base, ConstIncr, + SpecialIncr, AdvanceIncr); + } + + uint64_t getAdjustedLine(uint64_t Base, uint64_t Incr) override { + return LineRange != 0 + ? AdjustAddressFixtureBase::getAdjustedLine(Base, Incr) + : Base; + } + + uint8_t LineRange; +}; + +TEST_P(LineRangeFixture, LineRangeProblemsReportedCorrectly) { + runTest(/*CheckAdvancePC=*/false, + "but the prologue line_range value is 0. The address and line will " + "not be adjusted"); +} + +INSTANTIATE_TEST_CASE_P( + LineRangeParams, LineRangeFixture, + Values(std::make_tuple(0, true), // Test zero value (error). + std::make_tuple(14, false)), ); // Test non-zero value (no error). + TEST_F(DebugLineBasicFixture, ParserParsesCorrectly) { if (!setupGenerator()) return;