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
38using namespace lldb;
39using namespace lldb_private;
40using namespace lldb_private::dwarf;
41using namespace lldb_private::plugin::dwarf;
42
43class SymbolFileDWARFTests : public testing::Test {
44 SubsystemRAII<FileSystem, HostInfo, ObjectFilePECOFF, SymbolFileDWARF,
45 TypeSystemClang, SymbolFilePDB>
46 subsystems;
47
48public:
49 void SetUp() override {
50 m_dwarf_test_exe = GetInputFilePath(name: "test-dwarf.exe");
51 }
52
53protected:
54 std::string m_dwarf_test_exe;
55};
56
57TEST_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
71TEST_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
106TEST_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
152TEST_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
195TEST_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
234TEST_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

source code of lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp