|
6 | 6 | //
|
7 | 7 | //===----------------------------------------------------------------------===//
|
8 | 8 |
|
| 9 | +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" |
9 | 10 | #include "DwarfGenerator.h"
|
10 | 11 | #include "DwarfUtils.h"
|
11 | 12 | #include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
12 |
| -#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" |
13 | 13 | #include "llvm/Object/ObjectFile.h"
|
14 | 14 | #include "llvm/Testing/Support/Error.h"
|
15 | 15 | #include "gtest/gtest.h"
|
@@ -2035,4 +2035,135 @@ TEST_F(DebugLineBasicFixture, PrintPathsProperly) {
|
2035 | 2035 | EXPECT_THAT(Result.c_str(), MatchesRegex("a dir.b dir.b file"));
|
2036 | 2036 | }
|
2037 | 2037 |
|
| 2038 | +/// Test that lookupAddressRange correctly filters rows based on |
| 2039 | +/// DW_AT_LLVM_stmt_sequence. |
| 2040 | +/// |
| 2041 | +/// This test verifies that: |
| 2042 | +/// 1. When a DIE has a DW_AT_LLVM_stmt_sequence attribute, lookupAddressRange |
| 2043 | +/// only returns rows from the sequence starting at the specified offset |
| 2044 | +/// 2. When a DIE has an invalid DW_AT_LLVM_stmt_sequence offset, no rows are |
| 2045 | +/// returned |
| 2046 | +/// 3. When no DW_AT_LLVM_stmt_sequence is present, all matching rows are |
| 2047 | +/// returned |
| 2048 | +/// |
| 2049 | +/// The test creates a line table with two sequences at the same address range |
| 2050 | +/// but different line numbers. It then creates three subprogram DIEs: |
| 2051 | +/// - One with DW_AT_LLVM_stmt_sequence pointing to the first sequence |
| 2052 | +/// - One with DW_AT_LLVM_stmt_sequence pointing to the second sequence |
| 2053 | +/// - One with an invalid DW_AT_LLVM_stmt_sequence offset |
| 2054 | +TEST_F(DebugLineBasicFixture, LookupAddressRangeWithStmtSequenceOffset) { |
| 2055 | + if (!setupGenerator()) |
| 2056 | + GTEST_SKIP(); |
| 2057 | + |
| 2058 | + // Create new DWARF with the subprogram DIE |
| 2059 | + dwarfgen::CompileUnit &CU = Gen->addCompileUnit(); |
| 2060 | + dwarfgen::DIE CUDie = CU.getUnitDIE(); |
| 2061 | + |
| 2062 | + CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c"); |
| 2063 | + CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C); |
| 2064 | + |
| 2065 | + dwarfgen::DIE SD1 = CUDie.addChild(DW_TAG_subprogram); |
| 2066 | + SD1.addAttribute(DW_AT_name, DW_FORM_strp, "sub1"); |
| 2067 | + SD1.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x1000U); |
| 2068 | + SD1.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x1032U); |
| 2069 | + // DW_AT_LLVM_stmt_sequence points to the first sequence |
| 2070 | + SD1.addAttribute(DW_AT_LLVM_stmt_sequence, DW_FORM_sec_offset, 0x2e); |
| 2071 | + |
| 2072 | + dwarfgen::DIE SD2 = CUDie.addChild(DW_TAG_subprogram); |
| 2073 | + SD2.addAttribute(DW_AT_name, DW_FORM_strp, "sub2"); |
| 2074 | + SD2.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x1000U); |
| 2075 | + SD2.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x1032U); |
| 2076 | + // DW_AT_LLVM_stmt_sequence points to the second sequence |
| 2077 | + SD2.addAttribute(DW_AT_LLVM_stmt_sequence, DW_FORM_sec_offset, 0x42); |
| 2078 | + |
| 2079 | + dwarfgen::DIE SD3 = CUDie.addChild(DW_TAG_subprogram); |
| 2080 | + SD3.addAttribute(DW_AT_name, DW_FORM_strp, "sub3"); |
| 2081 | + SD3.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x1000U); |
| 2082 | + SD3.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x1032U); |
| 2083 | + // Invalid DW_AT_LLVM_stmt_sequence |
| 2084 | + SD3.addAttribute(DW_AT_LLVM_stmt_sequence, DW_FORM_sec_offset, 0x66); |
| 2085 | + |
| 2086 | + // Create a line table with multiple sequences |
| 2087 | + LineTable < = Gen->addLineTable(); |
| 2088 | + |
| 2089 | + // First sequence with addresses 0x1000(Ln100), 0x1004(Ln101) |
| 2090 | + LT.addExtendedOpcode(9, DW_LNE_set_address, {{0x1000U, LineTable::Quad}}); |
| 2091 | + LT.addStandardOpcode(DW_LNS_set_prologue_end, {}); |
| 2092 | + LT.addStandardOpcode(DW_LNS_advance_line, {{99, LineTable::SLEB}}); |
| 2093 | + LT.addStandardOpcode(DW_LNS_copy, {}); |
| 2094 | + LT.addByte(0x4b); // Special opcode: address += 4, line += 1 |
| 2095 | + LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); |
| 2096 | + |
| 2097 | + // Second sequence with addresses 0x1000(Ln200), 0x1004(Ln201) |
| 2098 | + LT.addExtendedOpcode(9, DW_LNE_set_address, {{0x1000U, LineTable::Quad}}); |
| 2099 | + LT.addStandardOpcode(DW_LNS_set_prologue_end, {}); |
| 2100 | + LT.addStandardOpcode(DW_LNS_advance_line, {{199, LineTable::SLEB}}); |
| 2101 | + LT.addStandardOpcode(DW_LNS_copy, {}); |
| 2102 | + LT.addByte(0x4b); // Special opcode: address += 4, line += 1 |
| 2103 | + LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); |
| 2104 | + |
| 2105 | + // Generate the DWARF |
| 2106 | + generate(); |
| 2107 | + |
| 2108 | + // Parse the line table to get the sequence offset |
| 2109 | + auto ExpectedLineTable = Line.getOrParseLineTable( |
| 2110 | + LineData, /*Offset=*/0, *Context, nullptr, RecordRecoverable); |
| 2111 | + ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); |
| 2112 | + const auto *Table = *ExpectedLineTable; |
| 2113 | + |
| 2114 | + uint32_t NumCUs = Context->getNumCompileUnits(); |
| 2115 | + ASSERT_EQ(NumCUs, 1u); |
| 2116 | + DWARFUnit *Unit = Context->getUnitAtIndex(0); |
| 2117 | + auto DwarfCUDie = Unit->getUnitDIE(false); |
| 2118 | + |
| 2119 | + auto Sub1Die = DwarfCUDie.getFirstChild(); |
| 2120 | + auto Sub2Die = Sub1Die.getSibling(); |
| 2121 | + auto Sub3Die = Sub2Die.getSibling(); |
| 2122 | + |
| 2123 | + // Verify Sub1Die is the DIE generated from SD1 |
| 2124 | + auto NameAttr1 = Sub1Die.find(DW_AT_name); |
| 2125 | + EXPECT_STREQ(*dwarf::toString(*NameAttr1), "sub1"); |
| 2126 | + |
| 2127 | + // Verify Sub2Die is the DIE generated from SD2 |
| 2128 | + auto NameAttr2 = Sub2Die.find(DW_AT_name); |
| 2129 | + EXPECT_STREQ(*dwarf::toString(*NameAttr2), "sub2"); |
| 2130 | + |
| 2131 | + // Verify Sub2Die is the DIE generated from SD3 |
| 2132 | + auto NameAttr3 = Sub3Die.find(DW_AT_name); |
| 2133 | + EXPECT_STREQ(*dwarf::toString(*NameAttr3), "sub3"); |
| 2134 | + |
| 2135 | + // Ensure there are two sequences |
| 2136 | + ASSERT_EQ(Table->Sequences.size(), 2u); |
| 2137 | + |
| 2138 | + // Lookup addresses in the first sequence with the second sequence's filter |
| 2139 | + { |
| 2140 | + std::vector<uint32_t> Rows; |
| 2141 | + bool Found; |
| 2142 | + |
| 2143 | + // Look up using Sub3Die, which has an invalid DW_AT_LLVM_stmt_sequence |
| 2144 | + Found = Table->lookupAddressRange( |
| 2145 | + {0x1000, object::SectionedAddress::UndefSection}, /*Size=*/1, Rows, |
| 2146 | + &Sub3Die); |
| 2147 | + EXPECT_FALSE(Found); |
| 2148 | + |
| 2149 | + // Look up using Sub1Die, which has a valid DW_AT_LLVM_stmt_sequence and |
| 2150 | + // should return row 0 |
| 2151 | + Found = Table->lookupAddressRange( |
| 2152 | + {0x1000, object::SectionedAddress::UndefSection}, /*Size=*/1, Rows, |
| 2153 | + &Sub1Die); |
| 2154 | + EXPECT_TRUE(Found); |
| 2155 | + ASSERT_EQ(Rows.size(), 1u); |
| 2156 | + EXPECT_EQ(Rows[0], 0); |
| 2157 | + |
| 2158 | + // Look up using Sub2Die, which has a valid DW_AT_LLVM_stmt_sequence and |
| 2159 | + // should return row 3 |
| 2160 | + Rows.clear(); |
| 2161 | + Found = Table->lookupAddressRange( |
| 2162 | + {0x1000, object::SectionedAddress::UndefSection}, /*Size=*/1, Rows, |
| 2163 | + &Sub2Die); |
| 2164 | + EXPECT_TRUE(Found); |
| 2165 | + ASSERT_EQ(Rows.size(), 1u); |
| 2166 | + EXPECT_EQ(Rows[0], 3); |
| 2167 | + } |
| 2168 | +} |
2038 | 2169 | } // end anonymous namespace
|
0 commit comments