1 | //===-- SymbolFileDWARFTests.cpp ------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "gtest/gtest.h" |
10 | |
11 | #include "llvm/ADT/STLExtras.h" |
12 | #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" |
13 | #include "llvm/DebugInfo/PDB/PDBSymbolData.h" |
14 | #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" |
15 | #include "llvm/Support/FileSystem.h" |
16 | #include "llvm/Support/Path.h" |
17 | |
18 | #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" |
19 | #include "Plugins/SymbolFile/DWARF/DWARFDataExtractor.h" |
20 | #include "Plugins/SymbolFile/DWARF/DWARFDebugAranges.h" |
21 | #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" |
22 | #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" |
23 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
24 | #include "TestingSupport/SubsystemRAII.h" |
25 | #include "TestingSupport/TestUtilities.h" |
26 | #include "lldb/Core/Address.h" |
27 | #include "lldb/Core/Module.h" |
28 | #include "lldb/Core/ModuleSpec.h" |
29 | #include "lldb/Host/FileSystem.h" |
30 | #include "lldb/Host/HostInfo.h" |
31 | #include "lldb/Symbol/CompileUnit.h" |
32 | #include "lldb/Symbol/LineTable.h" |
33 | #include "lldb/Utility/ArchSpec.h" |
34 | #include "lldb/Utility/DataEncoder.h" |
35 | #include "lldb/Utility/FileSpec.h" |
36 | #include "lldb/Utility/StreamString.h" |
37 | |
38 | using namespace lldb; |
39 | using namespace lldb_private; |
40 | using namespace lldb_private::dwarf; |
41 | using namespace lldb_private::plugin::dwarf; |
42 | using llvm::DWARFDebugArangeSet; |
43 | |
44 | class SymbolFileDWARFTests : public testing::Test { |
45 | SubsystemRAII<FileSystem, HostInfo, ObjectFilePECOFF, SymbolFileDWARF, |
46 | TypeSystemClang, SymbolFilePDB> |
47 | subsystems; |
48 | |
49 | public: |
50 | void SetUp() override { |
51 | m_dwarf_test_exe = GetInputFilePath(name: "test-dwarf.exe" ); |
52 | } |
53 | |
54 | protected: |
55 | std::string m_dwarf_test_exe; |
56 | }; |
57 | |
58 | TEST_F(SymbolFileDWARFTests, TestAbilitiesForDWARF) { |
59 | // Test that when we have Dwarf debug info, SymbolFileDWARF is used. |
60 | FileSpec fspec(m_dwarf_test_exe); |
61 | ArchSpec aspec("i686-pc-windows" ); |
62 | lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec); |
63 | |
64 | SymbolFile *symfile = module->GetSymbolFile(); |
65 | ASSERT_NE(nullptr, symfile); |
66 | EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic()); |
67 | |
68 | uint32_t expected_abilities = SymbolFile::kAllAbilities; |
69 | EXPECT_EQ(expected_abilities, symfile->CalculateAbilities()); |
70 | } |
71 | |
72 | TEST_F(SymbolFileDWARFTests, ParseArangesNonzeroSegmentSize) { |
73 | // This `.debug_aranges` table header is a valid 32bit big-endian section |
74 | // according to the DWARFv5 spec:6.2.1, but contains segment selectors which |
75 | // are not supported by lldb, and should be gracefully rejected |
76 | const unsigned char binary_data[] = { |
77 | 0, 0, 0, 41, // unit_length (length field not including this field itself) |
78 | 0, 2, // DWARF version number (half) |
79 | 0, 0, 0, 0, // offset into the .debug_info_table (ignored for the purposes |
80 | // of this test |
81 | 4, // address size |
82 | 1, // segment size |
83 | // alignment for the first tuple which "begins at an offset that is a |
84 | // multiple of the size of a single tuple". Tuples are nine bytes in this |
85 | // example. |
86 | 0, 0, 0, 0, 0, 0, |
87 | // BEGIN TUPLES |
88 | 1, 0, 0, 0, 4, 0, 0, 0, |
89 | 1, // a 1byte object starting at address 4 in segment 1 |
90 | 0, 0, 0, 0, 4, 0, 0, 0, |
91 | 1, // a 1byte object starting at address 4 in segment 0 |
92 | // END TUPLES |
93 | 0, 0, 0, 0, 0, 0, 0, 0, 0 // terminator |
94 | }; |
95 | llvm::DWARFDataExtractor data(llvm::ArrayRef<unsigned char>(binary_data), |
96 | /*isLittleEndian=*/false, /*AddrSize=*/4); |
97 | |
98 | DWARFDebugArangeSet debug_aranges; |
99 | offset_t off = 0; |
100 | llvm::Error error = debug_aranges.extract(data, offset_ptr: &off); |
101 | EXPECT_TRUE(bool(error)); |
102 | EXPECT_EQ("non-zero segment selector size in address range table at offset " |
103 | "0x0 is not supported" , |
104 | llvm::toString(std::move(error))); |
105 | EXPECT_EQ(off, 12U); // Parser should read no further than the segment size |
106 | } |
107 | |
108 | TEST_F(SymbolFileDWARFTests, ParseArangesWithMultipleTerminators) { |
109 | // This .debug_aranges set has multiple terminator entries which appear in |
110 | // binaries produced by popular linux compilers and linker combinations. We |
111 | // must be able to parse all the way through the data for each |
112 | // DWARFDebugArangeSet. Previously the DWARFDebugArangeSet::extract() |
113 | // function would stop parsing as soon as we ran into a terminator even |
114 | // though the length field stated that there was more data that follows. This |
115 | // would cause the next DWARFDebugArangeSet to be parsed immediately |
116 | // following the first terminator and it would attempt to decode the |
117 | // DWARFDebugArangeSet header using the remaining segment + address pairs |
118 | // from the remaining bytes. |
119 | unsigned char binary_data[] = { |
120 | 0, 0, 0, 0, // unit_length that will be set correctly after this |
121 | 0, 2, // DWARF version number (uint16_t) |
122 | 0, 0, 0, 255, // CU offset |
123 | 4, // address size |
124 | 0, // segment size |
125 | 0, 0, 0, 0, // alignment for the first tuple |
126 | // BEGIN TUPLES |
127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // premature terminator |
128 | 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100) |
129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // premature terminator |
130 | 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, // [0x2000-0x2010) |
131 | // END TUPLES |
132 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator |
133 | }; |
134 | // Set the big endian length correctly. |
135 | const offset_t binary_data_size = sizeof(binary_data); |
136 | binary_data[3] = (uint8_t)binary_data_size - 4; |
137 | DWARFDataExtractor data; |
138 | data.SetData(bytes: static_cast<const void *>(binary_data), length: sizeof binary_data, |
139 | byte_order: lldb::ByteOrder::eByteOrderBig); |
140 | DWARFDebugAranges debug_aranges; |
141 | debug_aranges.extract(debug_aranges_data: data); |
142 | // Parser should read all terminators to the end of the length specified. |
143 | ASSERT_EQ(debug_aranges.GetNumRanges(), 2U); |
144 | EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET); |
145 | EXPECT_EQ(debug_aranges.FindAddress(0x1000), 255u); |
146 | EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 255u); |
147 | EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET); |
148 | EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET); |
149 | EXPECT_EQ(debug_aranges.FindAddress(0x2000), 255u); |
150 | EXPECT_EQ(debug_aranges.FindAddress(0x2010 - 1), 255u); |
151 | EXPECT_EQ(debug_aranges.FindAddress(0x2010), DW_INVALID_OFFSET); |
152 | } |
153 | |
154 | TEST_F(SymbolFileDWARFTests, ParseArangesIgnoreEmpty) { |
155 | // This .debug_aranges set has some address ranges which have zero length |
156 | // and we ensure that these are ignored by our DWARFDebugArangeSet parser |
157 | // and not included in the descriptors that are returned. |
158 | unsigned char binary_data[] = { |
159 | 0, 0, 0, 0, // unit_length that will be set correctly after this |
160 | 0, 2, // DWARF version number (uint16_t) |
161 | 0, 0, 0, 255, // CU offset |
162 | 4, // address size |
163 | 0, // segment size |
164 | 0, 0, 0, 0, // alignment for the first tuple |
165 | // BEGIN TUPLES |
166 | 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100) |
167 | 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, // [0x1100-0x1100) |
168 | 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, // [0x2000-0x2010) |
169 | 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, // [0x2010-0x2010) |
170 | // END TUPLES |
171 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator |
172 | }; |
173 | // Set the big endian length correctly. |
174 | const offset_t binary_data_size = sizeof(binary_data); |
175 | binary_data[3] = (uint8_t)binary_data_size - 4; |
176 | DWARFDataExtractor data; |
177 | data.SetData(bytes: static_cast<const void *>(binary_data), length: sizeof binary_data, |
178 | byte_order: lldb::ByteOrder::eByteOrderBig); |
179 | DWARFDebugAranges debug_aranges; |
180 | debug_aranges.extract(debug_aranges_data: data); |
181 | // Parser should read all terminators to the end of the length specified. |
182 | // Previously the DWARFDebugArangeSet would stop at the first terminator |
183 | // entry and leave the offset in the middle of the current |
184 | // DWARFDebugArangeSet data, and that would cause the next extracted |
185 | // DWARFDebugArangeSet to fail. |
186 | ASSERT_EQ(debug_aranges.GetNumRanges(), 2U); |
187 | EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET); |
188 | EXPECT_EQ(debug_aranges.FindAddress(0x1000), 255u); |
189 | EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 255u); |
190 | EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET); |
191 | EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET); |
192 | EXPECT_EQ(debug_aranges.FindAddress(0x2000), 255u); |
193 | EXPECT_EQ(debug_aranges.FindAddress(0x2010 - 1), 255u); |
194 | EXPECT_EQ(debug_aranges.FindAddress(0x2010), DW_INVALID_OFFSET); |
195 | } |
196 | |
197 | TEST_F(SymbolFileDWARFTests, ParseAranges) { |
198 | // Test we can successfully parse a DWARFDebugAranges. The initial error |
199 | // checking code had a bug where it would always return an empty address |
200 | // ranges for everything in .debug_aranges and no error. |
201 | unsigned char binary_data[] = { |
202 | 0, 0, 0, 0, // unit_length that will be set correctly after this |
203 | 2, 0, // DWARF version number |
204 | 255, 0, 0, 0, // offset into the .debug_info_table |
205 | 8, // address size |
206 | 0, // segment size |
207 | 0, 0, 0, 0, // pad bytes |
208 | // BEGIN TUPLES |
209 | // First tuple: [0x1000-0x1100) |
210 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x1000 |
211 | 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100 |
212 | // Second tuple: [0x2000-0x2100) |
213 | 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x2000 |
214 | 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100 |
215 | // Terminating tuple |
216 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Terminator |
217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Terminator |
218 | }; |
219 | // Set the little endian length correctly. |
220 | binary_data[0] = sizeof(binary_data) - 4; |
221 | DWARFDataExtractor data; |
222 | data.SetData(bytes: static_cast<const void *>(binary_data), length: sizeof binary_data, |
223 | byte_order: lldb::ByteOrder::eByteOrderLittle); |
224 | DWARFDebugAranges debug_aranges; |
225 | debug_aranges.extract(debug_aranges_data: data); |
226 | EXPECT_EQ(debug_aranges.GetNumRanges(), 2u); |
227 | EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET); |
228 | EXPECT_EQ(debug_aranges.FindAddress(0x1000), 255u); |
229 | EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 255u); |
230 | EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET); |
231 | EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET); |
232 | EXPECT_EQ(debug_aranges.FindAddress(0x2000), 255u); |
233 | EXPECT_EQ(debug_aranges.FindAddress(0x2100 - 1), 255u); |
234 | EXPECT_EQ(debug_aranges.FindAddress(0x2100), DW_INVALID_OFFSET); |
235 | } |
236 | |
237 | TEST_F(SymbolFileDWARFTests, ParseArangesSkipErrors) { |
238 | // Test we can successfully parse a DWARFDebugAranges that contains some |
239 | // valid DWARFDebugArangeSet objects and some with errors as long as their |
240 | // length is set correctly. This helps LLDB ensure that it can parse newer |
241 | // .debug_aranges version that LLDB currently doesn't support, or ignore |
242 | // errors in individual DWARFDebugArangeSet objects as long as the length |
243 | // is set correctly. |
244 | const unsigned char binary_data[] = { |
245 | // This DWARFDebugArangeSet is well formed and has a single address range |
246 | // for [0x1000-0x1100) with a CU offset of 0x00000000. |
247 | 0, 0, 0, 28, // unit_length that will be set correctly after this |
248 | 0, 2, // DWARF version number (uint16_t) |
249 | 0, 0, 0, 0, // CU offset = 0x00000000 |
250 | 4, // address size |
251 | 0, // segment size |
252 | 0, 0, 0, 0, // alignment for the first tuple |
253 | 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100) |
254 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator |
255 | // This DWARFDebugArangeSet has the correct length, but an invalid |
256 | // version. We need to be able to skip this correctly and ignore it. |
257 | 0, 0, 0, 20, // unit_length that will be set correctly after this |
258 | 0, 44, // invalid DWARF version number (uint16_t) |
259 | 0, 0, 1, 0, // CU offset = 0x00000100 |
260 | 4, // address size |
261 | 0, // segment size |
262 | 0, 0, 0, 0, // alignment for the first tuple |
263 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator |
264 | // This DWARFDebugArangeSet is well formed and has a single address range |
265 | // for [0x2000-0x2100) with a CU offset of 0x00000000. |
266 | 0, 0, 0, 28, // unit_length that will be set correctly after this |
267 | 0, 2, // DWARF version number (uint16_t) |
268 | 0, 0, 2, 0, // CU offset = 0x00000200 |
269 | 4, // address size |
270 | 0, // segment size |
271 | 0, 0, 0, 0, // alignment for the first tuple |
272 | 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x2000-0x2100) |
273 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator |
274 | }; |
275 | |
276 | DWARFDataExtractor data; |
277 | data.SetData(bytes: static_cast<const void *>(binary_data), length: sizeof binary_data, |
278 | byte_order: lldb::ByteOrder::eByteOrderBig); |
279 | DWARFDebugAranges debug_aranges; |
280 | debug_aranges.extract(debug_aranges_data: data); |
281 | EXPECT_EQ(debug_aranges.GetNumRanges(), 2u); |
282 | EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET); |
283 | EXPECT_EQ(debug_aranges.FindAddress(0x1000), 0u); |
284 | EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 0u); |
285 | EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET); |
286 | EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET); |
287 | EXPECT_EQ(debug_aranges.FindAddress(0x2000), 0x200u); |
288 | EXPECT_EQ(debug_aranges.FindAddress(0x2100 - 1), 0x200u); |
289 | EXPECT_EQ(debug_aranges.FindAddress(0x2100), DW_INVALID_OFFSET); |
290 | } |
291 | |