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