1 //===-- SymbolFileDWARFTests.cpp --------------------------------*- C++ -*-===//
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/DWARFAbbreviationDeclaration.h"
19 #include "Plugins/SymbolFile/DWARF/DWARFDataExtractor.h"
20 #include "Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h"
21 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
22 #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
23 #include "TestingSupport/TestUtilities.h"
24 #include "lldb/Core/Address.h"
25 #include "lldb/Core/Module.h"
26 #include "lldb/Core/ModuleSpec.h"
27 #include "lldb/Host/FileSystem.h"
28 #include "lldb/Host/HostInfo.h"
29 #include "lldb/Symbol/ClangASTContext.h"
30 #include "lldb/Symbol/CompileUnit.h"
31 #include "lldb/Symbol/LineTable.h"
32 #include "lldb/Symbol/SymbolVendor.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 
39 
40 using namespace lldb;
41 using namespace lldb_private;
42 
43 class SymbolFileDWARFTests : public testing::Test {
44 public:
45   void SetUp() override {
46 // Initialize and TearDown the plugin every time, so we get a brand new
47 // AST every time so that modifications to the AST from each test don't
48 // leak into the next test.
49 FileSystem::Initialize();
50 HostInfo::Initialize();
51 ObjectFilePECOFF::Initialize();
52 SymbolFileDWARF::Initialize();
53 ClangASTContext::Initialize();
54 SymbolFilePDB::Initialize();
55 
56 m_dwarf_test_exe = GetInputFilePath("test-dwarf.exe");
57   }
58 
59   void TearDown() override {
60     SymbolFilePDB::Terminate();
61     ClangASTContext::Initialize();
62     SymbolFileDWARF::Terminate();
63     ObjectFilePECOFF::Terminate();
64     HostInfo::Terminate();
65     FileSystem::Terminate();
66   }
67 
68 protected:
69   std::string m_dwarf_test_exe;
70 };
71 
72 TEST_F(SymbolFileDWARFTests, TestAbilitiesForDWARF) {
73   // Test that when we have Dwarf debug info, SymbolFileDWARF is used.
74   FileSpec fspec(m_dwarf_test_exe);
75   ArchSpec aspec("i686-pc-windows");
76   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
77 
78   SymbolVendor *plugin = module->GetSymbolVendor();
79   EXPECT_NE(nullptr, plugin);
80   SymbolFile *symfile = plugin->GetSymbolFile();
81   EXPECT_NE(nullptr, symfile);
82   EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic());
83 
84   uint32_t expected_abilities = SymbolFile::kAllAbilities;
85   EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
86 }
87 
88 TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) {
89   // Test that if we have a .debug_abbrev that contains ordered abbreviation
90   // codes that start at 1, that we get O(1) access.
91 
92   const auto byte_order = eByteOrderLittle;
93   const uint8_t addr_size = 4;
94   StreamString encoder(Stream::eBinary, addr_size, byte_order);
95   encoder.PutULEB128(1); // Abbrev code 1
96   encoder.PutULEB128(DW_TAG_compile_unit);
97   encoder.PutHex8(DW_CHILDREN_yes);
98   encoder.PutULEB128(DW_AT_name);
99   encoder.PutULEB128(DW_FORM_strp);
100   encoder.PutULEB128(0);
101   encoder.PutULEB128(0);
102 
103   encoder.PutULEB128(2); // Abbrev code 2
104   encoder.PutULEB128(DW_TAG_subprogram);
105   encoder.PutHex8(DW_CHILDREN_no);
106   encoder.PutULEB128(DW_AT_name);
107   encoder.PutULEB128(DW_FORM_strp);
108   encoder.PutULEB128(0);
109   encoder.PutULEB128(0);
110 
111   encoder.PutULEB128(0); // Abbrev code 0 (termination)
112 
113   DWARFDataExtractor data;
114   data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
115   DWARFAbbreviationDeclarationSet abbrev_set;
116   lldb::offset_t data_offset = 0;
117   llvm::Error error = abbrev_set.extract(data, &data_offset);
118   EXPECT_FALSE(bool(error));
119   // Make sure we have O(1) access to each abbreviation by making sure the
120   // index offset is 1 and not UINT32_MAX
121   EXPECT_EQ(abbrev_set.GetIndexOffset(), 1u);
122 
123   auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(1);
124   EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit);
125   EXPECT_TRUE(abbrev1->HasChildren());
126   EXPECT_EQ(abbrev1->NumAttributes(), 1u);
127   auto abbrev2 = abbrev_set.GetAbbreviationDeclaration(2);
128   EXPECT_EQ(abbrev2->Tag(), DW_TAG_subprogram);
129   EXPECT_FALSE(abbrev2->HasChildren());
130   EXPECT_EQ(abbrev2->NumAttributes(), 1u);
131 }
132 
133 TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) {
134   // Test that if we have a .debug_abbrev that contains ordered abbreviation
135   // codes that start at 5, that we get O(1) access.
136 
137   const auto byte_order = eByteOrderLittle;
138   const uint8_t addr_size = 4;
139   StreamString encoder(Stream::eBinary, addr_size, byte_order);
140   encoder.PutULEB128(5); // Abbrev code 5
141   encoder.PutULEB128(DW_TAG_compile_unit);
142   encoder.PutHex8(DW_CHILDREN_yes);
143   encoder.PutULEB128(DW_AT_name);
144   encoder.PutULEB128(DW_FORM_strp);
145   encoder.PutULEB128(0);
146   encoder.PutULEB128(0);
147 
148   encoder.PutULEB128(6); // Abbrev code 6
149   encoder.PutULEB128(DW_TAG_subprogram);
150   encoder.PutHex8(DW_CHILDREN_no);
151   encoder.PutULEB128(DW_AT_name);
152   encoder.PutULEB128(DW_FORM_strp);
153   encoder.PutULEB128(0);
154   encoder.PutULEB128(0);
155 
156   encoder.PutULEB128(0); // Abbrev code 0 (termination)
157 
158   DWARFDataExtractor data;
159   data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
160   DWARFAbbreviationDeclarationSet abbrev_set;
161   lldb::offset_t data_offset = 0;
162   llvm::Error error = abbrev_set.extract(data, &data_offset);
163   EXPECT_FALSE(bool(error));
164   // Make sure we have O(1) access to each abbreviation by making sure the
165   // index offset is 5 and not UINT32_MAX
166   EXPECT_EQ(abbrev_set.GetIndexOffset(), 5u);
167 
168   auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(5);
169   EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit);
170   EXPECT_TRUE(abbrev1->HasChildren());
171   EXPECT_EQ(abbrev1->NumAttributes(), 1u);
172   auto abbrev2 = abbrev_set.GetAbbreviationDeclaration(6);
173   EXPECT_EQ(abbrev2->Tag(), DW_TAG_subprogram);
174   EXPECT_FALSE(abbrev2->HasChildren());
175   EXPECT_EQ(abbrev2->NumAttributes(), 1u);
176 }
177 
178 TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) {
179   // Test that if we have a .debug_abbrev that contains unordered abbreviation
180   // codes, that we can access the information correctly.
181 
182   const auto byte_order = eByteOrderLittle;
183   const uint8_t addr_size = 4;
184   StreamString encoder(Stream::eBinary, addr_size, byte_order);
185   encoder.PutULEB128(2); // Abbrev code 2
186   encoder.PutULEB128(DW_TAG_compile_unit);
187   encoder.PutHex8(DW_CHILDREN_yes);
188   encoder.PutULEB128(DW_AT_name);
189   encoder.PutULEB128(DW_FORM_strp);
190   encoder.PutULEB128(0);
191   encoder.PutULEB128(0);
192 
193   encoder.PutULEB128(1); // Abbrev code 1
194   encoder.PutULEB128(DW_TAG_subprogram);
195   encoder.PutHex8(DW_CHILDREN_no);
196   encoder.PutULEB128(DW_AT_name);
197   encoder.PutULEB128(DW_FORM_strp);
198   encoder.PutULEB128(0);
199   encoder.PutULEB128(0);
200 
201   encoder.PutULEB128(0); // Abbrev code 0 (termination)
202 
203   DWARFDataExtractor data;
204   data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
205   DWARFAbbreviationDeclarationSet abbrev_set;
206   lldb::offset_t data_offset = 0;
207   llvm::Error error = abbrev_set.extract(data, &data_offset);
208   EXPECT_FALSE(bool(error));
209   // Make sure we don't have O(1) access to each abbreviation by making sure
210   // the index offset is UINT32_MAX
211   EXPECT_EQ(abbrev_set.GetIndexOffset(), UINT32_MAX);
212 
213   auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(2);
214   EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit);
215   EXPECT_TRUE(abbrev1->HasChildren());
216   EXPECT_EQ(abbrev1->NumAttributes(), 1u);
217   auto abbrev2 = abbrev_set.GetAbbreviationDeclaration(1);
218   EXPECT_EQ(abbrev2->Tag(), DW_TAG_subprogram);
219   EXPECT_FALSE(abbrev2->HasChildren());
220   EXPECT_EQ(abbrev2->NumAttributes(), 1u);
221 }
222 
223 TEST_F(SymbolFileDWARFTests, TestAbbrevInvalidNULLTag) {
224   // Test that we detect when an abbreviation has a NULL tag and that we get
225   // an error when decoding.
226 
227   const auto byte_order = eByteOrderLittle;
228   const uint8_t addr_size = 4;
229   StreamString encoder(Stream::eBinary, addr_size, byte_order);
230   encoder.PutULEB128(1); // Abbrev code 1
231   encoder.PutULEB128(0); // Invalid NULL tag here!
232   encoder.PutHex8(DW_CHILDREN_no);
233   encoder.PutULEB128(0);
234   encoder.PutULEB128(0);
235 
236   encoder.PutULEB128(0); // Abbrev code 0 (termination)
237 
238   DWARFDataExtractor data;
239   data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
240   DWARFAbbreviationDeclarationSet abbrev_set;
241   lldb::offset_t data_offset = 0;
242   llvm::Error error = abbrev_set.extract(data, &data_offset);
243   // Verify we get an error
244   EXPECT_TRUE(bool(error));
245   EXPECT_EQ("abbrev decl requires non-null tag.",
246             llvm::toString(std::move(error)));
247 
248 }
249 
250 TEST_F(SymbolFileDWARFTests, TestAbbrevNullAttrValidForm) {
251   // Test that we detect when an abbreviation has a NULL attribute and a non
252   // NULL form and that we get an error when decoding.
253 
254   const auto byte_order = eByteOrderLittle;
255   const uint8_t addr_size = 4;
256   StreamString encoder(Stream::eBinary, addr_size, byte_order);
257   encoder.PutULEB128(1); // Abbrev code 1
258   encoder.PutULEB128(DW_TAG_compile_unit);
259   encoder.PutHex8(DW_CHILDREN_no);
260   encoder.PutULEB128(0); // Invalid NULL DW_AT
261   encoder.PutULEB128(DW_FORM_strp); // With a valid form
262   encoder.PutULEB128(0);
263   encoder.PutULEB128(0);
264 
265   encoder.PutULEB128(0); // Abbrev code 0 (termination)
266 
267   DWARFDataExtractor data;
268   data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
269   DWARFAbbreviationDeclarationSet abbrev_set;
270   lldb::offset_t data_offset = 0;
271   llvm::Error error = abbrev_set.extract(data, &data_offset);
272   // Verify we get an error
273   EXPECT_TRUE(bool(error));
274   EXPECT_EQ("malformed abbreviation declaration attribute",
275             llvm::toString(std::move(error)));
276 
277 }
278 
279 TEST_F(SymbolFileDWARFTests, TestAbbrevValidAttrNullForm) {
280   // Test that we detect when an abbreviation has a valid attribute and a
281   // NULL form and that we get an error when decoding.
282 
283   const auto byte_order = eByteOrderLittle;
284   const uint8_t addr_size = 4;
285   StreamString encoder(Stream::eBinary, addr_size, byte_order);
286   encoder.PutULEB128(1); // Abbrev code 1
287   encoder.PutULEB128(DW_TAG_compile_unit);
288   encoder.PutHex8(DW_CHILDREN_no);
289   encoder.PutULEB128(DW_AT_name); // Valid attribute
290   encoder.PutULEB128(0); // NULL form
291   encoder.PutULEB128(0);
292   encoder.PutULEB128(0);
293 
294   encoder.PutULEB128(0); // Abbrev code 0 (termination)
295 
296   DWARFDataExtractor data;
297   data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
298   DWARFAbbreviationDeclarationSet abbrev_set;
299   lldb::offset_t data_offset = 0;
300   llvm::Error error = abbrev_set.extract(data, &data_offset);
301   // Verify we get an error
302   EXPECT_TRUE(bool(error));
303   EXPECT_EQ("malformed abbreviation declaration attribute",
304             llvm::toString(std::move(error)));
305 }
306 
307 TEST_F(SymbolFileDWARFTests, TestAbbrevMissingTerminator) {
308   // Test that we detect when an abbreviation has a valid attribute and a
309   // form, but is missing the NULL attribute and form that terminates an
310   // abbreviation
311 
312   const auto byte_order = eByteOrderLittle;
313   const uint8_t addr_size = 4;
314   StreamString encoder(Stream::eBinary, addr_size, byte_order);
315   encoder.PutULEB128(1); // Abbrev code 1
316   encoder.PutULEB128(DW_TAG_compile_unit);
317   encoder.PutHex8(DW_CHILDREN_no);
318   encoder.PutULEB128(DW_AT_name);
319   encoder.PutULEB128(DW_FORM_strp);
320   // Don't add the NULL DW_AT and NULL DW_FORM terminator
321 
322   DWARFDataExtractor data;
323   data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
324   DWARFAbbreviationDeclarationSet abbrev_set;
325   lldb::offset_t data_offset = 0;
326   llvm::Error error = abbrev_set.extract(data, &data_offset);
327   // Verify we get an error
328   EXPECT_TRUE(bool(error));
329   EXPECT_EQ("abbreviation declaration attribute list not terminated with a "
330             "null entry", llvm::toString(std::move(error)));
331 }
332