[llvm] 8732192 - [DebugInfo] Report unsupported maximum_operations_per_instruction values
James Henderson via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 9 06:00:35 PDT 2020
Author: James Henderson
Date: 2020-03-09T12:59:43Z
New Revision: 8732192bbaf4457ae347912cb0af6dde46ef706a
URL: https://github.com/llvm/llvm-project/commit/8732192bbaf4457ae347912cb0af6dde46ef706a
DIFF: https://github.com/llvm/llvm-project/commit/8732192bbaf4457ae347912cb0af6dde46ef706a.diff
LOG: [DebugInfo] Report unsupported maximum_operations_per_instruction values
This patch adds a check which reports an unsupported value of the
maximum_operations_per_instruction field in a debug line table header.
This is reported once per line table, at most, and only if the tablet
would otherwise need to use it (i.e. never for tables with version 3 or
less, or for tables which don't use DW_LNS_const_add_pc or special
opcodes). Unsupported values are currently any apart from 1.
Reviewed by: probinson, MaskRay
Differential Revision: https://reviews.llvm.org/D74819
Added:
Modified:
llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
index 0eece9239f8a..d2208abad58b 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
@@ -362,14 +362,16 @@ class DWARFDebugLine {
private:
struct ParsingState {
- ParsingState(struct LineTable *LT);
+ ParsingState(struct LineTable *LT, uint64_t TableOffset,
+ function_ref<void(Error)> ErrorHandler);
void resetRowAndSequence();
void appendRowToMatrix();
/// Advance the address by the \p OperationAdvance value. \returns the
/// amount advanced by.
- uint64_t advanceAddr(uint64_t OperationAdvance);
+ uint64_t advanceAddr(uint64_t OperationAdvance, uint8_t Opcode,
+ uint64_t OpcodeOffset);
struct AddrAndAdjustedOpcode {
uint64_t AddrDelta;
@@ -378,7 +380,8 @@ class DWARFDebugLine {
/// Advance the address as required by the specified \p Opcode.
/// \returns the amount advanced by and the calculated adjusted opcode.
- AddrAndAdjustedOpcode advanceAddrForOpcode(uint8_t Opcode);
+ AddrAndAdjustedOpcode advanceAddrForOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset);
struct AddrAndLineDelta {
uint64_t Address;
@@ -387,12 +390,18 @@ class DWARFDebugLine {
/// Advance the line and address as required by the specified special \p
/// Opcode. \returns the address and line delta.
- AddrAndLineDelta handleSpecialOpcode(uint8_t Opcode);
+ AddrAndLineDelta handleSpecialOpcode(uint8_t Opcode, uint64_t OpcodeOffset);
/// Line table we're currently parsing.
struct LineTable *LineTable;
struct Row Row;
struct Sequence Sequence;
+
+ private:
+ uint64_t LineTableOffset;
+
+ bool ReportAdvanceAddrProblem = true;
+ function_ref<void(Error)> ErrorHandler;
};
using LineTableMapTy = std::map<uint64_t, LineTable>;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index d3421efa0df0..08f47aab8dcf 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -507,8 +507,10 @@ void DWARFDebugLine::LineTable::clear() {
Sequences.clear();
}
-DWARFDebugLine::ParsingState::ParsingState(struct LineTable *LT)
- : LineTable(LT) {
+DWARFDebugLine::ParsingState::ParsingState(
+ struct LineTable *LT, uint64_t TableOffset,
+ function_ref<void(Error)> ErrorHandler)
+ : LineTable(LT), LineTableOffset(TableOffset), ErrorHandler(ErrorHandler) {
resetRowAndSequence();
}
@@ -566,14 +568,39 @@ Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
return LT;
}
-uint64_t DWARFDebugLine::ParsingState::advanceAddr(uint64_t OperationAdvance) {
+static StringRef getOpcodeName(uint8_t Opcode, uint8_t OpcodeBase) {
+ assert(Opcode != 0);
+ if (Opcode < OpcodeBase)
+ return LNStandardString(Opcode);
+ return "special";
+}
+
+uint64_t DWARFDebugLine::ParsingState::advanceAddr(uint64_t OperationAdvance,
+ uint8_t Opcode,
+ uint64_t OpcodeOffset) {
+ StringRef OpcodeName = getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase);
+ // For versions less than 4, the MaxOpsPerInst member is set to 0, as the
+ // maximum_operations_per_instruction field wasn't introduced until DWARFv4.
+ // Don't warn about bad values in this situation.
+ if (ReportAdvanceAddrProblem && LineTable->Prologue.getVersion() >= 4 &&
+ LineTable->Prologue.MaxOpsPerInst != 1)
+ 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 maximum_operations_per_instruction value is %" PRId8
+ ", which is unsupported. Assuming a value of 1 instead",
+ LineTableOffset, OpcodeName.data(), OpcodeOffset,
+ LineTable->Prologue.MaxOpsPerInst));
+ ReportAdvanceAddrProblem = false;
uint64_t AddrOffset = OperationAdvance * LineTable->Prologue.MinInstLength;
Row.Address.Address += AddrOffset;
return AddrOffset;
}
DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode
-DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode) {
+DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset) {
assert(Opcode == DW_LNS_const_add_pc ||
Opcode >= LineTable->Prologue.OpcodeBase);
uint8_t OpcodeValue = Opcode;
@@ -581,12 +608,13 @@ DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode) {
OpcodeValue = 255;
uint8_t AdjustedOpcode = OpcodeValue - LineTable->Prologue.OpcodeBase;
uint64_t OperationAdvance = AdjustedOpcode / LineTable->Prologue.LineRange;
- uint64_t AddrOffset = advanceAddr(OperationAdvance);
+ uint64_t AddrOffset = advanceAddr(OperationAdvance, Opcode, OpcodeOffset);
return {AddrOffset, AdjustedOpcode};
}
DWARFDebugLine::ParsingState::AddrAndLineDelta
-DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode) {
+DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset) {
// A special opcode value is chosen based on the amount that needs
// to be added to the line and address registers. The maximum line
// increment for a special opcode is the value of the line_base
@@ -619,7 +647,7 @@ DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode) {
// line increment = line_base + (adjusted opcode % line_range)
DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode AddrAdvanceResult =
- advanceAddrForOpcode(Opcode);
+ advanceAddrForOpcode(Opcode, OpcodeOffset);
int32_t LineOffset =
LineTable->Prologue.LineBase +
(AddrAdvanceResult.AdjustedOpcode % LineTable->Prologue.LineRange);
@@ -673,12 +701,13 @@ Error DWARFDebugLine::LineTable::parse(
assert(Prologue.getAddressSize() == 0 ||
Prologue.getAddressSize() == DebugLineData.getAddressSize());
- ParsingState State(this);
+ ParsingState State(this, DebugLineOffset, RecoverableErrorHandler);
while (*OffsetPtr < EndOffset) {
if (OS)
*OS << format("0x%08.08" PRIx64 ": ", *OffsetPtr);
+ uint64_t OpcodeOffset = *OffsetPtr;
uint8_t Opcode = DebugLineData.getU8(OffsetPtr);
if (OS)
@@ -853,8 +882,8 @@ Error DWARFDebugLine::LineTable::parse(
// min_inst_length field of the prologue, and adds the
// result to the address register of the state machine.
{
- uint64_t AddrOffset =
- State.advanceAddr(DebugLineData.getULEB128(OffsetPtr));
+ uint64_t AddrOffset = State.advanceAddr(
+ DebugLineData.getULEB128(OffsetPtr), Opcode, OpcodeOffset);
if (OS)
*OS << " (" << AddrOffset << ")";
}
@@ -909,7 +938,8 @@ Error DWARFDebugLine::LineTable::parse(
// than twice that range will it need to use both DW_LNS_advance_pc
// and a special opcode, requiring three or more bytes.
{
- uint64_t AddrOffset = State.advanceAddrForOpcode(Opcode).AddrDelta;
+ uint64_t AddrOffset =
+ State.advanceAddrForOpcode(Opcode, OpcodeOffset).AddrDelta;
if (OS)
*OS << format(" (0x%16.16" PRIx64 ")", AddrOffset);
}
@@ -972,7 +1002,8 @@ Error DWARFDebugLine::LineTable::parse(
}
} else {
// Special Opcodes.
- ParsingState::AddrAndLineDelta Delta = State.handleSpecialOpcode(Opcode);
+ ParsingState::AddrAndLineDelta Delta =
+ State.handleSpecialOpcode(Opcode, OpcodeOffset);
if (OS) {
*OS << "address += " << Delta.Address << ", line += " << Delta.Line
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
index 25db5af3a32c..0164100f6595 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
@@ -754,6 +754,213 @@ TEST_F(DebugLineBasicFixture, CallbackUsedForUnterminatedSequence) {
EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u);
}
+struct AdjustAddressFixtureBase : public CommonFixture {
+ virtual ~AdjustAddressFixtureBase() {}
+
+ // Create and update the prologue as specified by the subclass, then return
+ // the length of the table.
+ virtual uint64_t editPrologue(LineTable <) = 0;
+
+ virtual uint64_t getAdjustedAddr(uint64_t Base, uint64_t ConstIncrs,
+ uint64_t SpecialIncrs,
+ uint64_t AdvanceIncrs) {
+ return Base + ConstIncrs + SpecialIncrs + AdvanceIncrs;
+ }
+
+ virtual uint64_t getAdjustedLine(uint64_t Base, uint64_t Incr) {
+ return Base + Incr;
+ }
+
+ uint64_t setupNoProblemTable() {
+ LineTable &NoProblem = Gen->addLineTable();
+ NoProblem.addExtendedOpcode(9, DW_LNE_set_address,
+ {{0xabcd, LineTable::Quad}});
+ NoProblem.addExtendedOpcode(1, DW_LNE_end_sequence, {});
+ return editPrologue(NoProblem);
+ }
+
+ uint64_t setupConstAddPcFirstTable() {
+ LineTable &ConstAddPCFirst = Gen->addLineTable();
+ ConstAddPCFirst.addExtendedOpcode(9, DW_LNE_set_address,
+ {{ConstAddPCAddr, LineTable::Quad}});
+ ConstAddPCFirst.addStandardOpcode(DW_LNS_const_add_pc, {});
+ ConstAddPCFirst.addStandardOpcode(DW_LNS_const_add_pc, {});
+ ConstAddPCFirst.addStandardOpcode(DW_LNS_advance_pc,
+ {{0x10, LineTable::ULEB}});
+ ConstAddPCFirst.addByte(0x21); // Special opcode, +1 op, +1 line.
+ ConstAddPCFirst.addExtendedOpcode(1, DW_LNE_end_sequence, {});
+ return editPrologue(ConstAddPCFirst);
+ }
+
+ uint64_t setupSpecialFirstTable() {
+ LineTable &SpecialFirst = Gen->addLineTable();
+ SpecialFirst.addExtendedOpcode(9, DW_LNE_set_address,
+ {{SpecialAddr, LineTable::Quad}});
+ SpecialFirst.addByte(0x22); // Special opcode, +1 op, +2 line.
+ SpecialFirst.addStandardOpcode(DW_LNS_const_add_pc, {});
+ SpecialFirst.addStandardOpcode(DW_LNS_advance_pc,
+ {{0x20, LineTable::ULEB}});
+ SpecialFirst.addByte(0x23); // Special opcode, +1 op, +3 line.
+ SpecialFirst.addExtendedOpcode(1, DW_LNE_end_sequence, {});
+ return editPrologue(SpecialFirst);
+ }
+
+ uint64_t setupAdvancePcFirstTable() {
+ LineTable &AdvancePCFirst = Gen->addLineTable();
+ AdvancePCFirst.addExtendedOpcode(9, DW_LNE_set_address,
+ {{AdvancePCAddr, LineTable::Quad}});
+ AdvancePCFirst.addStandardOpcode(DW_LNS_advance_pc,
+ {{0x30, LineTable::ULEB}});
+ AdvancePCFirst.addStandardOpcode(DW_LNS_const_add_pc, {});
+ AdvancePCFirst.addStandardOpcode(DW_LNS_advance_pc,
+ {{0x40, LineTable::ULEB}});
+ AdvancePCFirst.addByte(0x24); // Special opcode, +1 op, +4 line.
+ AdvancePCFirst.addExtendedOpcode(1, DW_LNE_end_sequence, {});
+ return editPrologue(AdvancePCFirst);
+ }
+
+ void setupTables(bool AddAdvancePCFirstTable) {
+ LineTable &Padding = Gen->addLineTable();
+ Padding.setCustomPrologue({{0, LineTable::Byte}});
+ NoProblemOffset = 1;
+
+ // Show that no warning is generated for the case where no
+ // DW_LNS_const_add_pc or special opcode is used.
+ ConstAddPCOffset = setupNoProblemTable() + NoProblemOffset;
+
+ // Show that the warning is emitted for the first DW_LNS_const_add_pc opcode
+ // and then not again.
+ SpecialOffset = setupConstAddPcFirstTable() + ConstAddPCOffset;
+
+ // Show that the warning is emitted for the first special opcode and then
+ // not again.
+ AdvancePCOffset = setupSpecialFirstTable() + SpecialOffset;
+
+ // Show that the warning is emitted for the first DW_LNS_advance_pc opcode
+ // (if requested) and then not again.
+ if (AddAdvancePCFirstTable)
+ setupAdvancePcFirstTable();
+ }
+
+ Expected<const DWARFDebugLine::LineTable *>
+ checkTable(uint64_t Offset, StringRef OpcodeType, const Twine &MsgSuffix) {
+ auto ExpectedTable = Line.getOrParseLineTable(LineData, Offset, *Context,
+ nullptr, RecordRecoverable);
+ EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded());
+ if (!IsErrorExpected) {
+ EXPECT_THAT_ERROR(std::move(Recoverable), Succeeded());
+ } else {
+ if (!ExpectedTable)
+ return ExpectedTable;
+ uint64_t ExpectedOffset = Offset +
+ (*ExpectedTable)->Prologue.getLength() +
+ 11; // 11 == size of DW_LNE_set_address.
+ std::string OffsetHex = Twine::utohexstr(Offset).str();
+ std::string OffsetZeroes = std::string(8 - OffsetHex.size(), '0');
+ std::string ExpectedHex = Twine::utohexstr(ExpectedOffset).str();
+ std::string ExpectedZeroes = std::string(8 - ExpectedHex.size(), '0');
+ EXPECT_THAT_ERROR(
+ std::move(Recoverable),
+ FailedWithMessage(("line table program at offset 0x" + OffsetZeroes +
+ OffsetHex + " contains a " + OpcodeType +
+ " opcode at offset 0x" + ExpectedZeroes +
+ ExpectedHex + ", " + MsgSuffix)
+ .str()));
+ }
+ return ExpectedTable;
+ }
+
+ void runTest(bool CheckAdvancePC, Twine MsgSuffix) {
+ if (!setupGenerator(Version))
+ return;
+
+ setupTables(/*AddAdvancePCFirstTable=*/CheckAdvancePC);
+
+ generate();
+
+ auto ExpectedNoProblem = Line.getOrParseLineTable(
+ LineData, NoProblemOffset, *Context, nullptr, RecordRecoverable);
+ EXPECT_THAT_ERROR(std::move(Recoverable), Succeeded());
+ EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded());
+ ASSERT_THAT_EXPECTED(ExpectedNoProblem, Succeeded());
+
+ auto ExpectedConstAddPC =
+ checkTable(ConstAddPCOffset, "DW_LNS_const_add_pc", MsgSuffix);
+ ASSERT_THAT_EXPECTED(ExpectedConstAddPC, Succeeded());
+ ASSERT_EQ((*ExpectedConstAddPC)->Rows.size(), 2u);
+ EXPECT_EQ((*ExpectedConstAddPC)->Rows[0].Address.Address,
+ getAdjustedAddr(ConstAddPCAddr, ConstIncr * 2, 0x1, 0x10));
+ EXPECT_EQ((*ExpectedConstAddPC)->Rows[0].Line, getAdjustedLine(1, 1));
+ EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded());
+
+ auto ExpectedSpecial = checkTable(SpecialOffset, "special", MsgSuffix);
+ ASSERT_THAT_EXPECTED(ExpectedSpecial, Succeeded());
+ ASSERT_EQ((*ExpectedSpecial)->Rows.size(), 3u);
+ EXPECT_EQ((*ExpectedSpecial)->Rows[0].Address.Address,
+ getAdjustedAddr(SpecialAddr, 0, 1, 0));
+ EXPECT_EQ((*ExpectedSpecial)->Rows[0].Line, getAdjustedLine(1, 2));
+ EXPECT_EQ((*ExpectedSpecial)->Rows[1].Address.Address,
+ getAdjustedAddr(SpecialAddr, ConstIncr, 0x2, 0x20));
+ EXPECT_EQ((*ExpectedSpecial)->Rows[1].Line, getAdjustedLine(1, 5));
+ EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded());
+
+ if (!CheckAdvancePC)
+ return;
+
+ auto ExpectedAdvancePC =
+ checkTable(AdvancePCOffset, "DW_LNS_advance_pc", MsgSuffix);
+ ASSERT_THAT_EXPECTED(ExpectedAdvancePC, Succeeded());
+ ASSERT_EQ((*ExpectedAdvancePC)->Rows.size(), 2u);
+ EXPECT_EQ((*ExpectedAdvancePC)->Rows[0].Address.Address,
+ getAdjustedAddr(AdvancePCAddr, ConstIncr, 0x1, 0x70));
+ EXPECT_EQ((*ExpectedAdvancePC)->Rows[0].Line, getAdjustedLine(1, 4));
+ }
+
+ uint64_t ConstIncr = 0x11;
+ uint64_t ConstAddPCAddr = 0x1234;
+ uint64_t SpecialAddr = 0x5678;
+ uint64_t AdvancePCAddr = 0xabcd;
+ uint64_t NoProblemOffset;
+ uint64_t ConstAddPCOffset;
+ uint64_t SpecialOffset;
+ uint64_t AdvancePCOffset;
+
+ uint16_t Version = 4;
+ bool IsErrorExpected;
+};
+
+struct MaxOpsPerInstFixture
+ : TestWithParam<std::tuple<uint16_t, uint8_t, bool>>,
+ AdjustAddressFixtureBase {
+ void SetUp() override {
+ std::tie(Version, MaxOpsPerInst, IsErrorExpected) = GetParam();
+ }
+
+ uint64_t editPrologue(LineTable <) override {
+ DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue();
+ Prologue.MaxOpsPerInst = MaxOpsPerInst;
+ LT.setPrologue(Prologue);
+ return Prologue.TotalLength + Prologue.sizeofTotalLength();
+ }
+
+ uint8_t MaxOpsPerInst;
+};
+
+TEST_P(MaxOpsPerInstFixture, MaxOpsPerInstProblemsReportedCorrectly) {
+ runTest(/*CheckAdvancePC=*/true,
+ "but the prologue maximum_operations_per_instruction value is " +
+ Twine(unsigned(MaxOpsPerInst)) +
+ ", which is unsupported. Assuming a value of 1 instead");
+}
+
+INSTANTIATE_TEST_CASE_P(
+ MaxOpsPerInstParams, MaxOpsPerInstFixture,
+ Values(std::make_tuple(3, 0, false), // Test for version < 4 (no error).
+ std::make_tuple(4, 0, true), // Test zero value for V4 (error).
+ std::make_tuple(4, 1, false), // Test good value for V4 (no error).
+ std::make_tuple(
+ 4, 2, true)), ); // Test one higher than permitted V4 (error).
+
TEST_F(DebugLineBasicFixture, ParserParsesCorrectly) {
if (!setupGenerator())
return;
More information about the llvm-commits
mailing list