diff options
author | David Stenberg <david.stenberg@ericsson.com> | 2023-07-12 12:14:46 +0200 |
---|---|---|
committer | David Stenberg <david.stenberg@ericsson.com> | 2023-07-12 13:46:29 +0200 |
commit | fe6cddef2020c8e103cff8180540d4e2e9102c6d (patch) | |
tree | a9864b3a0783816f9957e8e20064288c19a99666 /llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp | |
parent | 593797ab9bedca6e9b0b7a9ed0589cf76023ab00 (diff) | |
download | llvm-fe6cddef2020c8e103cff8180540d4e2e9102c6d.zip llvm-fe6cddef2020c8e103cff8180540d4e2e9102c6d.tar.gz llvm-fe6cddef2020c8e103cff8180540d4e2e9102c6d.tar.bz2 |
[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
Diffstat (limited to 'llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp')
-rw-r--r-- | llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp | 220 |
1 files changed, 192 insertions, 28 deletions
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp index 8711867..9635011 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"); |