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