]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r308421, and update
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / DebugInfo / DWARF / DWARFVerifier.cpp
1 //===- DWARFVerifier.cpp --------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
11 #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
12 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
13 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
14 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
15 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
16 #include "llvm/DebugInfo/DWARF/DWARFSection.h"
17 #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include <map>
20 #include <set>
21 #include <vector>
22
23 using namespace llvm;
24 using namespace dwarf;
25 using namespace object;
26
27 bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
28                                      uint32_t *Offset, unsigned UnitIndex,
29                                      uint8_t &UnitType, bool &isUnitDWARF64) {
30   uint32_t AbbrOffset, Length;
31   uint8_t AddrSize = 0;
32   uint16_t Version;
33   bool Success = true;
34
35   bool ValidLength = false;
36   bool ValidVersion = false;
37   bool ValidAddrSize = false;
38   bool ValidType = true;
39   bool ValidAbbrevOffset = true;
40
41   uint32_t OffsetStart = *Offset;
42   Length = DebugInfoData.getU32(Offset);
43   if (Length == UINT32_MAX) {
44     isUnitDWARF64 = true;
45     OS << format(
46         "Unit[%d] is in 64-bit DWARF format; cannot verify from this point.\n",
47         UnitIndex);
48     return false;
49   }
50   Version = DebugInfoData.getU16(Offset);
51
52   if (Version >= 5) {
53     UnitType = DebugInfoData.getU8(Offset);
54     AddrSize = DebugInfoData.getU8(Offset);
55     AbbrOffset = DebugInfoData.getU32(Offset);
56     ValidType = DWARFUnit::isValidUnitType(UnitType);
57   } else {
58     UnitType = 0;
59     AbbrOffset = DebugInfoData.getU32(Offset);
60     AddrSize = DebugInfoData.getU8(Offset);
61   }
62
63   if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset))
64     ValidAbbrevOffset = false;
65
66   ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3);
67   ValidVersion = DWARFContext::isSupportedVersion(Version);
68   ValidAddrSize = AddrSize == 4 || AddrSize == 8;
69   if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
70       !ValidType) {
71     Success = false;
72     OS << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, OffsetStart);
73     if (!ValidLength)
74       OS << "\tError: The length for this unit is too "
75             "large for the .debug_info provided.\n";
76     if (!ValidVersion)
77       OS << "\tError: The 16 bit unit header version is not valid.\n";
78     if (!ValidType)
79       OS << "\tError: The unit type encoding is not valid.\n";
80     if (!ValidAbbrevOffset)
81       OS << "\tError: The offset into the .debug_abbrev section is "
82             "not valid.\n";
83     if (!ValidAddrSize)
84       OS << "\tError: The address size is unsupported.\n";
85   }
86   *Offset = OffsetStart + Length + 4;
87   return Success;
88 }
89
90 bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) {
91   uint32_t NumUnitErrors = 0;
92   unsigned NumDies = Unit.getNumDIEs();
93   for (unsigned I = 0; I < NumDies; ++I) {
94     auto Die = Unit.getDIEAtIndex(I);
95     if (Die.getTag() == DW_TAG_null)
96       continue;
97     for (auto AttrValue : Die.attributes()) {
98       NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
99       NumUnitErrors += verifyDebugInfoForm(Die, AttrValue);
100     }
101   }
102   return NumUnitErrors == 0;
103 }
104
105 bool DWARFVerifier::handleDebugInfo() {
106   OS << "Verifying .debug_info Unit Header Chain...\n";
107
108   DWARFDataExtractor DebugInfoData(DCtx.getInfoSection(), DCtx.isLittleEndian(),
109                                    0);
110   uint32_t NumDebugInfoErrors = 0;
111   uint32_t OffsetStart = 0, Offset = 0, UnitIdx = 0;
112   uint8_t UnitType = 0;
113   bool isUnitDWARF64 = false;
114   bool isHeaderChainValid = true;
115   bool hasDIE = DebugInfoData.isValidOffset(Offset);
116   while (hasDIE) {
117     OffsetStart = Offset;
118     if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType,
119                           isUnitDWARF64)) {
120       isHeaderChainValid = false;
121       if (isUnitDWARF64)
122         break;
123     } else {
124       std::unique_ptr<DWARFUnit> Unit;
125       switch (UnitType) {
126       case dwarf::DW_UT_type:
127       case dwarf::DW_UT_split_type: {
128         DWARFUnitSection<DWARFTypeUnit> TUSection{};
129         Unit.reset(new DWARFTypeUnit(
130             DCtx, DCtx.getInfoSection(), DCtx.getDebugAbbrev(),
131             &DCtx.getRangeSection(), DCtx.getStringSection(),
132             DCtx.getStringOffsetSection(), &DCtx.getAppleObjCSection(),
133             DCtx.getLineSection(), DCtx.isLittleEndian(), false, TUSection,
134             nullptr));
135         break;
136       }
137       case dwarf::DW_UT_skeleton:
138       case dwarf::DW_UT_split_compile:
139       case dwarf::DW_UT_compile:
140       case dwarf::DW_UT_partial:
141       // UnitType = 0 means that we are
142       // verifying a compile unit in DWARF v4.
143       case 0: {
144         DWARFUnitSection<DWARFCompileUnit> CUSection{};
145         Unit.reset(new DWARFCompileUnit(
146             DCtx, DCtx.getInfoSection(), DCtx.getDebugAbbrev(),
147             &DCtx.getRangeSection(), DCtx.getStringSection(),
148             DCtx.getStringOffsetSection(), &DCtx.getAppleObjCSection(),
149             DCtx.getLineSection(), DCtx.isLittleEndian(), false, CUSection,
150             nullptr));
151         break;
152       }
153       default: { llvm_unreachable("Invalid UnitType."); }
154       }
155       Unit->extract(DebugInfoData, &OffsetStart);
156       if (!verifyUnitContents(*Unit))
157         ++NumDebugInfoErrors;
158     }
159     hasDIE = DebugInfoData.isValidOffset(Offset);
160     ++UnitIdx;
161   }
162   if (UnitIdx == 0 && !hasDIE) {
163     OS << "Warning: .debug_info is empty.\n";
164     isHeaderChainValid = true;
165   }
166   NumDebugInfoErrors += verifyDebugInfoReferences();
167   return (isHeaderChainValid && NumDebugInfoErrors == 0);
168 }
169
170 unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
171                                                  DWARFAttribute &AttrValue) {
172   unsigned NumErrors = 0;
173   const auto Attr = AttrValue.Attr;
174   switch (Attr) {
175   case DW_AT_ranges:
176     // Make sure the offset in the DW_AT_ranges attribute is valid.
177     if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
178       if (*SectionOffset >= DCtx.getRangeSection().Data.size()) {
179         ++NumErrors;
180         OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
181               "bounds:\n";
182         Die.dump(OS, 0);
183         OS << "\n";
184       }
185     } else {
186       ++NumErrors;
187       OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
188       Die.dump(OS, 0);
189       OS << "\n";
190     }
191     break;
192   case DW_AT_stmt_list:
193     // Make sure the offset in the DW_AT_stmt_list attribute is valid.
194     if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
195       if (*SectionOffset >= DCtx.getLineSection().Data.size()) {
196         ++NumErrors;
197         OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
198               "bounds: "
199            << format("0x%08" PRIx32, *SectionOffset) << "\n";
200         Die.dump(OS, 0);
201         OS << "\n";
202       }
203     } else {
204       ++NumErrors;
205       OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
206       Die.dump(OS, 0);
207       OS << "\n";
208     }
209     break;
210
211   default:
212     break;
213   }
214   return NumErrors;
215 }
216
217 unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
218                                             DWARFAttribute &AttrValue) {
219   unsigned NumErrors = 0;
220   const auto Form = AttrValue.Value.getForm();
221   switch (Form) {
222   case DW_FORM_ref1:
223   case DW_FORM_ref2:
224   case DW_FORM_ref4:
225   case DW_FORM_ref8:
226   case DW_FORM_ref_udata: {
227     // Verify all CU relative references are valid CU offsets.
228     Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
229     assert(RefVal);
230     if (RefVal) {
231       auto DieCU = Die.getDwarfUnit();
232       auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
233       auto CUOffset = AttrValue.Value.getRawUValue();
234       if (CUOffset >= CUSize) {
235         ++NumErrors;
236         OS << "error: " << FormEncodingString(Form) << " CU offset "
237            << format("0x%08" PRIx32, CUOffset)
238            << " is invalid (must be less than CU size of "
239            << format("0x%08" PRIx32, CUSize) << "):\n";
240         Die.dump(OS, 0);
241         OS << "\n";
242       } else {
243         // Valid reference, but we will verify it points to an actual
244         // DIE later.
245         ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
246       }
247     }
248     break;
249   }
250   case DW_FORM_ref_addr: {
251     // Verify all absolute DIE references have valid offsets in the
252     // .debug_info section.
253     Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
254     assert(RefVal);
255     if (RefVal) {
256       if (*RefVal >= DCtx.getInfoSection().Data.size()) {
257         ++NumErrors;
258         OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
259               "bounds:\n";
260         Die.dump(OS, 0);
261         OS << "\n";
262       } else {
263         // Valid reference, but we will verify it points to an actual
264         // DIE later.
265         ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
266       }
267     }
268     break;
269   }
270   case DW_FORM_strp: {
271     auto SecOffset = AttrValue.Value.getAsSectionOffset();
272     assert(SecOffset); // DW_FORM_strp is a section offset.
273     if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) {
274       ++NumErrors;
275       OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
276       Die.dump(OS, 0);
277       OS << "\n";
278     }
279     break;
280   }
281   default:
282     break;
283   }
284   return NumErrors;
285 }
286
287 unsigned DWARFVerifier::verifyDebugInfoReferences() {
288   // Take all references and make sure they point to an actual DIE by
289   // getting the DIE by offset and emitting an error
290   OS << "Verifying .debug_info references...\n";
291   unsigned NumErrors = 0;
292   for (auto Pair : ReferenceToDIEOffsets) {
293     auto Die = DCtx.getDIEForOffset(Pair.first);
294     if (Die)
295       continue;
296     ++NumErrors;
297     OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
298        << ". Offset is in between DIEs:\n";
299     for (auto Offset : Pair.second) {
300       auto ReferencingDie = DCtx.getDIEForOffset(Offset);
301       ReferencingDie.dump(OS, 0);
302       OS << "\n";
303     }
304     OS << "\n";
305   }
306   return NumErrors;
307 }
308
309 void DWARFVerifier::verifyDebugLineStmtOffsets() {
310   std::map<uint64_t, DWARFDie> StmtListToDie;
311   for (const auto &CU : DCtx.compile_units()) {
312     auto Die = CU->getUnitDIE();
313     // Get the attribute value as a section offset. No need to produce an
314     // error here if the encoding isn't correct because we validate this in
315     // the .debug_info verifier.
316     auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
317     if (!StmtSectionOffset)
318       continue;
319     const uint32_t LineTableOffset = *StmtSectionOffset;
320     auto LineTable = DCtx.getLineTableForUnit(CU.get());
321     if (LineTableOffset < DCtx.getLineSection().Data.size()) {
322       if (!LineTable) {
323         ++NumDebugLineErrors;
324         OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
325            << "] was not able to be parsed for CU:\n";
326         Die.dump(OS, 0);
327         OS << '\n';
328         continue;
329       }
330     } else {
331       // Make sure we don't get a valid line table back if the offset is wrong.
332       assert(LineTable == nullptr);
333       // Skip this line table as it isn't valid. No need to create an error
334       // here because we validate this in the .debug_info verifier.
335       continue;
336     }
337     auto Iter = StmtListToDie.find(LineTableOffset);
338     if (Iter != StmtListToDie.end()) {
339       ++NumDebugLineErrors;
340       OS << "error: two compile unit DIEs, "
341          << format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
342          << format("0x%08" PRIx32, Die.getOffset())
343          << ", have the same DW_AT_stmt_list section offset:\n";
344       Iter->second.dump(OS, 0);
345       Die.dump(OS, 0);
346       OS << '\n';
347       // Already verified this line table before, no need to do it again.
348       continue;
349     }
350     StmtListToDie[LineTableOffset] = Die;
351   }
352 }
353
354 void DWARFVerifier::verifyDebugLineRows() {
355   for (const auto &CU : DCtx.compile_units()) {
356     auto Die = CU->getUnitDIE();
357     auto LineTable = DCtx.getLineTableForUnit(CU.get());
358     // If there is no line table we will have created an error in the
359     // .debug_info verifier or in verifyDebugLineStmtOffsets().
360     if (!LineTable)
361       continue;
362     uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
363     uint64_t PrevAddress = 0;
364     uint32_t RowIndex = 0;
365     for (const auto &Row : LineTable->Rows) {
366       if (Row.Address < PrevAddress) {
367         ++NumDebugLineErrors;
368         OS << "error: .debug_line["
369            << format("0x%08" PRIx32,
370                      *toSectionOffset(Die.find(DW_AT_stmt_list)))
371            << "] row[" << RowIndex
372            << "] decreases in address from previous row:\n";
373
374         DWARFDebugLine::Row::dumpTableHeader(OS);
375         if (RowIndex > 0)
376           LineTable->Rows[RowIndex - 1].dump(OS);
377         Row.dump(OS);
378         OS << '\n';
379       }
380
381       if (Row.File > MaxFileIndex) {
382         ++NumDebugLineErrors;
383         OS << "error: .debug_line["
384            << format("0x%08" PRIx32,
385                      *toSectionOffset(Die.find(DW_AT_stmt_list)))
386            << "][" << RowIndex << "] has invalid file index " << Row.File
387            << " (valid values are [1," << MaxFileIndex << "]):\n";
388         DWARFDebugLine::Row::dumpTableHeader(OS);
389         Row.dump(OS);
390         OS << '\n';
391       }
392       if (Row.EndSequence)
393         PrevAddress = 0;
394       else
395         PrevAddress = Row.Address;
396       ++RowIndex;
397     }
398   }
399 }
400
401 bool DWARFVerifier::handleDebugLine() {
402   NumDebugLineErrors = 0;
403   OS << "Verifying .debug_line...\n";
404   verifyDebugLineStmtOffsets();
405   verifyDebugLineRows();
406   return NumDebugLineErrors == 0;
407 }
408
409 bool DWARFVerifier::handleAppleNames() {
410   NumAppleNamesErrors = 0;
411
412   DWARFDataExtractor AppleNamesSection(DCtx.getAppleNamesSection(),
413                                        DCtx.isLittleEndian(), 0);
414   DataExtractor StrData(DCtx.getStringSection(), DCtx.isLittleEndian(), 0);
415   DWARFAcceleratorTable AppleNames(AppleNamesSection, StrData);
416
417   if (!AppleNames.extract()) {
418     return true;
419   }
420
421   OS << "Verifying .apple_names...\n";
422
423   // Verify that all buckets have a valid hash index or are empty.
424   uint32_t NumBuckets = AppleNames.getNumBuckets();
425   uint32_t NumHashes = AppleNames.getNumHashes();
426
427   uint32_t BucketsOffset =
428       AppleNames.getSizeHdr() + AppleNames.getHeaderDataLength();
429   uint32_t HashesBase = BucketsOffset + NumBuckets * 4;
430   uint32_t OffsetsBase = HashesBase + NumHashes * 4;
431
432   for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
433     uint32_t HashIdx = AppleNamesSection.getU32(&BucketsOffset);
434     if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
435       OS << format("error: Bucket[%d] has invalid hash index: %u\n", BucketIdx,
436                    HashIdx);
437       ++NumAppleNamesErrors;
438     }
439   }
440
441   uint32_t NumAtoms = AppleNames.getAtomsDesc().size();
442   if (NumAtoms == 0) {
443     OS << "error: no atoms; failed to read HashData\n";
444     ++NumAppleNamesErrors;
445     return false;
446   }
447
448   if (!AppleNames.validateForms()) {
449     OS << "error: unsupported form; failed to read HashData\n";
450     ++NumAppleNamesErrors;
451     return false;
452   }
453
454   for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
455     uint32_t HashOffset = HashesBase + 4 * HashIdx;
456     uint32_t DataOffset = OffsetsBase + 4 * HashIdx;
457     uint32_t Hash = AppleNamesSection.getU32(&HashOffset);
458     uint32_t HashDataOffset = AppleNamesSection.getU32(&DataOffset);
459     if (!AppleNamesSection.isValidOffsetForDataOfSize(HashDataOffset,
460                                                       sizeof(uint64_t))) {
461       OS << format("error: Hash[%d] has invalid HashData offset: 0x%08x\n",
462                    HashIdx, HashDataOffset);
463       ++NumAppleNamesErrors;
464     }
465
466     uint32_t StrpOffset;
467     uint32_t StringOffset;
468     uint32_t StringCount = 0;
469     uint32_t DieOffset = dwarf::DW_INVALID_OFFSET;
470
471     while ((StrpOffset = AppleNamesSection.getU32(&HashDataOffset)) != 0) {
472       const uint32_t NumHashDataObjects =
473           AppleNamesSection.getU32(&HashDataOffset);
474       for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
475            ++HashDataIdx) {
476         DieOffset = AppleNames.readAtoms(HashDataOffset);
477         if (!DCtx.getDIEForOffset(DieOffset)) {
478           const uint32_t BucketIdx =
479               NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
480           StringOffset = StrpOffset;
481           const char *Name = StrData.getCStr(&StringOffset);
482           if (!Name)
483             Name = "<NULL>";
484
485           OS << format(
486               "error: .apple_names Bucket[%d] Hash[%d] = 0x%08x "
487               "Str[%u] = 0x%08x "
488               "DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n",
489               BucketIdx, HashIdx, Hash, StringCount, StrpOffset, HashDataIdx,
490               DieOffset, Name);
491
492           ++NumAppleNamesErrors;
493         }
494       }
495       ++StringCount;
496     }
497   }
498   return NumAppleNamesErrors == 0;
499 }