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