xref: /llvm-project/llvm/unittests/DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp (revision 32e10aa65c680087c1c9cad2aaeb4526deabe235)
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