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 @@ -690,6 +690,17 @@ return {AddrAdvanceResult.AddrDelta, LineOffset}; } +/// Parse a ULEB128 using the specified \p Cursor. \returns the parsed value on +/// success, or None if \p Cursor is in a failing state. +template +static Optional parseULEB128(DWARFDataExtractor &Data, + DataExtractor::Cursor &Cursor) { + T Value = Data.getULEB128(Cursor); + if (Cursor) + return Value; + return None; +} + Error DWARFDebugLine::LineTable::parse( DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, const DWARFContext &Ctx, const DWARFUnit *U, @@ -918,6 +929,7 @@ ExtOffset, Len, Cursor.tell() - ExtOffset)); *OffsetPtr = End; } else if (Opcode < Prologue.OpcodeBase) { + DataExtractor::Cursor Cursor(*OffsetPtr); if (Verbose) *OS << LNStandardString(Opcode); switch (Opcode) { @@ -938,9 +950,10 @@ // Takes a single unsigned LEB128 operand, multiplies it by the // min_inst_length field of the prologue, and adds the // result to the address register of the state machine. - { - uint64_t AddrOffset = State.advanceAddr( - TableData.getULEB128(OffsetPtr), Opcode, OpcodeOffset); + if (Optional Operand = + parseULEB128(TableData, Cursor)) { + uint64_t AddrOffset = + State.advanceAddr(*Operand, Opcode, OpcodeOffset); if (Verbose) *OS << " (" << AddrOffset << ")"; } @@ -949,25 +962,36 @@ case DW_LNS_advance_line: // Takes a single signed LEB128 operand and adds that value to // the line register of the state machine. - State.Row.Line += TableData.getSLEB128(OffsetPtr); - if (Verbose) - *OS << " (" << State.Row.Line << ")"; + { + int64_t LineDelta = TableData.getSLEB128(Cursor); + if (Cursor) { + State.Row.Line += LineDelta; + if (Verbose) + *OS << " (" << State.Row.Line << ")"; + } + } break; case DW_LNS_set_file: // Takes a single unsigned LEB128 operand and stores it in the file // register of the state machine. - State.Row.File = TableData.getULEB128(OffsetPtr); - if (Verbose) - *OS << " (" << State.Row.File << ")"; + if (Optional File = + parseULEB128(TableData, Cursor)) { + State.Row.File = *File; + if (Verbose) + *OS << " (" << State.Row.File << ")"; + } break; case DW_LNS_set_column: // Takes a single unsigned LEB128 operand and stores it in the // column register of the state machine. - State.Row.Column = TableData.getULEB128(OffsetPtr); - if (Verbose) - *OS << " (" << State.Row.Column << ")"; + if (Optional Column = + parseULEB128(TableData, Cursor)) { + State.Row.Column = *Column; + if (Verbose) + *OS << " (" << State.Row.Column << ")"; + } break; case DW_LNS_negate_stmt: @@ -1013,10 +1037,13 @@ // requires the use of DW_LNS_advance_pc. Such assemblers, however, // can use DW_LNS_fixed_advance_pc instead, sacrificing compression. { - uint16_t PCOffset = TableData.getRelocatedValue(2, OffsetPtr); - State.Row.Address.Address += PCOffset; - if (Verbose) - *OS << format(" (0x%4.4" PRIx16 ")", PCOffset); + uint16_t PCOffset = + TableData.getRelocatedValue(Cursor, 2); + if (Cursor) { + State.Row.Address.Address += PCOffset; + if (Verbose) + *OS << format(" (0x%4.4" PRIx16 ")", PCOffset); + } } break; @@ -1034,10 +1061,12 @@ case DW_LNS_set_isa: // Takes a single unsigned LEB128 operand and stores it in the - // column register of the state machine. - State.Row.Isa = TableData.getULEB128(OffsetPtr); - if (Verbose) - *OS << " (" << (uint64_t)State.Row.Isa << ")"; + // ISA register of the state machine. + if (Optional Isa = parseULEB128(TableData, Cursor)) { + State.Row.Isa = *Isa; + if (Verbose) + *OS << " (" << (uint64_t)State.Row.Isa << ")"; + } break; default: @@ -1049,16 +1078,22 @@ if (Verbose) *OS << "Unrecognized standard opcode"; uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1]; - if (OpcodeLength != 0) { - if (Verbose) - *OS << " (operands: "; - for (uint8_t I = 0; I < OpcodeLength; ++I) { - uint64_t Value = TableData.getULEB128(OffsetPtr); - if (Verbose) { - if (I > 0) - *OS << ", "; - *OS << format("0x%16.16" PRIx64, Value); - } + std::vector Operands; + for (uint8_t I = 0; I < OpcodeLength; ++I) { + if (Optional Value = + parseULEB128(TableData, Cursor)) + Operands.push_back(*Value); + else + break; + } + if (Verbose && !Operands.empty()) { + *OS << " (operands: "; + bool First = true; + for (uint64_t Value : Operands) { + if (!First) + *OS << ", "; + First = false; + *OS << format("0x%16.16" PRIx64, Value); } if (Verbose) *OS << ')'; @@ -1066,6 +1101,17 @@ } break; } + + *OffsetPtr = Cursor.tell(); + + // Most standard opcode failures are due to failures to read ULEBs. Bail + // out of parsing, since we don't know where to continue reading from as + // there is no stated length for such byte sequences. + if (!Cursor) { + if (Verbose) + *OS << "\n\n"; + return Cursor.takeError(); + } } else { // Special Opcodes. ParsingState::AddrAndLineDelta Delta = 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 @@ -1382,25 +1382,27 @@ using ValueAndLengths = std::vector; -struct TruncatedExtendedOpcodeFixture - : public TestWithParam>, - public CommonFixture { - void SetUp() { - std::tie(BodyLength, OpcodeLength, Opcode, Operands, ExpectedOutput, - ExpectedErr) = GetParam(); - } - - void runTest() { +struct TruncatedOpcodeFixtureBase : public CommonFixture { + LineTable &setupTable() { LineTable < = Gen->addLineTable(); - // Creating the prologue before adding the opcode ensures that the unit + + // Creating the prologue before adding any opcodes ensures that the unit // length does not include the table body. DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue(); - Prologue.TotalLength += BodyLength; + + // Add an unrecognised standard opcode, and adjust prologue properties + // accordingly. + Prologue.TotalLength += BodyLength + 1; + ++Prologue.PrologueLength; + ++Prologue.OpcodeBase; + Prologue.StandardOpcodeLengths.push_back(2); LT.setPrologue(Prologue); - LT.addExtendedOpcode(OpcodeLength, Opcode, Operands); - generate(); + return LT; + } + + void runTest(uint8_t OpcodeValue) { + generate(); DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); std::string Output; raw_string_ostream OS(Output); @@ -1408,28 +1410,52 @@ /*Verbose=*/true); OS.flush(); - StringRef LinePrefix = "0x0000002e: 00 "; + std::string LinePrefix = + ("0x0000002f: 0" + Twine::utohexstr(OpcodeValue) + " ").str(); StringRef OutputRef(Output); StringRef OutputToCheck = OutputRef.split(LinePrefix).second; // Each extended opcode ends with a new line and then the table ends with an // additional blank line. EXPECT_EQ((ExpectedOutput + "\n\n").str(), OutputToCheck); - EXPECT_THAT_ERROR(std::move(Recoverable), - FailedWithMessage(ExpectedErr.str())); } uint64_t BodyLength; - uint64_t OpcodeLength; uint8_t Opcode; ValueAndLengths Operands; StringRef ExpectedOutput; StringRef ExpectedErr; }; +struct TruncatedStandardOpcodeFixture + : public TestWithParam< + std::tuple>, + public TruncatedOpcodeFixtureBase { + void SetUp() { + std::tie(BodyLength, Opcode, Operands, ExpectedOutput, ExpectedErr) = + GetParam(); + } +}; + +struct TruncatedExtendedOpcodeFixture + : public TestWithParam>, + public TruncatedOpcodeFixtureBase { + void SetUp() { + std::tie(BodyLength, OpcodeLength, Opcode, Operands, ExpectedOutput, + ExpectedErr) = GetParam(); + } + + uint64_t OpcodeLength; +}; + TEST_P(TruncatedExtendedOpcodeFixture, ErrorForTruncatedExtendedOpcode) { if (!setupGenerator()) return; - runTest(); + LineTable < = setupTable(); + LT.addExtendedOpcode(OpcodeLength, Opcode, Operands); + runTest(0); + EXPECT_THAT_ERROR(std::move(Recoverable), + FailedWithMessage(ExpectedErr.str())); } INSTANTIATE_TEST_CASE_P( @@ -1437,18 +1463,18 @@ Values( std::make_tuple(1, 1, DW_LNE_end_sequence, ValueAndLengths(), "Badly formed extended line op (length 0)", - "unable to decode LEB128 at offset 0x0000002f: " + "unable to decode LEB128 at offset 0x00000030: " "malformed uleb128, extends past end"), std::make_tuple( 2, 9, DW_LNE_set_address, ValueAndLengths{{0x12345678, LineTable::Quad}}, "Unrecognized extended op 0x00 length 9", - "unexpected end of data at offset 0x30 while reading [0x30, 0x31)"), + "unexpected end of data at offset 0x31 while reading [0x31, 0x32)"), std::make_tuple( 3, 9, DW_LNE_set_address, ValueAndLengths{{0x12345678, LineTable::Quad}}, "DW_LNE_set_address (0x0000000000000000)", - "unexpected end of data at offset 0x31 while reading [0x31, 0x39)"), + "unexpected end of data at offset 0x32 while reading [0x32, 0x3a)"), std::make_tuple(3, 5, DW_LNE_define_file, ValueAndLengths{{'a', LineTable::Byte}, {'\0', LineTable::Byte}, @@ -1457,7 +1483,7 @@ {1, LineTable::ULEB}}, "DW_LNE_define_file (, dir=0, " "mod_time=(0x0000000000000000), length=0)", - "no null terminated string at offset 0x31"), + "no null terminated string at offset 0x32"), std::make_tuple(5, 5, DW_LNE_define_file, ValueAndLengths{{'a', LineTable::Byte}, {'\0', LineTable::Byte}, @@ -1466,7 +1492,7 @@ {1, LineTable::ULEB}}, "DW_LNE_define_file (a, dir=0, " "mod_time=(0x0000000000000000), length=0)", - "unable to decode LEB128 at offset 0x00000033: " + "unable to decode LEB128 at offset 0x00000034: " "malformed uleb128, extends past end"), std::make_tuple(6, 5, DW_LNE_define_file, ValueAndLengths{{'a', LineTable::Byte}, @@ -1476,7 +1502,7 @@ {1, LineTable::ULEB}}, "DW_LNE_define_file (a, dir=1, " "mod_time=(0x0000000000000000), length=0)", - "unable to decode LEB128 at offset 0x00000034: " + "unable to decode LEB128 at offset 0x00000035: " "malformed uleb128, extends past end"), std::make_tuple(7, 5, DW_LNE_define_file, ValueAndLengths{{'a', LineTable::Byte}, @@ -1486,14 +1512,70 @@ {1, LineTable::ULEB}}, "DW_LNE_define_file (a, dir=1, " "mod_time=(0x0000000000000001), length=0)", - "unable to decode LEB128 at offset 0x00000035: " + "unable to decode LEB128 at offset 0x00000036: " "malformed uleb128, extends past end"), std::make_tuple(3, 2, DW_LNE_set_discriminator, ValueAndLengths{{1, LineTable::ULEB}}, "DW_LNE_set_discriminator (0)", - "unable to decode LEB128 at offset 0x00000031: " + "unable to decode LEB128 at offset 0x00000032: " "malformed uleb128, extends past end")), ); +TEST_P(TruncatedStandardOpcodeFixture, ErrorForTruncatedStandardOpcode) { + if (!setupGenerator()) + return; + LineTable < = setupTable(); + LT.addStandardOpcode(Opcode, Operands); + runTest(Opcode); + EXPECT_THAT_ERROR(std::move(Unrecoverable), + FailedWithMessage(ExpectedErr.str())); +} + +INSTANTIATE_TEST_CASE_P( + TruncatedStandardOpcodeParams, TruncatedStandardOpcodeFixture, + Values( + std::make_tuple(2, DW_LNS_advance_pc, + ValueAndLengths{{0x100, LineTable::ULEB}}, + "DW_LNS_advance_pc", + "unable to decode LEB128 at offset 0x00000030: " + "malformed uleb128, extends past end"), + std::make_tuple(2, DW_LNS_advance_line, + ValueAndLengths{{0x200, LineTable::SLEB}}, + "DW_LNS_advance_line", + "unable to decode LEB128 at offset 0x00000030: " + "malformed sleb128, extends past end"), + std::make_tuple(2, DW_LNS_set_file, + ValueAndLengths{{0x300, LineTable::ULEB}}, + "DW_LNS_set_file", + "unable to decode LEB128 at offset 0x00000030: " + "malformed uleb128, extends past end"), + std::make_tuple(2, DW_LNS_set_column, + ValueAndLengths{{0x400, LineTable::ULEB}}, + "DW_LNS_set_column", + "unable to decode LEB128 at offset 0x00000030: " + "malformed uleb128, extends past end"), + std::make_tuple( + 2, DW_LNS_fixed_advance_pc, + ValueAndLengths{{0x500, LineTable::Half}}, + "DW_LNS_fixed_advance_pc", + "unexpected end of data at offset 0x31 while reading [0x30, 0x32)"), + std::make_tuple(2, DW_LNS_set_isa, + ValueAndLengths{{0x600, LineTable::ULEB}}, + "DW_LNS_set_isa", + "unable to decode LEB128 at offset 0x00000030: " + "malformed uleb128, extends past end"), + std::make_tuple(2, 0xd, + ValueAndLengths{{0x700, LineTable::ULEB}, + {0x800, LineTable::ULEB}}, + "Unrecognized standard opcode", + "unable to decode LEB128 at offset 0x00000030: " + "malformed uleb128, extends past end"), + std::make_tuple( + 4, 0xd, + ValueAndLengths{{0x900, LineTable::ULEB}, {0xa00, LineTable::ULEB}}, + "Unrecognized standard opcode (operands: 0x0000000000000900)", + "unable to decode LEB128 at offset 0x00000032: " + "malformed uleb128, extends past end")), ); + TEST_F(DebugLineBasicFixture, PrintPathsProperly) { if (!setupGenerator(5)) return;