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