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 @@ -609,6 +609,23 @@ ParsingState State(this); + bool SeenBadLineRange = false; + auto ReportBadLineRange = [&SeenBadLineRange, DebugLineOffset, + RecoverableErrorHandler](uint64_t Offset) { + // Only report the first bad line range instance, to avoid producing many + // errors if there are lots of special opcodes. + if (SeenBadLineRange) + return; + SeenBadLineRange = true; + RecoverableErrorHandler(createStringError( + errc::invalid_argument, + "line table program with offset 0x%8.8" PRIx64 + " contains a special opcode or DW_LNS_const_add_pc opcode at offset " + "0x%8.8" PRIx64 ", but the prologue line_range is 0. The address and " + "line will not be adjusted", + DebugLineOffset, Offset)); + }; + while (*OffsetPtr < EndOffset) { if (OS) *OS << format("0x%08.08" PRIx64 ": ", *OffsetPtr); @@ -845,8 +862,12 @@ // and a special opcode, requiring three or more bytes. { uint8_t AdjustOpcode = 255 - Prologue.OpcodeBase; - uint64_t AddrOffset = - (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; + uint64_t AddrOffset = 0; + if (Prologue.LineRange == 0) + ReportBadLineRange(*OffsetPtr - 1); + else + AddrOffset = + (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; State.Row.Address.Address += AddrOffset; if (OS) *OS @@ -944,12 +965,17 @@ // line increment = line_base + (adjusted opcode % line_range) uint8_t AdjustOpcode = Opcode - Prologue.OpcodeBase; - uint64_t AddrOffset = - (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; - int32_t LineOffset = - Prologue.LineBase + (AdjustOpcode % Prologue.LineRange); - State.Row.Line += LineOffset; - State.Row.Address.Address += AddrOffset; + uint64_t AddrOffset = 0; + int32_t LineOffset = 0; + if (Prologue.LineRange == 0) + ReportBadLineRange(*OffsetPtr - 1); + else { + AddrOffset = + (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; + LineOffset = Prologue.LineBase + (AdjustOpcode % Prologue.LineRange); + State.Row.Line += LineOffset; + State.Row.Address.Address += AddrOffset; + } if (OS) { *OS << "address += " << AddrOffset << ", line += " << 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 @@ -763,6 +763,116 @@ EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u); } +TEST_F(DebugLineBasicFixture, + ReportLineRangeZeroForSpecialAndConstAddPCOpcodes) { + if (!setupGenerator()) + return; + + LineTable &Padding = Gen->addLineTable(); + Padding.setCustomPrologue({{0, LineTable::Byte}}); + + // Show that no warning is generated for the case where no DW_LNS_const_add_pc + // or special opcode is used. + LineTable &NoProblem = Gen->addLineTable(); + NoProblem.addExtendedOpcode(9, DW_LNE_set_address, + {{0xabcd, LineTable::Quad}}); + NoProblem.addStandardOpcode(DW_LNS_copy, {}); + // Change the address, so that we have a valid sequence. + NoProblem.addExtendedOpcode(9, DW_LNE_set_address, + {{0xabce, LineTable::Quad}}); + NoProblem.addExtendedOpcode(1, DW_LNE_end_sequence, {}); + DWARFDebugLine::Prologue NoProblemProlgoue = NoProblem.createBasicPrologue(); + NoProblemProlgoue.LineRange = 0; + NoProblem.setPrologue(NoProblemProlgoue); + + // Show that the warning is emitted for the first DW_LNS_const_add_pc opcode + // and then not again. + LineTable &ConstAddPCFirst = Gen->addLineTable(); + uint64_t Addr1 = 0x1234; + ConstAddPCFirst.addExtendedOpcode(9, DW_LNE_set_address, + {{Addr1, LineTable::Quad}}); + ConstAddPCFirst.addStandardOpcode(DW_LNS_const_add_pc, {}); + ConstAddPCFirst.addStandardOpcode(DW_LNS_const_add_pc, {}); + ConstAddPCFirst.addByte(0xaa); // Special opcode. + // Change the address, so that we have a valid sequence. + ConstAddPCFirst.addExtendedOpcode(9, DW_LNE_set_address, + {{Addr1 + 1, LineTable::Quad}}); + ConstAddPCFirst.addExtendedOpcode(1, DW_LNE_end_sequence, {}); + DWARFDebugLine::Prologue AddPCPrologue = + ConstAddPCFirst.createBasicPrologue(); + AddPCPrologue.LineRange = 0; + ConstAddPCFirst.setPrologue(AddPCPrologue); + + // Show that the warning is emitted for the first special opcode and then not + // again. + LineTable &SpecialFirst = Gen->addLineTable(); + uint64_t Addr2 = 0x5678; + SpecialFirst.addExtendedOpcode(9, DW_LNE_set_address, + {{Addr2, LineTable::Quad}}); + SpecialFirst.addByte(0xaa); // Special opcode. + SpecialFirst.addStandardOpcode(DW_LNS_const_add_pc, {}); + SpecialFirst.addByte(0xbb); // Special opcode. + // Change the address, so that we have a valid sequence. + SpecialFirst.addExtendedOpcode(9, DW_LNE_set_address, + {{Addr2 + 1, LineTable::Quad}}); + SpecialFirst.addExtendedOpcode(1, DW_LNE_end_sequence, {}); + DWARFDebugLine::Prologue SpecialPrologue = SpecialFirst.createBasicPrologue(); + SpecialPrologue.LineRange = 0; + SpecialFirst.setPrologue(SpecialPrologue); + + generate(); + + auto ExpectedNoProblem = Line.getOrParseLineTable(LineData, 1, *Context, + nullptr, RecordRecoverable); + EXPECT_THAT_ERROR(std::move(Recoverable), Succeeded()); + EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded()); + ASSERT_THAT_EXPECTED(ExpectedNoProblem, Succeeded()); + + uint64_t NextOffset = 1 + (*ExpectedNoProblem)->Prologue.TotalLength + + (*ExpectedNoProblem)->Prologue.sizeofTotalLength(); + auto ExpectedConstAddPC = Line.getOrParseLineTable( + LineData, NextOffset, *Context, nullptr, RecordRecoverable); + ASSERT_THAT_EXPECTED(ExpectedConstAddPC, Succeeded()); + uint64_t ExpectedOffset = NextOffset + + (*ExpectedConstAddPC)->Prologue.getLength() + + 11; // 11 == size of DW_LNE_set_address. + checkError(("line table program with offset 0x000000" + + Twine::utohexstr(NextOffset) + + " contains a special opcode or DW_LNS_const_add_pc opcode at " + "offset 0x000000" + + Twine::utohexstr(ExpectedOffset) + + ", but the prologue line_range is 0. The address and line will " + "not be adjusted") + .str(), + std::move(Recoverable)); + EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded()); + ASSERT_EQ((*ExpectedConstAddPC)->Rows.size(), 2u); + EXPECT_EQ((*ExpectedConstAddPC)->Rows[0].Address.Address, Addr1); + EXPECT_EQ((*ExpectedConstAddPC)->Rows[0].Line, 1u); + + NextOffset = NextOffset + (*ExpectedConstAddPC)->Prologue.TotalLength + + (*ExpectedConstAddPC)->Prologue.sizeofTotalLength(); + auto ExpectedSpecial = Line.getOrParseLineTable( + LineData, NextOffset, *Context, nullptr, RecordRecoverable); + ASSERT_THAT_EXPECTED(ExpectedSpecial, Succeeded()); + ExpectedOffset = NextOffset + (*ExpectedSpecial)->Prologue.getLength() + + 11; // 11 == size of DW_LNE_set_address. + checkError(("line table program with offset 0x000000" + + Twine::utohexstr(NextOffset) + + " contains a special opcode or DW_LNS_const_add_pc opcode at " + "offset 0x000000" + + Twine::utohexstr(ExpectedOffset) + + ", but the prologue line_range is 0. The address and line will " + "not be adjusted") + .str(), + std::move(Recoverable)); + ASSERT_EQ((*ExpectedSpecial)->Rows.size(), 3u); + EXPECT_EQ((*ExpectedSpecial)->Rows[0].Address.Address, Addr2); + EXPECT_EQ((*ExpectedSpecial)->Rows[0].Line, 1u); + EXPECT_EQ((*ExpectedSpecial)->Rows[1].Address.Address, Addr2); + EXPECT_EQ((*ExpectedSpecial)->Rows[1].Line, 1u); +} + TEST_F(DebugLineBasicFixture, ParserParsesCorrectly) { if (!setupGenerator()) return;