1 //===- llvm/unittest/DebugInfo/DWARFDebugAbbrevTest.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/DWARFDebugAbbrev.h"
10 #include "llvm/BinaryFormat/Dwarf.h"
11 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
12 #include "llvm/Support/DataExtractor.h"
13 #include "llvm/Support/LEB128.h"
14 #include "llvm/Support/MemoryBuffer.h"
15 #include "llvm/Testing/Support/Error.h"
16 #include "gtest/gtest.h"
17
18 using namespace llvm;
19 using namespace dwarf;
20
21 enum OrderKind : bool { InOrder, OutOfOrder };
22
writeValidAbbreviationDeclarations(raw_ostream & OS,uint32_t FirstCode,OrderKind Order)23 void writeValidAbbreviationDeclarations(raw_ostream &OS, uint32_t FirstCode,
24 OrderKind Order) {
25 encodeULEB128(FirstCode, OS);
26 encodeULEB128(DW_TAG_compile_unit, OS);
27 OS << static_cast<uint8_t>(DW_CHILDREN_yes);
28 encodeULEB128(DW_AT_name, OS);
29 encodeULEB128(DW_FORM_strp, OS);
30 encodeULEB128(0, OS);
31 encodeULEB128(0, OS);
32
33 uint32_t SecondCode =
34 Order == OrderKind::InOrder ? FirstCode + 1 : FirstCode - 1;
35
36 encodeULEB128(SecondCode, OS);
37 encodeULEB128(DW_TAG_subprogram, OS);
38 OS << static_cast<uint8_t>(DW_CHILDREN_no);
39 encodeULEB128(DW_AT_name, OS);
40 encodeULEB128(DW_FORM_strp, OS);
41 encodeULEB128(0, OS);
42 encodeULEB128(0, OS);
43 }
44
writeMalformedULEB128Value(raw_ostream & OS)45 void writeMalformedULEB128Value(raw_ostream &OS) {
46 OS << static_cast<uint8_t>(0x80);
47 }
48
writeULEB128LargerThan64Bits(raw_ostream & OS)49 void writeULEB128LargerThan64Bits(raw_ostream &OS) {
50 static constexpr llvm::StringRef LargeULEB128 =
51 "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01";
52 OS << LargeULEB128;
53 }
54
TEST(DWARFDebugAbbrevTest,DWARFAbbrevDeclSetExtractSuccess)55 TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetExtractSuccess) {
56 SmallString<64> RawData;
57 raw_svector_ostream OS(RawData);
58 uint32_t FirstCode = 5;
59
60 writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
61 encodeULEB128(0, OS);
62
63 uint64_t Offset = 0;
64 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
65 DWARFAbbreviationDeclarationSet AbbrevSet;
66 ASSERT_THAT_ERROR(AbbrevSet.extract(Data, &Offset), Succeeded());
67 // The Abbreviation Declarations are in order and contiguous, so we want to
68 // make sure that FirstAbbrCode was correctly set.
69 EXPECT_EQ(AbbrevSet.getFirstAbbrCode(), FirstCode);
70
71 const DWARFAbbreviationDeclaration *Abbrev5 =
72 AbbrevSet.getAbbreviationDeclaration(FirstCode);
73 ASSERT_TRUE(Abbrev5);
74 EXPECT_EQ(Abbrev5->getTag(), DW_TAG_compile_unit);
75 EXPECT_TRUE(Abbrev5->hasChildren());
76 EXPECT_EQ(Abbrev5->getNumAttributes(), 1u);
77
78 const DWARFAbbreviationDeclaration *Abbrev6 =
79 AbbrevSet.getAbbreviationDeclaration(FirstCode + 1);
80 ASSERT_TRUE(Abbrev6);
81 EXPECT_EQ(Abbrev6->getTag(), DW_TAG_subprogram);
82 EXPECT_FALSE(Abbrev6->hasChildren());
83 EXPECT_EQ(Abbrev6->getNumAttributes(), 1u);
84 }
85
TEST(DWARFDebugAbbrevTest,DWARFAbbrevDeclSetExtractSuccessOutOfOrder)86 TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetExtractSuccessOutOfOrder) {
87 SmallString<64> RawData;
88 raw_svector_ostream OS(RawData);
89 uint32_t FirstCode = 2;
90
91 writeValidAbbreviationDeclarations(OS, FirstCode, OutOfOrder);
92 encodeULEB128(0, OS);
93
94 uint64_t Offset = 0;
95 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
96 DWARFAbbreviationDeclarationSet AbbrevSet;
97 ASSERT_THAT_ERROR(AbbrevSet.extract(Data, &Offset), Succeeded());
98 // The declarations are out of order, ensure that FirstAbbrCode is UINT32_MAX.
99 EXPECT_EQ(AbbrevSet.getFirstAbbrCode(), UINT32_MAX);
100
101 const DWARFAbbreviationDeclaration *Abbrev2 =
102 AbbrevSet.getAbbreviationDeclaration(FirstCode);
103 ASSERT_TRUE(Abbrev2);
104 EXPECT_EQ(Abbrev2->getTag(), DW_TAG_compile_unit);
105 EXPECT_TRUE(Abbrev2->hasChildren());
106 EXPECT_EQ(Abbrev2->getNumAttributes(), 1u);
107
108 const DWARFAbbreviationDeclaration *Abbrev1 =
109 AbbrevSet.getAbbreviationDeclaration(FirstCode - 1);
110 ASSERT_TRUE(Abbrev1);
111 EXPECT_EQ(Abbrev1->getTag(), DW_TAG_subprogram);
112 EXPECT_FALSE(Abbrev1->hasChildren());
113 EXPECT_EQ(Abbrev1->getNumAttributes(), 1u);
114 }
115
TEST(DWARFDebugAbbrevTest,DWARFAbbreviationDeclSetCodeExtractionError)116 TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetCodeExtractionError) {
117 SmallString<64> RawData;
118
119 // Check for malformed ULEB128.
120 {
121 raw_svector_ostream OS(RawData);
122 writeMalformedULEB128Value(OS);
123
124 uint64_t Offset = 0;
125 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
126 DWARFAbbreviationDeclarationSet AbbrevSet;
127 ASSERT_THAT_ERROR(
128 AbbrevSet.extract(Data, &Offset),
129 FailedWithMessage("unable to decode LEB128 at offset 0x00000000: "
130 "malformed uleb128, extends past end"));
131 EXPECT_EQ(Offset, 0u);
132 }
133
134 RawData.clear();
135 // Check for ULEB128 too large to fit into a uin64_t.
136 {
137 raw_svector_ostream OS(RawData);
138 writeULEB128LargerThan64Bits(OS);
139
140 uint64_t Offset = 0;
141 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
142 DWARFAbbreviationDeclarationSet AbbrevSet;
143 ASSERT_THAT_ERROR(
144 AbbrevSet.extract(Data, &Offset),
145 FailedWithMessage("unable to decode LEB128 at offset 0x00000000: "
146 "uleb128 too big for uint64"));
147 EXPECT_EQ(Offset, 0u);
148 }
149 }
150
TEST(DWARFDebugAbbrevTest,DWARFAbbreviationDeclSetTagExtractionError)151 TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetTagExtractionError) {
152 SmallString<64> RawData;
153 const uint32_t Code = 1;
154
155 // Check for malformed ULEB128.
156 {
157 raw_svector_ostream OS(RawData);
158 encodeULEB128(Code, OS);
159 writeMalformedULEB128Value(OS);
160
161 uint64_t Offset = 0;
162 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
163 DWARFAbbreviationDeclarationSet AbbrevSet;
164 ASSERT_THAT_ERROR(
165 AbbrevSet.extract(Data, &Offset),
166 FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
167 "malformed uleb128, extends past end"));
168 // Only the code was extracted correctly.
169 EXPECT_EQ(Offset, 1u);
170 }
171
172 RawData.clear();
173 // Check for ULEB128 too large to fit into a uint64_t.
174 {
175 raw_svector_ostream OS(RawData);
176 encodeULEB128(Code, OS);
177 writeULEB128LargerThan64Bits(OS);
178
179 uint64_t Offset = 0;
180 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
181 DWARFAbbreviationDeclarationSet AbbrevSet;
182 ASSERT_THAT_ERROR(
183 AbbrevSet.extract(Data, &Offset),
184 FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
185 "uleb128 too big for uint64"));
186 // Only the code was extracted correctly.
187 EXPECT_EQ(Offset, 1u);
188 }
189 }
190
TEST(DWARFDebugAbbrevTest,DWARFAbbreviationDeclSetChildExtractionError)191 TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetChildExtractionError) {
192 SmallString<64> RawData;
193 const uint32_t Code = 1;
194 const dwarf::Tag Tag = DW_TAG_compile_unit;
195
196 // We want to make sure that we fail if we reach the end of the stream before
197 // reading the 'children' byte.
198 raw_svector_ostream OS(RawData);
199 encodeULEB128(Code, OS);
200 encodeULEB128(Tag, OS);
201 uint64_t Offset = 0;
202 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
203 DWARFAbbreviationDeclarationSet AbbrevSet;
204 ASSERT_THAT_ERROR(
205 AbbrevSet.extract(Data, &Offset),
206 FailedWithMessage(
207 "unexpected end of data at offset 0x2 while reading [0x2, 0x3)"));
208 // The code and the tag were extracted correctly.
209 EXPECT_EQ(Offset, 2u);
210 }
211
TEST(DWARFDebugAbbrevTest,DWARFAbbreviationDeclSetAttributeExtractionError)212 TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetAttributeExtractionError) {
213 SmallString<64> RawData;
214 const uint32_t Code = 1;
215 const dwarf::Tag Tag = DW_TAG_compile_unit;
216 const uint8_t Children = DW_CHILDREN_yes;
217
218 // Check for malformed ULEB128.
219 {
220 raw_svector_ostream OS(RawData);
221 encodeULEB128(Code, OS);
222 encodeULEB128(Tag, OS);
223 OS << Children;
224 writeMalformedULEB128Value(OS);
225
226 uint64_t Offset = 0;
227 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
228 DWARFAbbreviationDeclarationSet AbbrevSet;
229 ASSERT_THAT_ERROR(
230 AbbrevSet.extract(Data, &Offset),
231 FailedWithMessage("unable to decode LEB128 at offset 0x00000003: "
232 "malformed uleb128, extends past end"));
233 // The code, tag, and child byte were extracted correctly.
234 EXPECT_EQ(Offset, 3u);
235 }
236
237 RawData.clear();
238 // Check for ULEB128 too large to fit into a uint64_t.
239 {
240 raw_svector_ostream OS(RawData);
241 encodeULEB128(Code, OS);
242 encodeULEB128(Tag, OS);
243 OS << Children;
244 writeULEB128LargerThan64Bits(OS);
245
246 uint64_t Offset = 0;
247 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
248 DWARFAbbreviationDeclarationSet AbbrevSet;
249 ASSERT_THAT_ERROR(
250 AbbrevSet.extract(Data, &Offset),
251 FailedWithMessage("unable to decode LEB128 at offset 0x00000003: "
252 "uleb128 too big for uint64"));
253 // The code, tag, and child byte were extracted correctly.
254 EXPECT_EQ(Offset, 3u);
255 }
256 }
257
TEST(DWARFDebugAbbrevTest,DWARFAbbreviationDeclSetFormExtractionError)258 TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetFormExtractionError) {
259 SmallString<64> RawData;
260 const uint32_t Code = 1;
261 const dwarf::Tag Tag = DW_TAG_compile_unit;
262 const uint8_t Children = DW_CHILDREN_yes;
263 const dwarf::Attribute Attr = DW_AT_name;
264
265 // Check for malformed ULEB128.
266 {
267 raw_svector_ostream OS(RawData);
268 encodeULEB128(Code, OS);
269 encodeULEB128(Tag, OS);
270 OS << Children;
271 encodeULEB128(Attr, OS);
272 writeMalformedULEB128Value(OS);
273
274 uint64_t Offset = 0;
275 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
276 DWARFAbbreviationDeclarationSet AbbrevSet;
277 ASSERT_THAT_ERROR(
278 AbbrevSet.extract(Data, &Offset),
279 FailedWithMessage("unable to decode LEB128 at offset 0x00000004: "
280 "malformed uleb128, extends past end"));
281 // The code, tag, child byte, and first attribute were extracted correctly.
282 EXPECT_EQ(Offset, 4u);
283 }
284
285 RawData.clear();
286 // Check for ULEB128 too large to fit into a uint64_t.
287 {
288 raw_svector_ostream OS(RawData);
289 encodeULEB128(Code, OS);
290 encodeULEB128(Tag, OS);
291 OS << Children;
292 encodeULEB128(Attr, OS);
293 writeULEB128LargerThan64Bits(OS);
294
295 uint64_t Offset = 0;
296 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
297 DWARFAbbreviationDeclarationSet AbbrevSet;
298 ASSERT_THAT_ERROR(
299 AbbrevSet.extract(Data, &Offset),
300 FailedWithMessage("unable to decode LEB128 at offset 0x00000004: "
301 "uleb128 too big for uint64"));
302 // The code, tag, child byte, and first attribute were extracted correctly.
303 EXPECT_EQ(Offset, 4u);
304 }
305 }
306
TEST(DWARFDebugAbbrevTest,DWARFAbbrevDeclSetInvalidTag)307 TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetInvalidTag) {
308 SmallString<64> RawData;
309 raw_svector_ostream OS(RawData);
310 uint32_t FirstCode = 1;
311 // First, we're going to manually add good data.
312 writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
313
314 // Afterwards, we're going to write an Abbreviation Decl manually with an
315 // invalid tag.
316 encodeULEB128(FirstCode + 2, OS);
317 encodeULEB128(0, OS); // Invalid Tag
318 OS << static_cast<uint8_t>(DW_CHILDREN_no);
319 encodeULEB128(DW_AT_name, OS);
320 encodeULEB128(DW_FORM_strp, OS);
321 encodeULEB128(0, OS);
322 encodeULEB128(0, OS);
323
324 encodeULEB128(0, OS);
325 uint64_t Offset = 0;
326 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
327 DWARFAbbreviationDeclarationSet AbbrevSet;
328 EXPECT_THAT_ERROR(
329 AbbrevSet.extract(Data, &Offset),
330 FailedWithMessage("abbreviation declaration requires a non-null tag"));
331 }
332
TEST(DWARFDebugAbbrevTest,DWARFAbbrevDeclSetInvalidAttrValidForm)333 TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetInvalidAttrValidForm) {
334 SmallString<64> RawData;
335 raw_svector_ostream OS(RawData);
336 uint32_t FirstCode = 120;
337 // First, we're going to manually add good data.
338 writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
339
340 // Afterwards, we're going to write an Abbreviation Decl manually with an
341 // invalid attribute but valid form.
342 encodeULEB128(FirstCode - 5, OS);
343 encodeULEB128(DW_TAG_compile_unit, OS);
344 OS << static_cast<uint8_t>(DW_CHILDREN_no);
345 encodeULEB128(0, OS); // Invalid attribute followed by an invalid form.
346 encodeULEB128(DW_FORM_strp, OS);
347 encodeULEB128(0, OS);
348 encodeULEB128(0, OS);
349
350 encodeULEB128(0, OS);
351
352 uint64_t Offset = 0;
353 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
354 DWARFAbbreviationDeclarationSet AbbrevSet;
355 EXPECT_THAT_ERROR(
356 AbbrevSet.extract(Data, &Offset),
357 FailedWithMessage(
358 "malformed abbreviation declaration attribute. Either the "
359 "attribute or the form is zero while the other is not"));
360 }
361
TEST(DWARFDebugAbbrevTest,DWARFAbbrevDeclSetValidAttrInvalidForm)362 TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetValidAttrInvalidForm) {
363 SmallString<64> RawData;
364 raw_svector_ostream OS(RawData);
365 uint32_t FirstCode = 120;
366 // First, we're going to manually add good data.
367 writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
368
369 // Afterwards, we're going to write an Abbreviation Decl manually with a
370 // valid attribute but invalid form.
371 encodeULEB128(FirstCode - 5, OS);
372 encodeULEB128(DW_TAG_compile_unit, OS);
373 OS << static_cast<uint8_t>(DW_CHILDREN_no);
374 encodeULEB128(DW_AT_name, OS);
375 encodeULEB128(0, OS); // Invalid form after a valid attribute.
376 encodeULEB128(0, OS);
377 encodeULEB128(0, OS);
378
379 encodeULEB128(0, OS);
380
381 uint64_t Offset = 0;
382 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
383 DWARFAbbreviationDeclarationSet AbbrevSet;
384 EXPECT_THAT_ERROR(
385 AbbrevSet.extract(Data, &Offset),
386 FailedWithMessage(
387 "malformed abbreviation declaration attribute. Either the "
388 "attribute or the form is zero while the other is not"));
389 }
390
TEST(DWARFDebugAbbrevTest,DWARFAbbrevDeclSetMissingTerminator)391 TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetMissingTerminator) {
392 SmallString<64> RawData;
393 raw_svector_ostream OS(RawData);
394 uint32_t FirstCode = 120;
395 // First, we're going to manually add good data.
396 writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
397
398 // Afterwards, we're going to write an Abbreviation Decl manually without a
399 // termintating sequence.
400 encodeULEB128(FirstCode + 7, OS);
401 encodeULEB128(DW_TAG_compile_unit, OS);
402 OS << static_cast<uint8_t>(DW_CHILDREN_no);
403 encodeULEB128(DW_AT_name, OS);
404 encodeULEB128(DW_FORM_strp, OS);
405
406 uint64_t Offset = 0;
407 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
408 DWARFAbbreviationDeclarationSet AbbrevSet;
409 EXPECT_THAT_ERROR(
410 AbbrevSet.extract(Data, &Offset),
411 FailedWithMessage(
412 "abbreviation declaration attribute list was not terminated with a "
413 "null entry"));
414 }
415
TEST(DWARFDebugAbbrevTest,DWARFDebugAbbrevParseError)416 TEST(DWARFDebugAbbrevTest, DWARFDebugAbbrevParseError) {
417 SmallString<64> RawData;
418 raw_svector_ostream OS(RawData);
419 const uint32_t FirstCode = 70;
420 // First, we're going to manually add good data.
421 writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
422
423 // Afterwards, we're going to write an Abbreviation Decl manually without a
424 // termintating sequence.
425 encodeULEB128(FirstCode - 1, OS);
426 encodeULEB128(DW_TAG_compile_unit, OS);
427 OS << static_cast<uint8_t>(DW_CHILDREN_no);
428 encodeULEB128(DW_AT_name, OS);
429 encodeULEB128(DW_FORM_strp, OS);
430
431 // The specific error should percolate up to the DWARFDebugAbbrev::parse().
432 DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
433 DWARFDebugAbbrev DebugAbbrev(Data);
434 EXPECT_THAT_ERROR(
435 DebugAbbrev.parse(),
436 FailedWithMessage(
437 "abbreviation declaration attribute list was not terminated with a "
438 "null entry"));
439 }
440