[llvm] fe6cdde - [DWARF] Allow op-index in line number programs
David Stenberg via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 12 04:48:04 PDT 2023
Author: David Stenberg
Date: 2023-07-12T13:46:29+02:00
New Revision: fe6cddef2020c8e103cff8180540d4e2e9102c6d
URL: https://github.com/llvm/llvm-project/commit/fe6cddef2020c8e103cff8180540d4e2e9102c6d
DIFF: https://github.com/llvm/llvm-project/commit/fe6cddef2020c8e103cff8180540d4e2e9102c6d.diff
LOG: [DWARF] Allow op-index in line number programs
This extends DWARFDebugLine to properly parse line number programs with
maximum_operations_per_instruction > 1 for VLIW targets.
No functions that use that parsed output to retrieve line information
have been extended to support multiple op-indexes. This means that when
retrieving information for an address with multiple op-indexes, e.g.
when using llvm-addr2line, the penultimate row for that address will be
used, which in most cases is the row for the second largest op-index.
This will be addressed in further changes, but this patch at least
allows us to correctly parse such line number programs, with a warning
saying that the line number information may be incorrect (incomplete).
Reviewed By: StephenTozer
Differential Revision: https://reviews.llvm.org/D152536
Added:
Modified:
llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
llvm/test/MC/ELF/RISCV/gen-dwarf.s
llvm/test/tools/llvm-dwarfdump/X86/tombstone.s
llvm/test/tools/llvm-dwarfdump/X86/verbose.test
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 dc32f1ece18a93..ce3bae6a1760c2 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
@@ -377,29 +377,37 @@ class DWARFDebugLine {
void resetRowAndSequence();
void appendRowToMatrix();
- /// Advance the address by the \p OperationAdvance value. \returns the
- /// amount advanced by.
- uint64_t advanceAddr(uint64_t OperationAdvance, uint8_t Opcode,
- uint64_t OpcodeOffset);
+ struct AddrOpIndexDelta {
+ uint64_t AddrOffset;
+ int16_t OpIndexDelta;
+ };
+
+ /// Advance the address and op-index by the \p OperationAdvance value.
+ /// \returns the amount advanced by.
+ AddrOpIndexDelta advanceAddrOpIndex(uint64_t OperationAdvance,
+ uint8_t Opcode, uint64_t OpcodeOffset);
- struct AddrAndAdjustedOpcode {
+ struct OpcodeAdvanceResults {
uint64_t AddrDelta;
+ int16_t OpIndexDelta;
uint8_t AdjustedOpcode;
};
- /// Advance the address as required by the specified \p Opcode.
+ /// Advance the address and op-index as required by the specified \p Opcode.
/// \returns the amount advanced by and the calculated adjusted opcode.
- AddrAndAdjustedOpcode advanceAddrForOpcode(uint8_t Opcode,
- uint64_t OpcodeOffset);
+ OpcodeAdvanceResults advanceForOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset);
- struct AddrAndLineDelta {
+ struct SpecialOpcodeDelta {
uint64_t Address;
int32_t Line;
+ int16_t OpIndex;
};
- /// Advance the line and address as required by the specified special \p
- /// Opcode. \returns the address and line delta.
- AddrAndLineDelta handleSpecialOpcode(uint8_t Opcode, uint64_t OpcodeOffset);
+ /// Advance the line, address and op-index as required by the specified
+ /// special \p Opcode. \returns the address, op-index and line delta.
+ SpecialOpcodeDelta handleSpecialOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset);
/// Line table we're currently parsing.
struct LineTable *LineTable;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 818cc25db60dbf..6f2afe5d50e9c8 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -610,21 +610,36 @@ static StringRef getOpcodeName(uint8_t Opcode, uint8_t OpcodeBase) {
return "special";
}
-uint64_t DWARFDebugLine::ParsingState::advanceAddr(uint64_t OperationAdvance,
- uint8_t Opcode,
- uint64_t OpcodeOffset) {
+DWARFDebugLine::ParsingState::AddrOpIndexDelta
+DWARFDebugLine::ParsingState::advanceAddrOpIndex(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)
+ LineTable->Prologue.MaxOpsPerInst == 0)
+ ErrorHandler(createStringError(
+ errc::invalid_argument,
+ "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 0"
+ ", which is invalid. Assuming a value of 1 instead",
+ LineTableOffset, OpcodeName.data(), OpcodeOffset));
+ // Although we are able to correctly parse line number programs with
+ // MaxOpsPerInst > 1, the rest of DWARFDebugLine and its
+ // users have not been updated to handle line information for all operations
+ // in a multi-operation instruction, so warn about potentially incorrect
+ // results.
+ if (ReportAdvanceAddrProblem && 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",
+ ", which is experimentally supported, so line number information "
+ "may be incorrect",
LineTableOffset, OpcodeName.data(), OpcodeOffset,
LineTable->Prologue.MaxOpsPerInst));
if (ReportAdvanceAddrProblem && LineTable->Prologue.MinInstLength == 0)
@@ -636,14 +651,35 @@ uint64_t DWARFDebugLine::ParsingState::advanceAddr(uint64_t OperationAdvance,
"is 0, which prevents any address advancing",
LineTableOffset, OpcodeName.data(), OpcodeOffset));
ReportAdvanceAddrProblem = false;
- uint64_t AddrOffset = OperationAdvance * LineTable->Prologue.MinInstLength;
+
+ // Advances the address and op_index according to DWARFv5, section 6.2.5.1:
+ //
+ // new address = address +
+ // minimum_instruction_length *
+ // ((op_index + operation advance) / maximum_operations_per_instruction)
+ //
+ // new op_index =
+ // (op_index + operation advance) % maximum_operations_per_instruction
+
+ // For versions less than 4, the MaxOpsPerInst member is set to 0, as the
+ // maximum_operations_per_instruction field wasn't introduced until DWARFv4.
+ uint8_t MaxOpsPerInst =
+ std::max(LineTable->Prologue.MaxOpsPerInst, uint8_t{1});
+
+ uint64_t AddrOffset = ((Row.OpIndex + OperationAdvance) / MaxOpsPerInst) *
+ LineTable->Prologue.MinInstLength;
Row.Address.Address += AddrOffset;
- return AddrOffset;
+
+ uint8_t PrevOpIndex = Row.OpIndex;
+ Row.OpIndex = (Row.OpIndex + OperationAdvance) % MaxOpsPerInst;
+ int16_t OpIndexDelta = static_cast<int16_t>(Row.OpIndex) - PrevOpIndex;
+
+ return {AddrOffset, OpIndexDelta};
}
-DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode
-DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode,
- uint64_t OpcodeOffset) {
+DWARFDebugLine::ParsingState::OpcodeAdvanceResults
+DWARFDebugLine::ParsingState::advanceForOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset) {
assert(Opcode == DW_LNS_const_add_pc ||
Opcode >= LineTable->Prologue.OpcodeBase);
if (ReportBadLineRange && LineTable->Prologue.LineRange == 0) {
@@ -667,11 +703,12 @@ DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode,
LineTable->Prologue.LineRange != 0
? AdjustedOpcode / LineTable->Prologue.LineRange
: 0;
- uint64_t AddrOffset = advanceAddr(OperationAdvance, Opcode, OpcodeOffset);
- return {AddrOffset, AdjustedOpcode};
+ AddrOpIndexDelta Advance =
+ advanceAddrOpIndex(OperationAdvance, Opcode, OpcodeOffset);
+ return {Advance.AddrOffset, Advance.OpIndexDelta, AdjustedOpcode};
}
-DWARFDebugLine::ParsingState::AddrAndLineDelta
+DWARFDebugLine::ParsingState::SpecialOpcodeDelta
DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode,
uint64_t OpcodeOffset) {
// A special opcode value is chosen based on the amount that needs
@@ -705,15 +742,16 @@ DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode,
//
// line increment = line_base + (adjusted opcode % line_range)
- DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode AddrAdvanceResult =
- advanceAddrForOpcode(Opcode, OpcodeOffset);
+ DWARFDebugLine::ParsingState::OpcodeAdvanceResults AddrAdvanceResult =
+ advanceForOpcode(Opcode, OpcodeOffset);
int32_t LineOffset = 0;
if (LineTable->Prologue.LineRange != 0)
LineOffset =
LineTable->Prologue.LineBase +
(AddrAdvanceResult.AdjustedOpcode % LineTable->Prologue.LineRange);
Row.Line += LineOffset;
- return {AddrAdvanceResult.AddrDelta, LineOffset};
+ return {AddrAdvanceResult.AddrDelta, LineOffset,
+ AddrAdvanceResult.OpIndexDelta};
}
/// Parse a ULEB128 using the specified \p Cursor. \returns the parsed value on
@@ -860,9 +898,10 @@ Error DWARFDebugLine::LineTable::parse(
// Takes a single relocatable address as an operand. The size of the
// operand is the size appropriate to hold an address on the target
// machine. Set the address register to the value given by the
- // relocatable address. All of the other statement program opcodes
- // that affect the address register add a delta to it. This instruction
- // stores a relocatable value into it instead.
+ // relocatable address and set the op_index register to 0. All of the
+ // other statement program opcodes that affect the address register
+ // add a delta to it. This instruction stores a relocatable value into
+ // it instead.
//
// Make sure the extractor knows the address size. If not, infer it
// from the size of the operand.
@@ -893,6 +932,7 @@ Error DWARFDebugLine::LineTable::parse(
TableData.setAddressSize(OpcodeAddressSize);
State.Row.Address.Address = TableData.getRelocatedAddress(
Cursor, &State.Row.Address.SectionIndex);
+ State.Row.OpIndex = 0;
uint64_t Tombstone =
dwarf::computeTombstoneAddress(OpcodeAddressSize);
@@ -1004,15 +1044,16 @@ Error DWARFDebugLine::LineTable::parse(
break;
case DW_LNS_advance_pc:
- // 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.
+ // Takes a single unsigned LEB128 operand as the operation advance
+ // and modifies the address and op_index registers of the state machine
+ // according to that.
if (std::optional<uint64_t> Operand =
parseULEB128<uint64_t>(TableData, Cursor)) {
- uint64_t AddrOffset =
- State.advanceAddr(*Operand, Opcode, OpcodeOffset);
+ ParsingState::AddrOpIndexDelta Advance =
+ State.advanceAddrOpIndex(*Operand, Opcode, OpcodeOffset);
if (Verbose)
- *OS << " (" << AddrOffset << ")";
+ *OS << " (addr += " << Advance.AddrOffset
+ << ", op-index += " << Advance.OpIndexDelta << ")";
}
break;
@@ -1064,8 +1105,8 @@ Error DWARFDebugLine::LineTable::parse(
break;
case DW_LNS_const_add_pc:
- // Takes no arguments. Add to the address register of the state
- // machine the address increment value corresponding to special
+ // Takes no arguments. Advance the address and op_index registers of
+ // the state machine by the increments corresponding to special
// opcode 255. The motivation for DW_LNS_const_add_pc is this:
// when the statement program needs to advance the address by a
// small amount, it can use a single special opcode, which occupies
@@ -1076,30 +1117,35 @@ 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, OpcodeOffset).AddrDelta;
+ ParsingState::OpcodeAdvanceResults Advance =
+ State.advanceForOpcode(Opcode, OpcodeOffset);
if (Verbose)
- *OS << format(" (0x%16.16" PRIx64 ")", AddrOffset);
+ *OS << format(" (addr += 0x%16.16" PRIx64 ", op-index += %" PRIu8
+ ")",
+ Advance.AddrDelta, Advance.OpIndexDelta);
}
break;
case DW_LNS_fixed_advance_pc:
// Takes a single uhalf operand. Add to the address register of
- // the state machine the value of the (unencoded) operand. This
- // is the only extended opcode that takes an argument that is not
- // a variable length number. The motivation for DW_LNS_fixed_advance_pc
- // is this: existing assemblers cannot emit DW_LNS_advance_pc or
- // special opcodes because they cannot encode LEB128 numbers or
- // judge when the computation of a special opcode overflows and
- // requires the use of DW_LNS_advance_pc. Such assemblers, however,
- // can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
+ // the state machine the value of the (unencoded) operand and set
+ // the op_index register to 0. This is the only extended opcode that
+ // takes an argument that is not a variable length number.
+ // The motivation for DW_LNS_fixed_advance_pc is this: existing
+ // assemblers cannot emit DW_LNS_advance_pc or special opcodes because
+ // they cannot encode LEB128 numbers or judge when the computation
+ // of a special opcode overflows and 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(Cursor, 2);
if (Cursor) {
State.Row.Address.Address += PCOffset;
+ State.Row.OpIndex = 0;
if (Verbose)
- *OS << format(" (0x%4.4" PRIx16 ")", PCOffset);
+ *OS << format(" (addr += 0x%4.4" PRIx16 ", op-index = 0)",
+ PCOffset);
}
}
break;
@@ -1163,11 +1209,12 @@ Error DWARFDebugLine::LineTable::parse(
*OffsetPtr = Cursor.tell();
} else {
// Special Opcodes.
- ParsingState::AddrAndLineDelta Delta =
+ ParsingState::SpecialOpcodeDelta Delta =
State.handleSpecialOpcode(Opcode, OpcodeOffset);
if (Verbose)
- *OS << "address += " << Delta.Address << ", line += " << Delta.Line;
+ *OS << "address += " << Delta.Address << ", line += " << Delta.Line
+ << ", op-index += " << Delta.OpIndex;
EmitRow();
*OffsetPtr = Cursor.tell();
}
@@ -1228,6 +1275,9 @@ uint32_t DWARFDebugLine::LineTable::findRowInSeq(
//
// In general we want a non-empty range: the last row whose address is less
// than or equal to Address. This can be computed as upper_bound - 1.
+ //
+ // TODO: This function, and its users, needs to be update to return multiple
+ // rows for bundles with multiple op-indexes.
DWARFDebugLine::Row Row;
Row.Address = Address;
RowIter FirstRow = Rows.begin() + Seq.FirstRowIndex;
diff --git a/llvm/test/MC/ELF/RISCV/gen-dwarf.s b/llvm/test/MC/ELF/RISCV/gen-dwarf.s
index c0c8cae61c72ba..670f833f258d25 100644
--- a/llvm/test/MC/ELF/RISCV/gen-dwarf.s
+++ b/llvm/test/MC/ELF/RISCV/gen-dwarf.s
@@ -26,11 +26,11 @@
# CHECK-NEXT: DW_LNS_copy
# CHECK-NEXT: is_stmt
# CHECK-NEXT: DW_LNS_advance_line
-# CHECK-NEXT: DW_LNS_fixed_advance_pc (0x0004)
+# CHECK-NEXT: DW_LNS_fixed_advance_pc (addr += 0x0004, op-index = 0)
# CHECK-NEXT: DW_LNS_copy
# CHECK-NEXT: is_stmt
# CHECK-NEXT: DW_LNS_advance_line
-# CHECK-NEXT: DW_LNS_fixed_advance_pc (0x0004)
+# CHECK-NEXT: DW_LNS_fixed_advance_pc (addr += 0x0004, op-index = 0)
# CHECK-NEXT: DW_LNS_copy
# CHECK: 0x00000000: range list header: length = 0x0000001d, format = DWARF32, version = 0x0005
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/tombstone.s b/llvm/test/tools/llvm-dwarfdump/X86/tombstone.s
index 7b4ff70e5ff584..d72a6cbc17725f 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/tombstone.s
+++ b/llvm/test/tools/llvm-dwarfdump/X86/tombstone.s
@@ -63,23 +63,23 @@
# CHECK-NEXT: --------------
# CHECK-NEXT: DW_LNE_set_address (0xffffffff)
# CHECK-NEXT: DW_LNS_copy
-# CHECK-NEXT: DW_LNS_advance_pc (1)
+# CHECK-NEXT: DW_LNS_advance_pc (addr += 1, op-index += 0)
# CHECK-NEXT: DW_LNE_end_sequence
# CHECK-NEXT: DW_LNE_set_address (0x00000042)
# CHECK-NEXT: DW_LNS_copy
# CHECK-NEXT: 0x0000000000000042 1
-# CHECK-NEXT: DW_LNS_advance_pc (1)
+# CHECK-NEXT: DW_LNS_advance_pc (addr += 1, op-index += 0)
# CHECK-NEXT: DW_LNE_end_sequence
# CHECK: Address Line
# CHECK-NEXT: --------------
# CHECK-NEXT: DW_LNE_set_address (0xffffffffffffffff)
# CHECK-NEXT: DW_LNS_copy
-# CHECK-NEXT: DW_LNS_advance_pc (1)
+# CHECK-NEXT: DW_LNS_advance_pc (addr += 1, op-index += 0)
# CHECK-NEXT: DW_LNE_end_sequence
# CHECK-NEXT: DW_LNE_set_address (0x0000000000000042)
# CHECK-NEXT: DW_LNS_copy
# CHECK-NEXT: 0x0000000000000042 1
-# CHECK-NEXT: DW_LNS_advance_pc (1)
+# CHECK-NEXT: DW_LNS_advance_pc (addr += 1, op-index += 0)
# CHECK-NEXT: DW_LNE_end_sequence
# Dumping of the debug_addr, ranges, and rnglists sections don't do anything
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/verbose.test b/llvm/test/tools/llvm-dwarfdump/X86/verbose.test
index 0e74fc7a624e7f..f4513cf35c4d34 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/verbose.test
+++ b/llvm/test/tools/llvm-dwarfdump/X86/verbose.test
@@ -22,9 +22,9 @@
# CHECK-NEXT: 0x0000000000000000 1 0 1 0 0 0 is_stmt
# CHECK-NEXT:0x00000035: 05 DW_LNS_set_column (12)
# CHECK-NEXT:0x00000037: 0a DW_LNS_set_prologue_end
-# CHECK-NEXT:0x00000038: 66 address += 6, line += 0
+# CHECK-NEXT:0x00000038: 66 address += 6, line += 0, op-index += 0
# CHECK-NEXT: 0x0000000000000006 1 12 1 0 0 0 is_stmt prologue_end
-# CHECK-NEXT:0x00000039: 02 DW_LNS_advance_pc (2)
+# CHECK-NEXT:0x00000039: 02 DW_LNS_advance_pc (addr += 2, op-index += 0)
# CHECK-NEXT:0x0000003b: 00 DW_LNE_end_sequence
# CHECK-NEXT: 0x0000000000000008 1 12 1 0 0 0 is_stmt end_sequence
# CHECK-EMPTY:
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
index 871186700f07aa..9635011601cd25 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
@@ -1085,41 +1085,201 @@ struct AdjustAddressFixtureBase : public CommonFixture {
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 {
+struct OpIndexFixture : Test, CommonFixture {
+ void createPrologue(LineTable <, uint8_t MaxOpsPerInst,
+ uint8_t MinInstLength) {
DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue();
Prologue.MaxOpsPerInst = MaxOpsPerInst;
+ Prologue.MinInstLength = MinInstLength;
LT.setPrologue(Prologue);
- return Prologue.TotalLength + Prologue.sizeofTotalLength();
}
-
- uint8_t MaxOpsPerInst;
};
#ifdef _AIX
-TEST_P(MaxOpsPerInstFixture, DISABLED_MaxOpsPerInstProblemsReportedCorrectly) {
+TEST_F(OpIndexFixture, DISABLED_OpIndexAdvance) {
#else
-TEST_P(MaxOpsPerInstFixture, MaxOpsPerInstProblemsReportedCorrectly) {
+TEST_F(OpIndexFixture, OpIndexAdvance) {
#endif
- runTest(/*CheckAdvancePC=*/true,
- "but the prologue maximum_operations_per_instruction value is " +
- Twine(unsigned(MaxOpsPerInst)) +
- ", which is unsupported. Assuming a value of 1 instead");
+ if (!setupGenerator(4, 4))
+ GTEST_SKIP();
+
+ uint8_t MaxOpsPerInst = 13;
+ uint8_t MinInstLength = 4;
+
+ LineTable < = Gen->addLineTable();
+
+ // Row 0-2: Different locations for one bundle set up using special opcodes.
+ LT.addExtendedOpcode(5, DW_LNE_set_address, {{0x20, LineTable::Long}});
+ LT.addByte(0x13); // Special opcode, +1 line.
+ LT.addByte(0x23); // Special opcode, +3 line, +1 op-index.
+ LT.addByte(0x3a); // Special opcode, -2 line, +3 op-index.
+
+ // Row 3: New bundle, set up using DW_LNS_advance pc.
+ // Operation advance 0x84, which gives +40 addr, +2 op-index
+ LT.addStandardOpcode(DW_LNS_advance_line, {{100, LineTable::SLEB}});
+ LT.addStandardOpcode(DW_LNS_advance_pc, {{0x84, LineTable::ULEB}});
+ LT.addStandardOpcode(DW_LNS_copy, {}); // Create new row.
+
+ // Row 4: New bundle, set up using a single special opcode.
+ LT.addByte(0x71); // Special opcode, +4 addr, -3 line, -6 op-index.
+
+ // Row 5: New bundle, set up using using DW_LNS_const_add_pc.
+ // Corresponds to advancing address and op-index using special opcode 255,
+ // which gives +4 addr, +4 op-index.
+ LT.addStandardOpcode(DW_LNS_advance_line, {{10, LineTable::SLEB}});
+ LT.addStandardOpcode(DW_LNS_const_add_pc, {});
+ LT.addStandardOpcode(DW_LNS_copy, {}); // Create new row.
+
+ // Row 6: End sequence to have the input well-formed.
+ LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
+
+ createPrologue(LT, MaxOpsPerInst, MinInstLength);
+
+ generate();
+
+ auto VerifyRow = [](const DWARFDebugLine::Row &Row, uint64_t Address,
+ uint8_t OpIndex, uint32_t Line) {
+ EXPECT_EQ(Row.Address.Address, Address);
+ EXPECT_EQ(Row.OpIndex, OpIndex);
+ EXPECT_EQ(Row.Line, Line);
+ };
+
+ auto Table = Line.getOrParseLineTable(LineData, 0, *Context, nullptr,
+ RecordRecoverable);
+ EXPECT_THAT_ERROR(
+ std::move(Recoverable),
+ FailedWithMessage("line table program at offset 0x00000000 contains a "
+ "special opcode at offset 0x00000035, but the prologue "
+ "maximum_operations_per_instruction value is 13, which "
+ "is experimentally supported, so line number "
+ "information may be incorrect"));
+ EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded());
+ ASSERT_THAT_EXPECTED(Table, Succeeded());
+
+ ASSERT_EQ((*Table)->Rows.size(), 7u);
+
+ VerifyRow((*Table)->Rows[0], 0x20, 0, 2);
+ VerifyRow((*Table)->Rows[1], 0x20, 1, 5);
+ VerifyRow((*Table)->Rows[2], 0x20, 4, 3);
+ VerifyRow((*Table)->Rows[3], 0x48, 6, 103);
+ VerifyRow((*Table)->Rows[4], 0x4c, 0, 100);
+ VerifyRow((*Table)->Rows[5], 0x50, 4, 110);
}
-INSTANTIATE_TEST_SUITE_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).
+#ifdef _AIX
+TEST_F(OpIndexFixture, DISABLED_OpIndexReset) {
+#else
+TEST_F(OpIndexFixture, OpIndexReset) {
+#endif
+ if (!setupGenerator(4, 4))
+ GTEST_SKIP();
+
+ uint8_t MaxOpsPerInst = 13;
+ uint8_t MinInstLength = 4;
+
+ LineTable < = Gen->addLineTable();
+
+ // Row 0: Just set op-index to some value > 0.
+ LT.addExtendedOpcode(5, DW_LNE_set_address, {{0, LineTable::Long}});
+ LT.addByte(0x20); // Special opcode, +1 op-index
+
+ // Row 1: DW_LNE_fixed_advance_pc should set op-index to 0.
+ LT.addStandardOpcode(DW_LNS_fixed_advance_pc, {{10, LineTable::Half}});
+ LT.addStandardOpcode(DW_LNS_copy, {}); // Create new row.
+
+ // Row 2: Just set op-index to some value > 0.
+ LT.addByte(0x66); // Special opcode, +6 op-index
+
+ // Row 3: DW_LNE_set_address should set op-index to 0.
+ LT.addExtendedOpcode(5, DW_LNE_set_address, {{20, LineTable::Long}});
+ LT.addStandardOpcode(DW_LNS_copy, {}); // Create new row.
+
+ // Row 4: Just set op-index to some value > 0.
+ LT.addByte(0xba); // Special opcode, +12 op-index
+
+ // Row 5: End sequence (op-index unchanged for this row)...
+ LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
+
+ // Row 6: ... but shall be reset after the DW_LNE_end_sequence row.
+ LT.addStandardOpcode(DW_LNS_copy, {}); // Create new row.
+
+ // Row 7: End sequence to have the input well-formed.
+ LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
+
+ createPrologue(LT, MaxOpsPerInst, MinInstLength);
+
+ generate();
+
+ auto Table = Line.getOrParseLineTable(LineData, 0, *Context, nullptr,
+ RecordRecoverable);
+ EXPECT_THAT_ERROR(
+ std::move(Recoverable),
+ FailedWithMessage("line table program at offset 0x00000000 contains a "
+ "special opcode at offset 0x00000035, but the prologue "
+ "maximum_operations_per_instruction value is 13, which "
+ "is experimentally supported, so line number "
+ "information may be incorrect"));
+ EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded());
+ ASSERT_THAT_EXPECTED(Table, Succeeded());
+
+ ASSERT_EQ((*Table)->Rows.size(), 8u);
+ EXPECT_EQ((*Table)->Rows[0].OpIndex, 1u);
+ EXPECT_EQ((*Table)->Rows[1].OpIndex, 0u); // DW_LNS_fixed_advance_pc.
+ EXPECT_EQ((*Table)->Rows[2].OpIndex, 6u);
+ EXPECT_EQ((*Table)->Rows[3].OpIndex, 0u); // DW_LNE_set_address.
+ EXPECT_EQ((*Table)->Rows[4].OpIndex, 12u);
+ EXPECT_EQ((*Table)->Rows[5].OpIndex, 12u);
+ EXPECT_EQ((*Table)->Rows[6].OpIndex, 0u); // row after DW_LNE_end_sequence.
+ EXPECT_EQ((*Table)->Rows[7].OpIndex, 0u);
+}
+
+#ifdef _AIX
+TEST_F(OpIndexFixture, DISABLED_MaxOpsZeroDwarf3) {
+#else
+TEST_F(OpIndexFixture, MaxOpsZeroDwarf3) {
+#endif
+ if (!setupGenerator(3, 4))
+ GTEST_SKIP();
+
+ LineTable < = Gen->addLineTable();
+ LT.addStandardOpcode(DW_LNS_const_add_pc, {}); // Just some opcode to advance.
+ LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); //
+ createPrologue(LT, /*MaxOpsPerInst=*/0, /*MinInstLength=*/1);
+ generate();
+
+ auto Table = Line.getOrParseLineTable(LineData, 0, *Context, nullptr,
+ RecordRecoverable);
+ EXPECT_THAT_ERROR(std::move(Recoverable), Succeeded());
+ EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded());
+ ASSERT_THAT_EXPECTED(Table, Succeeded());
+}
+
+#ifdef _AIX
+TEST_F(OpIndexFixture, DISABLED_MaxOpsZeroDwarf4) {
+#else
+TEST_F(OpIndexFixture, MaxOpsZeroDwarf4) {
+#endif
+ if (!setupGenerator(4, 4))
+ GTEST_SKIP();
+
+ LineTable < = Gen->addLineTable();
+ LT.addStandardOpcode(DW_LNS_const_add_pc, {}); // Just some opcode to advance.
+ LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); //
+ createPrologue(LT, /*MaxOpsPerInst=*/0, /*MinInstLength=*/1);
+ generate();
+
+ auto Table = Line.getOrParseLineTable(LineData, 0, *Context, nullptr,
+ RecordRecoverable);
+ EXPECT_THAT_ERROR(
+ std::move(Recoverable),
+ FailedWithMessage(
+ "line table program at offset 0x00000000 contains a "
+ "DW_LNS_const_add_pc opcode at offset 0x0000002e, but "
+ "the prologue maximum_operations_per_instruction value "
+ "is 0, which is invalid. Assuming a value of 1 instead"));
+ EXPECT_THAT_ERROR(std::move(Unrecoverable), Succeeded());
+ ASSERT_THAT_EXPECTED(Table, Succeeded());
+}
struct LineRangeFixture : TestWithParam<std::tuple<uint8_t, bool>>,
AdjustAddressFixtureBase {
@@ -1572,22 +1732,26 @@ TEST_F(DebugLineBasicFixture, VerboseOutput) {
EXPECT_EQ(NextLine(), "0x00000059: 01 DW_LNS_copy");
EXPECT_EQ(NextLine(), " 0x0123456789abcdef 1 0 1 "
"0 127 0 is_stmt");
- EXPECT_EQ(NextLine(), "0x0000005a: 02 DW_LNS_advance_pc (11)");
+ EXPECT_EQ(NextLine(), "0x0000005a: 02 DW_LNS_advance_pc (addr += 11, "
+ "op-index += 0)");
EXPECT_EQ(NextLine(), "0x0000005c: 03 DW_LNS_advance_line (23)");
EXPECT_EQ(NextLine(), "0x0000005e: 04 DW_LNS_set_file (33)");
EXPECT_EQ(NextLine(), "0x00000060: 05 DW_LNS_set_column (44)");
EXPECT_EQ(NextLine(), "0x00000062: 06 DW_LNS_negate_stmt");
EXPECT_EQ(NextLine(), "0x00000063: 07 DW_LNS_set_basic_block");
EXPECT_EQ(NextLine(),
- "0x00000064: 08 DW_LNS_const_add_pc (0x0000000000000011)");
- EXPECT_EQ(NextLine(), "0x00000065: 09 DW_LNS_fixed_advance_pc (0x0037)");
+ "0x00000064: 08 DW_LNS_const_add_pc (addr += 0x0000000000000011, "
+ "op-index += 0)");
+ EXPECT_EQ(NextLine(), "0x00000065: 09 DW_LNS_fixed_advance_pc (addr += 0x0037"
+ ", op-index = 0)");
EXPECT_EQ(NextLine(), "0x00000068: 0a DW_LNS_set_prologue_end");
EXPECT_EQ(NextLine(), "0x00000069: 0b DW_LNS_set_epilogue_begin");
EXPECT_EQ(NextLine(), "0x0000006a: 0c DW_LNS_set_isa (66)");
EXPECT_EQ(NextLine(), "0x0000006c: 0d Unrecognized standard opcode "
"(operands: 0x0000000000000001, 0x0123456789abcdef)");
EXPECT_EQ(NextLine(), "0x00000077: 0e Unrecognized standard opcode");
- EXPECT_EQ(NextLine(), "0x00000078: ff address += 17, line += -3");
+ EXPECT_EQ(NextLine(), "0x00000078: ff address += 17, line += -3, "
+ "op-index += 0");
EXPECT_EQ(NextLine(),
" 0x0123456789abce53 20 44 33 66 "
" 0 0 basic_block prologue_end epilogue_begin");
More information about the llvm-commits
mailing list