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 @@ -632,7 +632,9 @@ // from the size of the operand. { uint8_t ExtractorAddressSize = DebugLineData.getAddressSize(); - if (ExtractorAddressSize != Len - 1 && ExtractorAddressSize != 0) + uint64_t OpcodeAddressSize = Len - 1; + if (ExtractorAddressSize != OpcodeAddressSize && + ExtractorAddressSize != 0) RecoverableErrorCallback(createStringError( errc::invalid_argument, "mismatching address size at offset 0x%8.8" PRIx64 @@ -640,14 +642,25 @@ ExtOffset, ExtractorAddressSize, Len - 1)); // Assume that the line table is correct and temporarily override the - // address size. - DebugLineData.setAddressSize(Len - 1); - State.Row.Address.Address = DebugLineData.getRelocatedAddress( - OffsetPtr, &State.Row.Address.SectionIndex); - - // Restore the address size if the extractor already had it. - if (ExtractorAddressSize != 0) - DebugLineData.setAddressSize(ExtractorAddressSize); + // address size. If the size is unsupported, give up trying to read + // the address and continue to the next opcode. + if (OpcodeAddressSize != 4 && OpcodeAddressSize != 8) { + RecoverableErrorCallback(createStringError( + errc::invalid_argument, + "address size 0x%2.2" PRIx64 + " of DW_LNE_set_address opcode at offset 0x%8.8" PRIx64 + " is unsupported", + OpcodeAddressSize, ExtOffset)); + *OffsetPtr += OpcodeAddressSize; + } else { + DebugLineData.setAddressSize(OpcodeAddressSize); + State.Row.Address.Address = DebugLineData.getRelocatedAddress( + OffsetPtr, &State.Row.Address.SectionIndex); + + // Restore the address size if the extractor already had it. + if (ExtractorAddressSize != 0) + DebugLineData.setAddressSize(ExtractorAddressSize); + } if (OS) *OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address.Address); 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 @@ -621,6 +621,90 @@ EXPECT_EQ((*ExpectedLineTable)->Rows[1].Address.Address, Addr2); } +TEST_F(DebugLineBasicFixture, + ErrorForUnsupportedAddressSizeInSetAddressLength) { + // Use DWARF v4, and 0 for data extractor address size so that the address + // size is derived from the opcode length. + if (!setupGenerator(4, 0)) + return; + + LineTable < = Gen->addLineTable(); + LT.addExtendedOpcode(2, DW_LNE_set_address, {{0x42, LineTable::Byte}}); + LT.addStandardOpcode(DW_LNS_copy, {}); + LT.addByte(0xaa); + LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); + + generate(); + + auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, + nullptr, RecordRecoverable); + checkError( + "address size 0x01 of DW_LNE_set_address opcode at offset 0x00000030 is " + "unsupported", + std::move(Recoverable)); + ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); + ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 3u); + EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u); + // Show that the set address opcode is ignored in this case. + EXPECT_EQ((*ExpectedLineTable)->Rows[0].Address.Address, 0); +} + +TEST_F(DebugLineBasicFixture, ErrorForAddressSizeGreaterThanByteSize) { + // Use DWARF v4, and 0 for data extractor address size so that the address + // size is derived from the opcode length. + if (!setupGenerator(4, 0)) + return; + + LineTable < = Gen->addLineTable(); + // Specifically use an operand size that has a trailing byte of a supported + // size (8), so that any potential truncation would result in a valid size. + std::vector Operands(0x108); + LT.addExtendedOpcode(Operands.size() + 1, DW_LNE_set_address, Operands); + LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); + + generate(); + + auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, + nullptr, RecordRecoverable); + checkError( + "address size 0x108 of DW_LNE_set_address opcode at offset 0x00000031 is " + "unsupported", + std::move(Recoverable)); + ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); +} + +TEST_F(DebugLineBasicFixture, ErrorForUnsupportedAddressSizeDefinedInHeader) { + // Use 0 for data extractor address size so that it does not clash with the + // header address size. + if (!setupGenerator(5, 0)) + return; + + LineTable < = Gen->addLineTable(); + uint8_t AddressSize = 9; + LT.addExtendedOpcode(AddressSize + 1, DW_LNE_set_address, + {{0x12345678, LineTable::Quad}, {0, LineTable::Byte}}); + LT.addStandardOpcode(DW_LNS_copy, {}); + LT.addByte(0xaa); + LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); + DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue(); + Prologue.FormParams.AddrSize = AddressSize; + LT.setPrologue(Prologue); + + generate(); + + auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, + nullptr, RecordRecoverable); + checkError( + "address size 0x09 of DW_LNE_set_address opcode at offset 0x00000035 is " + "unsupported", + std::move(Recoverable)); + ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); + ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 3u); + EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u); + // Show that the set address opcode is ignored in this case. + EXPECT_EQ((*ExpectedLineTable)->Rows[0].Address.Address, 0); +} + TEST_F(DebugLineBasicFixture, CallbackUsedForUnterminatedSequence) { if (!setupGenerator()) return; diff --git a/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h b/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h --- a/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h +++ b/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h @@ -171,8 +171,8 @@ enum ValueLength { Byte = 1, Half = 2, Long = 4, Quad = 8, ULEB, SLEB }; struct ValueAndLength { - uint64_t Value; - ValueLength Length; + uint64_t Value = 0; + ValueLength Length = Byte; }; LineTable(uint16_t Version, dwarf::DwarfFormat Format, uint8_t AddrSize,