mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[DebugInfo] Report errors for truncated debug line standard opcode
Standard opcodes usually have ULEB128 arguments, so it is generally not possible to recover from such errors. This patch causes the parser to stop parsing the table in such situations. Also don't emit the operands or add data to the table if there is an error reading these opcodes. Reviewed by: JDevlieghere Differential Revision: https://reviews.llvm.org/D81470
This commit is contained in:
parent
5a6ecb6df8
commit
2227cf704f
@ -690,6 +690,17 @@ DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode,
|
||||
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 <typename T>
|
||||
static Optional<T> 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 @@ Error DWARFDebugLine::LineTable::parse(
|
||||
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 @@ Error DWARFDebugLine::LineTable::parse(
|
||||
// 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<uint64_t> Operand =
|
||||
parseULEB128<uint64_t>(TableData, Cursor)) {
|
||||
uint64_t AddrOffset =
|
||||
State.advanceAddr(*Operand, Opcode, OpcodeOffset);
|
||||
if (Verbose)
|
||||
*OS << " (" << AddrOffset << ")";
|
||||
}
|
||||
@ -949,25 +962,36 @@ Error DWARFDebugLine::LineTable::parse(
|
||||
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<uint16_t> File =
|
||||
parseULEB128<uint16_t>(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<uint16_t> Column =
|
||||
parseULEB128<uint16_t>(TableData, Cursor)) {
|
||||
State.Row.Column = *Column;
|
||||
if (Verbose)
|
||||
*OS << " (" << State.Row.Column << ")";
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_LNS_negate_stmt:
|
||||
@ -1013,10 +1037,13 @@ Error DWARFDebugLine::LineTable::parse(
|
||||
// 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 @@ Error DWARFDebugLine::LineTable::parse(
|
||||
|
||||
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<uint8_t> Isa = parseULEB128<uint8_t>(TableData, Cursor)) {
|
||||
State.Row.Isa = *Isa;
|
||||
if (Verbose)
|
||||
*OS << " (" << (uint64_t)State.Row.Isa << ")";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1049,16 +1078,22 @@ Error DWARFDebugLine::LineTable::parse(
|
||||
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<uint64_t> Operands;
|
||||
for (uint8_t I = 0; I < OpcodeLength; ++I) {
|
||||
if (Optional<uint64_t> Value =
|
||||
parseULEB128<uint64_t>(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 @@ Error DWARFDebugLine::LineTable::parse(
|
||||
}
|
||||
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 =
|
||||
|
@ -1382,25 +1382,27 @@ TEST_F(DebugLineBasicFixture, VerboseOutput) {
|
||||
|
||||
using ValueAndLengths = std::vector<LineTable::ValueAndLength>;
|
||||
|
||||
struct TruncatedExtendedOpcodeFixture
|
||||
: public TestWithParam<std::tuple<uint64_t, uint64_t, uint8_t,
|
||||
ValueAndLengths, StringRef, StringRef>>,
|
||||
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;
|
||||
LT.setPrologue(Prologue);
|
||||
LT.addExtendedOpcode(OpcodeLength, Opcode, Operands);
|
||||
generate();
|
||||
|
||||
// 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);
|
||||
|
||||
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 @@ struct TruncatedExtendedOpcodeFixture
|
||||
/*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<uint64_t, uint8_t, ValueAndLengths, StringRef, StringRef>>,
|
||||
public TruncatedOpcodeFixtureBase {
|
||||
void SetUp() {
|
||||
std::tie(BodyLength, Opcode, Operands, ExpectedOutput, ExpectedErr) =
|
||||
GetParam();
|
||||
}
|
||||
};
|
||||
|
||||
struct TruncatedExtendedOpcodeFixture
|
||||
: public TestWithParam<std::tuple<uint64_t, uint64_t, uint8_t,
|
||||
ValueAndLengths, StringRef, StringRef>>,
|
||||
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 @@ INSTANTIATE_TEST_CASE_P(
|
||||
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 @@ INSTANTIATE_TEST_CASE_P(
|
||||
{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 @@ INSTANTIATE_TEST_CASE_P(
|
||||
{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 @@ INSTANTIATE_TEST_CASE_P(
|
||||
{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 @@ INSTANTIATE_TEST_CASE_P(
|
||||
{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;
|
||||
|
Loading…
Reference in New Issue
Block a user