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