xref: /llvm-project/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp (revision a8b4c11f9d51f3d735f76c98367c87d6ff328a32)
1 //===- DWARFAcceleratorTableTest.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 "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
10 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
11 #include "llvm/ObjectYAML/DWARFEmitter.h"
12 #include "llvm/Testing/Support/Error.h"
13 #include "gtest/gtest.h"
14 
15 using namespace llvm;
16 
ExtractDebugNames(StringRef NamesSecData,StringRef StrSecData)17 static Error ExtractDebugNames(StringRef NamesSecData, StringRef StrSecData) {
18   DWARFDataExtractor NamesExtractor(NamesSecData,
19                                     /*isLittleEndian=*/true,
20                                     /*AddrSize=*/4);
21   DataExtractor StrExtractor(StrSecData,
22                              /*isLittleEndian=*/true,
23                              /*AddrSize=*/4);
24   DWARFDebugNames Table(NamesExtractor, StrExtractor);
25   return Table.extract();
26 }
27 
28 namespace {
29 
TEST(DWARFDebugNames,ReservedUnitLength)30 TEST(DWARFDebugNames, ReservedUnitLength) {
31   static const char NamesSecData[64] =
32       "\xf0\xff\xff\xff"; // Reserved unit length value
33   EXPECT_THAT_ERROR(
34       ExtractDebugNames(StringRef(NamesSecData, sizeof(NamesSecData)),
35                         StringRef()),
36       FailedWithMessage("parsing .debug_names header at 0x0: unsupported "
37                         "reserved unit length of value 0xfffffff0"));
38 }
39 
TEST(DWARFDebugNames,TooSmallForDWARF64)40 TEST(DWARFDebugNames, TooSmallForDWARF64) {
41   // DWARF64 header takes at least 44 bytes.
42   static const char NamesSecData[43] = "\xff\xff\xff\xff"; // DWARF64 mark
43   EXPECT_THAT_ERROR(
44       ExtractDebugNames(StringRef(NamesSecData, sizeof(NamesSecData)),
45                         StringRef()),
46       FailedWithMessage("parsing .debug_names header at 0x0: unexpected end of "
47                         "data at offset 0x2b while reading [0x28, 0x2c)"));
48 }
49 
TEST(DWARFDebugNames,BasicTestEntries)50 TEST(DWARFDebugNames, BasicTestEntries) {
51   const char *Yamldata = R"(
52 --- !ELF
53   debug_str:
54     - 'NameType1'
55     - 'NameType2'
56 
57   debug_names:
58     Abbreviations:
59     - Code:   0x1
60       Tag: DW_TAG_namespace
61       Indices:
62         - Idx:   DW_IDX_compile_unit
63           Form:  DW_FORM_data4
64         - Idx:   DW_IDX_die_offset
65           Form:  DW_FORM_ref4
66     Entries:
67     - Name:   0x0  # strp to NameType1
68       Code:   0x1
69       Values:
70         - 0x0      # Compile unit
71         - 0x0      # DIE Offset
72     - Name:   0xa  # strp to NameType2
73       Code:   0x1
74       Values:
75         - 0x1      # Compile unit
76         - 0x1      # DIE Offset
77     - Name:   0x0  # strp to NameType1
78       Code:   0x1
79       Values:
80         - 0x2     # Compile unit
81         - 0x2     # DIE Offset
82 
83 )";
84 
85   Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
86       DWARFYAML::emitDebugSections(Yamldata,
87                                    /*IsLittleEndian=*/true,
88                                    /*Is64BitAddrSize=*/true);
89   ASSERT_THAT_EXPECTED(Sections, Succeeded());
90   auto Ctx = DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true);
91   const DWARFDebugNames &DebugNames = Ctx->getDebugNames();
92   ASSERT_NE(DebugNames.begin(), DebugNames.end());
93   const DWARFDebugNames::NameIndex &NameIndex = *DebugNames.begin();
94 
95   ASSERT_EQ(NameIndex.getNameCount(), 2u);
96   ASSERT_EQ(NameIndex.getBucketCount(), 0u);
97   ASSERT_EQ(NameIndex.getCUCount(), 1u);
98   ASSERT_EQ(NameIndex.getCUOffset(0), 0u);
99   ASSERT_EQ(NameIndex.getForeignTUCount(), 0u);
100   ASSERT_EQ(NameIndex.getLocalTUCount(), 0u);
101 
102   // Check "NameEntries": there should be one per unique name.
103   // These are indexed starting on 1.
104   DWARFDebugNames::NameTableEntry FirstEntry = NameIndex.getNameTableEntry(1);
105   ASSERT_EQ(FirstEntry.getString(), StringRef("NameType1"));
106   DWARFDebugNames::NameTableEntry SecondEntry = NameIndex.getNameTableEntry(2);
107   ASSERT_EQ(SecondEntry.getString(), StringRef("NameType2"));
108 
109   SmallVector<DWARFDebugNames::Entry> FirstNameEntries =
110       to_vector_of<DWARFDebugNames::Entry>(NameIndex.equal_range("NameType1"));
111   ASSERT_EQ(FirstNameEntries.size(), 2u);
112   ASSERT_EQ(FirstNameEntries[0].getCUIndex(), 0u);
113   ASSERT_EQ(FirstNameEntries[1].getCUIndex(), 0x2);
114   ASSERT_EQ(FirstNameEntries[0].getDIEUnitOffset(), 0x0);
115   ASSERT_EQ(FirstNameEntries[1].getDIEUnitOffset(), 0x2);
116 
117   SmallVector<DWARFDebugNames::Entry> SecondNameEntries =
118       to_vector_of<DWARFDebugNames::Entry>(NameIndex.equal_range("NameType2"));
119   ASSERT_EQ(SecondNameEntries.size(), 1u);
120   ASSERT_EQ(SecondNameEntries[0].getCUIndex(), 0x1);
121   ASSERT_EQ(SecondNameEntries[0].getDIEUnitOffset(), 0x1);
122 }
123 
TEST(DWARFDebugNames,ParentEntries)124 TEST(DWARFDebugNames, ParentEntries) {
125   const char *Yamldata = R"(
126 --- !ELF
127   debug_str:
128     - 'Name1'
129     - 'Name2'
130     - 'Name3'
131     - 'Name4'
132   debug_names:
133     Abbreviations:
134     - Code:   0x11
135       Tag: DW_TAG_namespace
136       Indices:
137         - Idx:   DW_IDX_parent
138           Form:  DW_FORM_flag_present
139         - Idx:   DW_IDX_die_offset
140           Form:  DW_FORM_ref4
141     - Code:   0x22
142       Tag: DW_TAG_namespace
143       Indices:
144         - Idx:   DW_IDX_parent
145           Form:  DW_FORM_ref4
146         - Idx:   DW_IDX_die_offset
147           Form:  DW_FORM_ref4
148     - Code:   0x33
149       Tag: DW_TAG_namespace
150       Indices:
151         - Idx:   DW_IDX_die_offset
152           Form:  DW_FORM_ref4
153     Entries:
154     - Name:   0x0  # strp to Name1
155       Code:   0x11
156       Values:
157         - 0x0      # Die offset
158     - Name:   0x6  # strp to Name2
159       Code:   0x22
160       Values:
161         - 0x0      # Parent = First entry
162         - 0x1      # Die offset
163     - Name:   0xc  # strp to Name3
164       Code:   0x22
165       Values:
166         - 0x6      # Parent = Second entry
167         - 0x1      # Die offset
168     - Name:   0x12  # strp to Name4
169       Code:   0x33
170       Values:
171         - 0x1      # Die offset
172 )";
173 
174   Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
175       DWARFYAML::emitDebugSections(Yamldata,
176                                    /*IsLittleEndian=*/true,
177                                    /*Is64BitAddrSize=*/true);
178   ASSERT_THAT_EXPECTED(Sections, Succeeded());
179   auto Ctx = DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true);
180   const DWARFDebugNames &DebugNames = Ctx->getDebugNames();
181   ASSERT_NE(DebugNames.begin(), DebugNames.end());
182   const DWARFDebugNames::NameIndex &NameIndex = *DebugNames.begin();
183 
184   SmallVector<DWARFDebugNames::Entry> Name1Entries =
185       to_vector_of<DWARFDebugNames::Entry>(NameIndex.equal_range("Name1"));
186   ASSERT_EQ(Name1Entries.size(), 1u);
187   Expected<std::optional<DWARFDebugNames::Entry>> Name1Parent =
188       Name1Entries[0].getParentDIEEntry();
189   ASSERT_THAT_EXPECTED(Name1Parent, Succeeded());
190   ASSERT_EQ(*Name1Parent, std::nullopt); // Name1 has no parent
191 
192   SmallVector<DWARFDebugNames::Entry> Name2Entries =
193       to_vector_of<DWARFDebugNames::Entry>(NameIndex.equal_range("Name2"));
194   ASSERT_EQ(Name2Entries.size(), 1u);
195   Expected<std::optional<DWARFDebugNames::Entry>> Name2Parent =
196       Name2Entries[0].getParentDIEEntry();
197   ASSERT_THAT_EXPECTED(Name2Parent, Succeeded());
198   ASSERT_EQ((**Name2Parent).getDIEUnitOffset(), 0x0); // Name2 parent == Name1
199 
200   SmallVector<DWARFDebugNames::Entry> Name3Entries =
201       to_vector_of<DWARFDebugNames::Entry>(NameIndex.equal_range("Name3"));
202   ASSERT_EQ(Name3Entries.size(), 1u);
203   Expected<std::optional<DWARFDebugNames::Entry>> Name3Parent =
204       Name3Entries[0].getParentDIEEntry();
205   ASSERT_THAT_EXPECTED(Name3Parent, Succeeded());
206   ASSERT_EQ((**Name3Parent).getDIEUnitOffset(), 0x1); // Name3 parent == Name2
207 
208   SmallVector<DWARFDebugNames::Entry> Name4Entries =
209       to_vector_of<DWARFDebugNames::Entry>(NameIndex.equal_range("Name4"));
210   ASSERT_EQ(Name4Entries.size(), 1u);
211   ASSERT_FALSE(Name4Entries[0].hasParentInformation());
212 }
213 
TEST(DWARFDebugNames,InvalidAbbrevCode)214 TEST(DWARFDebugNames, InvalidAbbrevCode) {
215   const char *Yamldata = R"(
216 --- !ELF
217   debug_str:
218     - 'NameType1'
219 
220   debug_names:
221     Abbreviations:
222     - Code:   0x1
223       Tag: DW_TAG_namespace
224       Indices:
225         - Idx:   DW_IDX_compile_unit
226           Form:  DW_FORM_data4
227     Entries:
228     - Name:   0x0  # strp to NameType1
229       Code:   0x123456
230       Values:
231         - 0x0      # Compile unit
232 )";
233 
234   Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
235       DWARFYAML::emitDebugSections(Yamldata,
236                                    /*IsLittleEndian=*/true,
237                                    /*Is64BitAddrSize=*/true);
238   ASSERT_THAT_EXPECTED(
239       Sections,
240       FailedWithMessage("did not find an Abbreviation for this code"));
241 }
242 
TEST(DWARFDebugNames,InvalidNumOfValues)243 TEST(DWARFDebugNames, InvalidNumOfValues) {
244   const char *Yamldata = R"(
245 --- !ELF
246   debug_str:
247     - 'NameType1'
248 
249   debug_names:
250     Abbreviations:
251     - Code:   0x1
252       Tag: DW_TAG_namespace
253       Indices:
254         - Idx:   DW_IDX_compile_unit
255           Form:  DW_FORM_data4
256     Entries:
257     - Name:   0x0  # strp to NameType1
258       Code:   0x1
259       Values:
260         - 0x0      # Compile unit
261         - 0x0      # Compile unit
262         - 0x0      # Compile unit
263 )";
264 
265   Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
266       DWARFYAML::emitDebugSections(Yamldata,
267                                    /*IsLittleEndian=*/true,
268                                    /*Is64BitAddrSize=*/true);
269   ASSERT_THAT_EXPECTED(
270       Sections, FailedWithMessage(
271                     "mismatch between provided and required number of values"));
272 }
273 
TEST(DWARFDebugNames,UnsupportedForm)274 TEST(DWARFDebugNames, UnsupportedForm) {
275   const char *Yamldata = R"(
276 --- !ELF
277   debug_str:
278     - 'NameType1'
279 
280   debug_names:
281     Abbreviations:
282     - Code:   0x1
283       Tag: DW_TAG_namespace
284       Indices:
285         - Idx:   DW_IDX_compile_unit
286           Form:  DW_FORM_strx
287     Entries:
288     - Name:   0x0  # strp to NameType1
289       Code:   0x1
290       Values:
291         - 0x0      # Compile unit
292 )";
293 
294   Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
295       DWARFYAML::emitDebugSections(Yamldata,
296                                    /*IsLittleEndian=*/true,
297                                    /*Is64BitAddrSize=*/true);
298   ASSERT_THAT_EXPECTED(
299       Sections,
300       FailedWithMessage("unsupported Form for YAML debug_names emitter"));
301 }
302 } // end anonymous namespace
303