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 @@ -406,11 +406,14 @@ /// Get the adjusted opcode and operation advance for a given special /// opcode value. - AdvanceAddrProperties getOperationAdvance(uint8_t Opcode); + AdvanceAddrProperties getOperationAdvance(uint8_t Opcode, + uint64_t OpcodeOffset, + StringRef OpcodeName); 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 @@ -569,13 +569,26 @@ } DWARFDebugLine::ParsingState::AdvanceAddrProperties -DWARFDebugLine::ParsingState::getOperationAdvance(uint8_t Opcode) { +DWARFDebugLine::ParsingState::getOperationAdvance(uint8_t Opcode, + uint64_t OpcodeOffset, + StringRef OpcodeName) { assert(Opcode >= LineTable->Prologue.OpcodeBase && "special opcode value is lower than opcode_base"); + if (ReportBadLineRange && LineTable->Prologue.LineRange == 0) + 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; AdvanceAddrProperties Result; Result.AdjustedOpcode = Opcode - LineTable->Prologue.OpcodeBase; Result.OperationAdvance = - Result.AdjustedOpcode / LineTable->Prologue.LineRange; + LineTable->Prologue.LineRange != 0 + ? Result.AdjustedOpcode / LineTable->Prologue.LineRange + : 0; return Result; } @@ -605,7 +618,8 @@ DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode, uint64_t OpcodeOffset, StringRef OpcodeName) { - AdvanceAddrProperties AdvanceProps = getOperationAdvance(Opcode); + AdvanceAddrProperties AdvanceProps = + getOperationAdvance(Opcode, OpcodeOffset, OpcodeName); uint64_t AddrOffset = advanceAddr(AdvanceProps.OperationAdvance, OpcodeOffset, OpcodeName); return {AddrOffset, AdvanceProps.AdjustedOpcode}; @@ -647,9 +661,11 @@ DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode AddrAdvanceResult = advanceAddrForOpcode(Opcode, OpcodeOffset, "special"); - 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 : public TestWithParam>, + public 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;