51std::optional<DWARFAddressRange>
53 auto Begin =
Ranges.begin();
55 auto Pos = std::lower_bound(Begin,
End, R);
58 if (Pos !=
End && *Pos == R) {
91 auto Prev = std::prev(It);
92 if (Prev->intersects(RI))
103 if (It->intersects(RI))
113 auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();
119 bool Covered = I1->LowPC <= R.LowPC;
120 if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) {
128 if (R.LowPC < I1->HighPC)
129 R.LowPC = I1->HighPC;
137 auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();
138 while (I1 != E1 && I2 != E2) {
139 if (I1->intersects(*I2)) {
144 if (I1->LowPC < I2->LowPC)
153 uint64_t *
Offset,
unsigned UnitIndex,
155 uint64_t AbbrOffset,
Length;
160 bool ValidLength =
false;
161 bool ValidVersion =
false;
162 bool ValidAddrSize =
false;
163 bool ValidType =
true;
164 bool ValidAbbrevOffset =
true;
166 uint64_t OffsetStart = *
Offset;
175 AbbrOffset = isUnitDWARF64 ? DebugInfoData.
getU64(
Offset)
180 AbbrOffset = isUnitDWARF64 ? DebugInfoData.
getU64(
Offset)
187 if (!AbbrevSetOrErr) {
188 ValidAbbrevOffset =
false;
198 if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
201 bool HeaderShown =
false;
202 auto ShowHeaderOnce = [&]() {
204 error() <<
formatv(
"Units[{0}] - start offset: {1:x+8}\n", UnitIndex,
210 ErrorCategory.Report(
211 "Unit Header Length: Unit too large for .debug_info provided", [&]() {
213 note() <<
"The length for this unit is too "
214 "large for the .debug_info provided.\n";
217 ErrorCategory.Report(
218 "Unit Header Length: 16 bit unit header version is not valid", [&]() {
220 note() <<
"The 16 bit unit header version is not valid.\n";
223 ErrorCategory.Report(
224 "Unit Header Length: Unit type encoding is not valid", [&]() {
226 note() <<
"The unit type encoding is not valid.\n";
228 if (!ValidAbbrevOffset)
229 ErrorCategory.Report(
230 "Unit Header Length: Offset into the .debug_abbrev section is not "
234 note() <<
"The offset into the .debug_abbrev section is "
238 ErrorCategory.Report(
"Unit Header Length: Address size is unsupported",
241 note() <<
"The address size is unsupported.\n";
244 *
Offset = OffsetStart +
Length + (isUnitDWARF64 ? 12 : 4);
248bool DWARFVerifier::verifyName(
const DWARFDie &Die) {
252 std::string ReconstructedName;
253 raw_string_ostream OS(ReconstructedName);
254 std::string OriginalFullName;
256 if (OriginalFullName.empty() || OriginalFullName == ReconstructedName)
259 ErrorCategory.Report(
260 "Simplified template DW_AT_name could not be reconstituted", [&]() {
262 <<
"Simplified template DW_AT_name could not be reconstituted:\n"
264 " reconstituted: {1}\n",
265 OriginalFullName, ReconstructedName);
272unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit,
273 ReferenceMap &UnitLocalReferences,
274 ReferenceMap &CrossUnitReferences) {
275 unsigned NumUnitErrors = 0;
276 unsigned NumDies =
Unit.getNumDIEs();
277 for (
unsigned I = 0;
I < NumDies; ++
I) {
278 auto Die =
Unit.getDIEAtIndex(
I);
280 if (Die.
getTag() == DW_TAG_null)
284 NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
285 NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences,
286 CrossUnitReferences);
289 NumUnitErrors += verifyName(Die);
294 warn() <<
formatv(
"{0} has DW_CHILDREN_yes but DIE has no children: ",
300 NumUnitErrors += verifyDebugInfoCallSite(Die);
301 NumUnitErrors += verifyDebugInfoSubprogram(Die);
304 DWARFDie Die =
Unit.getUnitDIE(
false);
306 ErrorCategory.Report(
"Compilation unit missing DIE", [&]() {
307 error() <<
"Compilation unit without DIE.\n";
310 return NumUnitErrors;
314 ErrorCategory.Report(
"Compilation unit root DIE is not a unit DIE", [&]() {
315 error() <<
formatv(
"Compilation unit root DIE is not a unit DIE: {0}.\n",
323 ErrorCategory.Report(
"Mismatched unit type", [&]() {
325 "Compilation unit type ({0}) and root DIE ({1}) do not match.\n",
335 ErrorCategory.Report(
"Skeleton CU has children", [&]() {
336 error() <<
"Skeleton compilation unit has children.\n";
342 NumUnitErrors += verifyDieRanges(Die, RI);
344 return NumUnitErrors;
347unsigned DWARFVerifier::verifyDebugInfoCallSite(
const DWARFDie &Die) {
348 if (Die.
getTag() != DW_TAG_call_site && Die.
getTag() != DW_TAG_GNU_call_site)
353 if (Curr.
getTag() == DW_TAG_inlined_subroutine) {
354 ErrorCategory.Report(
355 "Call site nested entry within inlined subroutine", [&]() {
356 error() <<
"Call site entry nested within inlined subroutine:";
364 ErrorCategory.Report(
365 "Call site entry not nested within valid subprogram", [&]() {
366 error() <<
"Call site entry not nested within a valid subprogram:";
372 std::optional<DWARFFormValue> CallAttr = Curr.
find(
373 {DW_AT_call_all_calls, DW_AT_call_all_source_calls,
374 DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,
375 DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites});
377 ErrorCategory.Report(
378 "Subprogram with call site entry has no DW_AT_call attribute", [&]() {
380 <<
"Subprogram with call site entry has no DW_AT_call attribute:";
390unsigned DWARFVerifier::verifyDebugInfoSubprogram(
const DWARFDie &Die) {
391 if (Die.
getTag() != DW_TAG_subprogram)
396 auto DumpWithChildren = [&]() {
397 DIDumpOptions ChildDumpOpts = DumpOpts;
400 Die.
dump(OS, 0, ChildDumpOpts);
406 return AttrValue.Attr == DW_AT_sibling;
408 ErrorCategory.Report(
"Subprogram DIE has no attributes", [&]() {
409 error() <<
"Subprogram DIE has no attributes:\n";
417 if (!Die.
find({DW_AT_name, DW_AT_linkage_name, DW_AT_MIPS_linkage_name,
418 DW_AT_abstract_origin, DW_AT_specification, DW_AT_low_pc,
419 DW_AT_ranges, DW_AT_entry_pc})) {
420 warn() <<
"Subprogram DIE has no name, abstract origin, specification or "
428unsigned DWARFVerifier::verifyAbbrevSection(
const DWARFDebugAbbrev *Abbrev) {
432 Expected<const DWARFAbbreviationDeclarationSet *> AbbrDeclsOrErr =
434 if (!AbbrDeclsOrErr) {
436 ErrorCategory.Report(
"Abbreviation Declaration error",
437 [&]() {
error() << ErrMsg <<
"\n"; });
441 const auto *AbbrDecls = *AbbrDeclsOrErr;
442 unsigned NumErrors = 0;
443 for (
auto AbbrDecl : *AbbrDecls) {
444 SmallDenseSet<uint16_t> AttributeSet;
445 for (
auto Attribute : AbbrDecl.attributes()) {
448 ErrorCategory.Report(
449 "Abbreviation declartion contains multiple attributes", [&]() {
450 error() <<
formatv(
"Abbreviation declaration contains multiple "
463 OS <<
"Verifying .debug_abbrev...\n";
466 unsigned NumErrors = 0;
468 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
470 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
472 return NumErrors == 0;
476 unsigned NumDebugInfoErrors = 0;
477 ReferenceMap CrossUnitReferences;
481 for (
const auto &Unit : Units) {
482 OS <<
formatv(
"Verifying unit: {0} / {1}",
Index, Units.getNumUnits());
483 if (
const char *Name = Unit->getUnitDIE(
true).getShortName())
484 OS <<
formatv(
", \"{0}\"", Name);
487 ReferenceMap UnitLocalReferences;
488 NumDebugInfoErrors +=
489 verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences);
490 NumDebugInfoErrors += verifyDebugInfoReferences(
491 UnitLocalReferences, [&](uint64_t
Offset) {
return Unit.get(); });
495 NumDebugInfoErrors += verifyDebugInfoReferences(
497 if (DWARFUnit *U = Units.getUnitForOffset(
Offset))
502 return NumDebugInfoErrors;
505unsigned DWARFVerifier::verifyUnitSection(
const DWARFSection &S) {
506 const DWARFObject &DObj = DCtx.getDWARFObj();
507 DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);
508 unsigned NumDebugInfoErrors = 0;
511 bool isUnitDWARF64 =
false;
512 bool isHeaderChainValid =
true;
514 DWARFUnitVector TypeUnitVector;
515 DWARFUnitVector CompileUnitVector;
519 isHeaderChainValid =
false;
526 if (UnitIdx == 0 && !hasDIE) {
527 warn() <<
"Section is empty.\n";
528 isHeaderChainValid =
true;
530 if (!isHeaderChainValid)
531 ++NumDebugInfoErrors;
532 return NumDebugInfoErrors;
535unsigned DWARFVerifier::verifyIndex(StringRef Name,
537 StringRef IndexStr) {
538 if (IndexStr.
empty())
540 OS <<
"Verifying " <<
Name <<
"...\n";
541 DWARFUnitIndex
Index(InfoColumnKind);
542 DataExtractor
D(IndexStr, DCtx.isLittleEndian());
545 using MapType = IntervalMap<uint64_t, uint64_t>;
546 MapType::Allocator
Alloc;
547 std::vector<std::unique_ptr<MapType>> Sections(
Index.getColumnKinds().size());
548 for (
const DWARFUnitIndex::Entry &
E :
Index.getRows()) {
550 if (!
E.getContributions())
553 InfoColumnKind == DW_SECT_INFO
556 const DWARFUnitIndex::Entry::SectionContribution &SC =
E.value();
561 Sections[Col] = std::make_unique<MapType>(
Alloc);
562 auto &
M = *Sections[Col];
565 StringRef Category = InfoColumnKind == DWARFSectionKind::DW_SECT_INFO
566 ?
"Overlapping CU index entries"
567 :
"Overlapping TU index entries";
568 ErrorCategory.Report(Category, [&]() {
570 "overlapping index entries for entries {0:x16} "
571 "and {1:x16} for column {2}\n",
584 return verifyIndex(
".debug_cu_index", DWARFSectionKind::DW_SECT_INFO,
585 DCtx.getDWARFObj().getCUIndexSection()) == 0;
590 DCtx.getDWARFObj().getTUIndexSection()) == 0;
595 unsigned NumErrors = 0;
597 OS <<
"Verifying .debug_info Unit Header Chain...\n";
599 [&](
const DWARFSection &S) { NumErrors += verifyUnitSection(S); });
601 OS <<
"Verifying .debug_types Unit Header Chain...\n";
603 [&](
const DWARFSection &S) { NumErrors += verifyUnitSection(S); });
605 OS <<
"Verifying non-dwo Units...\n";
606 NumErrors += verifyUnits(DCtx.getNormalUnitsVector());
608 OS <<
"Verifying dwo Units...\n";
609 NumErrors += verifyUnits(DCtx.getDWOUnitsVector());
610 return NumErrors == 0;
613unsigned DWARFVerifier::verifyDieRanges(
const DWARFDie &Die,
614 DieRangeInfo &ParentRI) {
615 unsigned NumErrors = 0;
623 if (!RangesOrError) {
625 if (!Unit->isDWOUnit())
634 DieRangeInfo RI(Die);
655 if (!IsObjectFile || IsMachOObject || Die.
getTag() != DW_TAG_compile_unit) {
656 bool DumpDieAfterError =
false;
657 for (
const auto &
Range : Ranges) {
658 if (!
Range.valid()) {
660 ErrorCategory.
Report(
"Invalid address range", [&]() {
662 DumpDieAfterError =
true;
673 if (
auto PrevRange = RI.insert(
Range)) {
675 ErrorCategory.Report(
"DIE has overlapping DW_AT_ranges", [&]() {
676 error() <<
formatv(
"DIE has overlapping ranges in DW_AT_ranges "
677 "attribute: {0} and {1}\n",
679 DumpDieAfterError =
true;
683 if (DumpDieAfterError)
684 dump(Die, 2) <<
'\n';
688 const auto IntersectingChild = ParentRI.insert(RI);
689 if (IntersectingChild != ParentRI.Children.end()) {
691 ErrorCategory.Report(
"DIEs have overlapping address ranges", [&]() {
692 error() <<
"DIEs have overlapping address ranges:";
694 dump(IntersectingChild->Die) <<
'\n';
699 bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() &&
700 !(Die.
getTag() == DW_TAG_subprogram &&
701 ParentRI.Die.getTag() == DW_TAG_subprogram);
702 if (ShouldBeContained && !ParentRI.contains(RI)) {
704 ErrorCategory.Report(
705 "DIE address ranges are not contained by parent ranges", [&]() {
707 <<
"DIE address ranges are not contained in its parent's ranges:";
709 dump(Die, 2) <<
'\n';
714 for (DWARFDie Child : Die)
715 NumErrors += verifyDieRanges(Child, RI);
720bool DWARFVerifier::verifyExpressionOp(
const DWARFExpression::Operation &
Op,
722 for (
unsigned Operand = 0; Operand <
Op.Desc.
Op.
size(); ++Operand) {
723 unsigned Size =
Op.Desc.
Op[Operand];
730 if (
Op.Opcode == DW_OP_convert &&
Op.Operands[Operand] == 0)
732 auto Die =
U->getDIEForOffset(
U->getOffset() +
Op.Operands[Operand]);
733 if (!Die || Die.
getTag() != dwarf::DW_TAG_base_type)
741bool DWARFVerifier::verifyExpression(
const DWARFExpression &
E, DWARFUnit *U) {
743 if (!verifyExpressionOp(
Op, U))
749unsigned DWARFVerifier::verifyDebugInfoAttribute(
const DWARFDie &Die,
750 DWARFAttribute &AttrValue) {
751 unsigned NumErrors = 0;
752 auto ReportError = [&](StringRef category,
const Twine &TitleMsg) {
754 ErrorCategory.Report(category, [&]() {
760 const DWARFObject &DObj = DCtx.getDWARFObj();
762 const auto Attr = AttrValue.
Attr;
767 unsigned DwarfVersion =
U->getVersion();
768 const DWARFSection &RangeSection = DwarfVersion < 5
771 if (
U->isDWOUnit() && RangeSection.
Data.
empty())
773 if (*SectionOffset >= RangeSection.
Data.
size())
775 "DW_AT_ranges offset out of bounds",
776 llvm::formatv(
"DW_AT_ranges offset is beyond {0} bounds: {1:x8}",
777 StringRef(DwarfVersion < 5 ?
".debug_ranges"
778 :
".debug_rnglists"),
782 ReportError(
"Invalid DW_AT_ranges encoding",
783 "DIE has invalid DW_AT_ranges encoding:");
785 case DW_AT_stmt_list:
788 if (*SectionOffset >=
U->getLineSection().Data.size())
790 "DW_AT_stmt_list offset out of bounds",
792 "DW_AT_stmt_list offset is beyond .debug_line bounds: {0:x8}",
796 ReportError(
"Invalid DW_AT_stmt_list encoding",
797 "DIE has invalid DW_AT_stmt_list encoding:");
799 case DW_AT_location: {
810 if (Expected<std::vector<DWARFLocationExpression>> Loc =
812 for (
const auto &Entry : *Loc) {
813 DataExtractor
Data(
Entry.Expr, DCtx.isLittleEndian());
814 DWARFExpression Expression(
Data,
U->getAddressByteSize(),
815 U->getFormParams().Format);
817 any_of(Expression, [](
const DWARFExpression::Operation &
Op) {
820 if (
Error || !verifyExpression(Expression, U))
821 ReportError(
"Invalid DWARF expressions",
822 "DIE contains invalid DWARF expression:");
825 Loc.takeError(), [&](std::unique_ptr<ResolverError>
E) {
826 return U->isDWOUnit() ? Error::success()
827 : Error(std::move(E));
829 ReportError(
"Invalid DW_AT_location",
toString(std::move(Err)));
832 case DW_AT_specification:
833 case DW_AT_abstract_origin: {
835 auto DieTag = Die.
getTag();
836 auto RefTag = ReferencedDie.getTag();
837 if (DieTag == RefTag)
839 if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
841 if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
844 if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)
846 ReportError(
"Incompatible DW_AT_abstract_origin tag reference",
847 formatv(
"DIE with tag {0} has {1} that points to DIE with "
848 "incompatible tag {2}",
857 ReportError(
"Incompatible DW_AT_type attribute tag",
858 formatv(
"DIE has {0} with incompatible tag {1}",
863 case DW_AT_call_file:
864 case DW_AT_decl_file: {
866 if (
U->isDWOUnit() && !
U->isTypeUnit())
868 const auto *
LT =
U->getContext().getLineTableForUnit(U);
870 if (!
LT->hasFileAtIndex(*FileIdx)) {
871 bool IsZeroIndexed =
LT->Prologue.getVersion() >= 5;
872 if (std::optional<uint64_t> LastFileIdx =
873 LT->getLastValidFileIndex()) {
874 ReportError(
"Invalid file index in DW_AT_decl_file",
876 "{1} (valid values are [{2}-{3}])",
878 (IsZeroIndexed ?
"0" :
"1"),
882 "Invalid file index in DW_AT_decl_file",
883 llvm::formatv(
"DIE has {0} with an invalid file index {1} (the "
884 "file table in the prologue is empty)",
890 "File index in DW_AT_decl_file reference CU with no line table",
891 llvm::formatv(
"DIE has {0} that references a file with index {1} "
892 "and the compile unit has no line table",
896 ReportError(
"Invalid encoding in DW_AT_decl_file",
902 case DW_AT_call_line:
903 case DW_AT_decl_line: {
906 Attr == DW_AT_call_line ?
"Invalid file index in DW_AT_decl_line"
907 :
"Invalid file index in DW_AT_call_line",
912 case DW_AT_LLVM_stmt_sequence: {
916 if (!SectionOffset) {
917 ReportError(
"Invalid DW_AT_LLVM_stmt_sequence encoding",
918 "DIE has invalid DW_AT_LLVM_stmt_sequence encoding");
921 if (*SectionOffset >=
U->getLineSection().Data.size()) {
923 "DW_AT_LLVM_stmt_sequence offset out of bounds",
924 "DW_AT_LLVM_stmt_sequence offset is beyond .debug_line bounds: " +
930 const auto *LineTable = DCtx.getLineTableForUnit(U);
932 ReportError(
"DW_AT_LLVM_stmt_sequence without line table",
933 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
939 DWARFDie CUDie =
U->getUnitDIE();
941 if (!StmtListOffset) {
942 ReportError(
"DW_AT_LLVM_stmt_sequence without DW_AT_stmt_list",
943 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
948 const int8_t DwarfOffset =
949 LineTable->Prologue.getFormParams().getDwarfOffsetByteSize();
951 uint64_t LineTableStart = *StmtListOffset;
952 uint64_t PrologueLength = LineTable->Prologue.PrologueLength;
953 uint64_t TotalLength = LineTable->Prologue.TotalLength;
954 uint64_t LineTableEnd = LineTableStart + TotalLength + DwarfOffset;
959 uint64_t InitialLengthSize = DwarfOffset;
962 uint64_t PrologueLengthSize = DwarfOffset;
963 uint64_t SequencesStart = LineTableStart + InitialLengthSize + VersionSize +
964 PrologueLengthSize + PrologueLength;
967 if (*SectionOffset < SequencesStart || *SectionOffset >= LineTableEnd) {
968 ReportError(
"DW_AT_LLVM_stmt_sequence offset out of line table bounds",
969 llvm::formatv(
"DW_AT_LLVM_stmt_sequence offset {0:x8} is not "
970 "within the line table bounds [{1:x8}, {2:x8})",
971 *SectionOffset, SequencesStart, LineTableEnd));
977 [SectionOffset](
const auto &Sequence) {
978 return Sequence.StmtSeqOffset == *SectionOffset;
981 if (It == LineTable->Sequences.end())
983 "Invalid DW_AT_LLVM_stmt_sequence offset",
984 llvm::formatv(
"DW_AT_LLVM_stmt_sequence offset {0:x8} does not point "
985 "to a valid sequence offset in the line table",
995unsigned DWARFVerifier::verifyDebugInfoForm(
const DWARFDie &Die,
996 DWARFAttribute &AttrValue,
997 ReferenceMap &LocalReferences,
998 ReferenceMap &CrossUnitReferences) {
1000 unsigned NumErrors = 0;
1007 case DW_FORM_ref_udata: {
1012 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
1014 if (CUOffset >= CUSize) {
1016 ErrorCategory.Report(
"Invalid CU offset", [&]() {
1017 error() <<
formatv(
"{0} CU offset {1:x+8} is invalid (must be less "
1018 "than CU size of {2:x+8}):\n",
1020 Die.
dump(OS, 0, DumpOpts);
1032 case DW_FORM_ref_addr: {
1038 if (*RefVal >= DieCU->getInfoSection().Data.size()) {
1040 ErrorCategory.Report(
"DW_FORM_ref_addr offset out of bounds", [&]() {
1041 error() <<
"DW_FORM_ref_addr offset beyond .debug_info "
1048 CrossUnitReferences[*RefVal].insert(Die.
getOffset());
1059 case DW_FORM_line_strp: {
1062 std::string ErrMsg =
toString(std::move(
E));
1063 ErrorCategory.Report(
"Invalid DW_FORM attribute", [&]() {
1076unsigned DWARFVerifier::verifyDebugInfoReferences(
1077 const ReferenceMap &References,
1078 llvm::function_ref<DWARFUnit *(
uint64_t)> GetUnitForOffset) {
1080 if (DWARFUnit *U = GetUnitForOffset(
Offset))
1081 return U->getDIEForOffset(
Offset);
1084 unsigned NumErrors = 0;
1085 for (
const std::pair<
const uint64_t, std::set<uint64_t>> &Pair : References) {
1086 if (GetDIEForOffset(Pair.first))
1089 ErrorCategory.Report(
"Invalid DIE reference", [&]() {
1091 "invalid DIE reference {0:x+8}. Offset is in between DIEs:\n",
1093 for (
auto Offset : Pair.second)
1101void DWARFVerifier::verifyDebugLineStmtOffsets() {
1102 std::map<uint64_t, DWARFDie> StmtListToDie;
1103 for (
const auto &CU : DCtx.compile_units()) {
1104 auto Die = CU->getUnitDIE();
1109 if (!StmtSectionOffset)
1111 const uint64_t LineTableOffset = *StmtSectionOffset;
1112 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1113 if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
1115 ++NumDebugLineErrors;
1116 ErrorCategory.Report(
"Unparsable .debug_line entry", [&]() {
1118 ".debug_line[{0:x+8}] was not able to be parsed for CU:\n",
1126 assert(LineTable ==
nullptr);
1131 auto [Iter,
Inserted] = StmtListToDie.try_emplace(LineTableOffset, Die);
1133 ++NumDebugLineErrors;
1134 const auto &OldDie = Iter->second;
1135 ErrorCategory.Report(
"Identical DW_AT_stmt_list section offset", [&]() {
1136 error() <<
formatv(
"two compile unit DIEs, {0:x+8} and {1:x+8}, have "
1137 "the same DW_AT_stmt_list section offset:\n",
1147void DWARFVerifier::verifyDebugLineRows() {
1148 for (
const auto &CU : DCtx.compile_units()) {
1149 auto Die = CU->getUnitDIE();
1150 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1157 bool isDWARF5 = LineTable->Prologue.getVersion() >= 5;
1158 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
1159 uint32_t MinFileIndex = isDWARF5 ? 0 : 1;
1160 uint32_t FileIndex = MinFileIndex;
1161 StringMap<uint16_t> FullPathMap;
1162 for (
const auto &FileName : LineTable->Prologue.FileNames) {
1164 if (FileName.DirIdx > MaxDirIndex) {
1165 ++NumDebugLineErrors;
1166 ErrorCategory.Report(
1167 "Invalid index in .debug_line->prologue.file_names->dir_idx",
1169 error() <<
formatv(
".debug_line[{0:x+8}].prologue.file_names[{1}]"
1170 ".dir_idx contains an invalid index: {2}\n",
1172 FileIndex, FileName.DirIdx);
1177 std::string FullPath;
1178 const bool HasFullPath = LineTable->getFileNameByIndex(
1179 FileIndex, CU->getCompilationDir(),
1181 assert(HasFullPath &&
"Invalid index?");
1184 if (!Inserted && It->second != FileIndex && DumpOpts.Verbose) {
1185 warn() <<
formatv(
".debug_line[{0:x+8}].prologue.file_names[{1}] is a "
1186 "duplicate of file_names[{2}]\n",
1188 FileIndex, It->second);
1196 if (LineTable->Rows.size() == 1 && LineTable->Rows.front().EndSequence)
1201 uint32_t RowIndex = 0;
1202 for (
const auto &Row : LineTable->Rows) {
1204 if (Row.Address.Address < PrevAddress) {
1205 ++NumDebugLineErrors;
1206 ErrorCategory.Report(
1207 "decreasing address between debug_line rows", [&]() {
1208 error() <<
formatv(
".debug_line[{0:x+8}] row[{1}] decreases in "
1209 "address from previous row:\n",
1215 LineTable->Rows[RowIndex - 1].dump(OS);
1221 if (!LineTable->hasFileAtIndex(Row.File)) {
1222 ++NumDebugLineErrors;
1223 ErrorCategory.Report(
"Invalid file index in debug_line", [&]() {
1224 error() <<
formatv(
".debug_line[{0:x+8}][{1}] has invalid file index "
1225 "{2} (valid values are [{3},{4}{5}):\n",
1227 RowIndex, Row.File, MinFileIndex,
1228 LineTable->Prologue.FileNames.size(),
1229 (isDWARF5 ?
")" :
"]"));
1235 if (Row.EndSequence)
1238 PrevAddress = Row.Address.Address;
1246 : OS(S), DCtx(
D), DumpOpts(
std::
move(DumpOpts)), IsObjectFile(
false),
1247 IsMachOObject(
false) {
1248 ErrorCategory.ShowDetail(this->DumpOpts.
Verbose ||
1249 !this->DumpOpts.ShowAggregateErrors);
1250 if (
const auto *
F = DCtx.getDWARFObj().getFile()) {
1251 IsObjectFile = F->isRelocatableObject();
1252 IsMachOObject = F->isMachO();
1257 NumDebugLineErrors = 0;
1258 OS <<
"Verifying .debug_line...\n";
1259 verifyDebugLineStmtOffsets();
1260 verifyDebugLineRows();
1261 return NumDebugLineErrors == 0;
1264void DWARFVerifier::verifyAppleAccelTable(
const DWARFSection *AccelSection,
1274 if (!AccelSectionData.isValidOffset(
AccelTable.getSizeHdr())) {
1275 ErrorCategory.
Report(
"Section is too small to fit a section header", [&]() {
1276 error() <<
"Section is too small to fit a section header.\n";
1282 if (
Error E = AccelTable.extract()) {
1284 ErrorCategory.Report(
"Section is too small to fit a section header",
1285 [&]() {
error() <<
Msg <<
'\n'; });
1290 uint32_t NumBuckets = AccelTable.getNumBuckets();
1291 uint32_t NumHashes = AccelTable.getNumHashes();
1294 AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
1295 uint64_t HashesBase = BucketsOffset + NumBuckets * 4;
1296 uint64_t OffsetsBase = HashesBase + NumHashes * 4;
1297 for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
1298 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
1299 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
1300 ErrorCategory.Report(
"Invalid hash index", [&]() {
1301 error() <<
formatv(
"Bucket[{0}] has invalid hash index: {1}.\n",
1302 BucketIdx, HashIdx);
1306 uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
1307 if (NumAtoms == 0) {
1308 ErrorCategory.Report(
"No atoms", [&]() {
1309 error() <<
"No atoms: failed to read HashData.\n";
1313 if (!AccelTable.validateForms()) {
1314 ErrorCategory.Report(
"Unsupported form", [&]() {
1315 error() <<
"Unsupported form: failed to read HashData.\n";
1320 for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
1321 uint64_t HashOffset = HashesBase + 4 * HashIdx;
1322 uint64_t DataOffset = OffsetsBase + 4 * HashIdx;
1323 uint32_t Hash = AccelSectionData.getU32(&HashOffset);
1324 uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
1325 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
1327 ErrorCategory.Report(
"Invalid HashData offset", [&]() {
1328 error() <<
formatv(
"Hash[{0}] has invalid HashData offset: {1:x+8}.\n",
1329 HashIdx, HashDataOffset);
1335 uint32_t StringCount = 0;
1338 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
1339 const uint32_t NumHashDataObjects =
1340 AccelSectionData.getU32(&HashDataOffset);
1341 for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
1343 std::tie(
Offset,
Tag) = AccelTable.readAtoms(&HashDataOffset);
1344 auto Die = DCtx.getDIEForOffset(
Offset);
1346 const uint32_t BucketIdx =
1347 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
1348 StringOffset = StrpOffset;
1349 const char *
Name = StrData->
getCStr(&StringOffset);
1353 ErrorCategory.Report(
"Invalid DIE offset", [&]() {
1354 error() <<
formatv(
"{0} Bucket[{1}] Hash[{2}] = {3:x+8} "
1355 "Str[{4}] = {5:x+8} DIE[{6}] = {7:x+8} "
1356 "is not a valid DIE offset for \"{8}\".\n",
1357 SectionName, BucketIdx, HashIdx, Hash,
1358 StringCount, StrpOffset, HashDataIdx,
Offset,
1363 if ((
Tag != dwarf::DW_TAG_null) && (Die.
getTag() !=
Tag)) {
1364 ErrorCategory.Report(
"Mismatched Tag in accellerator table", [&]() {
1365 error() <<
formatv(
"Tag {0} in accelerator table does not match "
1366 "Tag {1} of DIE[{2}].\n",
1379 DenseMap<uint64_t, uint64_t> CUMap;
1380 CUMap.
reserve(DCtx.getNumCompileUnits());
1382 DenseSet<uint64_t> CUOffsets;
1383 for (
const auto &CU : DCtx.compile_units())
1384 CUOffsets.
insert(CU->getOffset());
1386 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
1388 ErrorCategory.Report(
"Name Index doesn't index any CU", [&]() {
1389 error() <<
formatv(
"Name Index @ {0:x} does not index any CU\n",
1397 ErrorCategory.Report(
"Name Index references non-existing CU", [&]() {
1399 "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
1406 std::lock_guard<std::mutex> Lock(AccessMutex);
1408 if (Iter != CUMap.
end())
1409 DuplicateCUOffset = Iter->second;
1413 if (DuplicateCUOffset) {
1414 ErrorCategory.Report(
"Duplicate Name Index", [&]() {
1416 "Name Index @ {0:x} references a CU @ {1:x}, but "
1417 "this CU is already indexed by Name Index @ {2:x}\n",
1425 for (
const auto &CU : DCtx.compile_units()) {
1426 if (CUMap.
count(CU->getOffset()) == 0)
1427 warn() <<
formatv(
"CU @ {0:x} not covered by any Name Index\n",
1438 constexpr BucketInfo(uint32_t Bucket, uint32_t
Index)
1444 warn() <<
formatv(
"Name Index @ {0:x} does not contain a hash table.\n",
1451 std::vector<BucketInfo> BucketStarts;
1453 const uint64_t OrigNumberOfErrors = ErrorCategory.GetNumErrors();
1457 ErrorCategory.Report(
"Name Index Bucket contains invalid value", [&]() {
1458 error() <<
formatv(
"Bucket {0} of Name Index @ {1:x} contains invalid "
1459 "value {2}. Valid range is [0, {3}].\n",
1466 BucketStarts.emplace_back(Bucket,
Index);
1472 if (OrigNumberOfErrors != ErrorCategory.GetNumErrors())
1485 uint32_t NextUncovered = 1;
1486 for (
const BucketInfo &
B : BucketStarts) {
1493 if (
B.Index > NextUncovered) {
1494 ErrorCategory.Report(
"Name table entries uncovered by hash table", [&]() {
1495 error() <<
formatv(
"Name Index @ {0:x}: Name table entries [{1}, {2}] "
1496 "are not covered by the hash table.\n",
1500 uint32_t
Idx =
B.Index;
1513 ErrorCategory.Report(
"Name Index point to mismatched hash value", [&]() {
1515 "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
1516 "mismatched hash value {2:x} (belonging to bucket {3}).\n",
1532 ErrorCategory.Report(
1533 "String hash doesn't match Name Index hash", [&]() {
1535 "Name Index @ {0:x}: String ({1}) at index {2} "
1536 "hashes to {3:x}, but "
1537 "the Name Index hash is {4:x}\n",
1543 NextUncovered = std::max(NextUncovered, Idx);
1547void DWARFVerifier::verifyNameIndexAttribute(
1551 if (FormName.
empty()) {
1552 ErrorCategory.Report(
"Unknown NameIndex Abbreviation", [&]() {
1553 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1554 "unknown form: {3}.\n",
1561 if (AttrEnc.
Index == DW_IDX_type_hash) {
1562 if (AttrEnc.
Form != dwarf::DW_FORM_data8) {
1563 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1565 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
1566 "uses an unexpected form {2} (should be {3}).\n",
1574 if (AttrEnc.
Index == dwarf::DW_IDX_parent) {
1575 constexpr static auto AllowedForms = {dwarf::Form::DW_FORM_flag_present,
1576 dwarf::Form::DW_FORM_ref4};
1578 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1580 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_parent "
1581 "uses an unexpected form {2} (should be "
1582 "DW_FORM_ref4 or DW_FORM_flag_present).\n",
1593 struct FormClassTable {
1596 StringLiteral ClassName;
1598 static constexpr FormClassTable
Table[] = {
1606 return T.Index == AttrEnc.
Index;
1609 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} contains an "
1610 "unknown index attribute: {2}.\n",
1615 if (!DWARFFormValue(AttrEnc.
Form).isFormClass(Iter->Class)) {
1616 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1617 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1618 "unexpected form {3} (expected form class {4}).\n",
1620 AttrEnc.
Form, Iter->ClassName);
1626void DWARFVerifier::verifyNameIndexAbbrevs(
1630 if (TagName.
empty()) {
1631 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} references an "
1632 "unknown tag: {2}.\n",
1636 for (
const auto &AttrEnc : Abbrev.Attributes) {
1638 ErrorCategory.Report(
1639 "NameIndex Abbreviateion contains multiple attributes", [&]() {
1641 "NameIndex @ {0:x}: Abbreviation {1:x} contains "
1642 "multiple {2} attributes.\n",
1647 verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
1651 !
Attributes.count(dwarf::DW_IDX_type_unit)) {
1652 ErrorCategory.Report(
"Abbreviation contains no attribute", [&]() {
1653 error() <<
formatv(
"NameIndex @ {0:x}: Indexing multiple compile units "
1654 "and abbreviation {1:x} has no DW_IDX_compile_unit "
1655 "or DW_IDX_type_unit attribute.\n",
1659 if (!
Attributes.count(dwarf::DW_IDX_die_offset)) {
1660 ErrorCategory.Report(
"Abbreviate in NameIndex missing attribute", [&]() {
1662 "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
1672 bool IncludeStrippedTemplateNames,
1673 bool IncludeObjCNames =
true,
1674 bool IncludeLinkageName =
true) {
1676 if (
const char *Str =
DIE.getShortName()) {
1678 Result.emplace_back(Name);
1679 if (IncludeStrippedTemplateNames) {
1680 if (std::optional<StringRef> StrippedName =
1684 Result.push_back(StrippedName->str());
1687 if (IncludeObjCNames) {
1688 if (std::optional<ObjCSelectorNames> ObjCNames =
1690 Result.emplace_back(ObjCNames->ClassName);
1691 Result.emplace_back(ObjCNames->Selector);
1692 if (ObjCNames->ClassNameNoCategory)
1693 Result.emplace_back(*ObjCNames->ClassNameNoCategory);
1694 if (ObjCNames->MethodNameNoCategory)
1695 Result.push_back(std::move(*ObjCNames->MethodNameNoCategory));
1698 }
else if (
DIE.
getTag() == dwarf::DW_TAG_namespace)
1699 Result.emplace_back(
"(anonymous namespace)");
1701 if (IncludeLinkageName) {
1702 if (
const char *Str =
DIE.getLinkageName())
1703 Result.emplace_back(Str);
1709void DWARFVerifier::verifyNameIndexEntries(
1715 ErrorCategory.Report(
"Unable to get string associated with name", [&]() {
1716 error() <<
formatv(
"Name Index @ {0:x}: Unable to get string associated "
1722 StringRef Str(CStr);
1726 Expected<DWARFDebugNames::Entry> EntryOr = NI.
getEntry(&NextEntryID);
1727 for (; EntryOr; ++
NumEntries, EntryID = NextEntryID,
1728 EntryOr = NI.
getEntry(&NextEntryID)) {
1730 std::optional<uint64_t> CUIndex = EntryOr->getRelatedCUIndex();
1731 std::optional<uint64_t> TUIndex = EntryOr->getTUIndex();
1732 if (CUIndex && *CUIndex >= NI.
getCUCount()) {
1733 ErrorCategory.Report(
"Name Index entry contains invalid CU index", [&]() {
1734 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1735 "invalid CU index ({2}).\n",
1742 if (TUIndex && *TUIndex >= (NumLocalTUs + NumForeignTUs)) {
1743 ErrorCategory.Report(
"Name Index entry contains invalid TU index", [&]() {
1744 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1745 "invalid TU index ({2}).\n",
1750 std::optional<uint64_t> UnitOffset;
1753 if (*TUIndex >= NumLocalTUs) {
1766 ErrorCategory.Report(
1767 "Name Index entry contains foreign TU index with invalid CU "
1771 "Name Index @ {0:x}: Entry @ {1:x} contains an "
1772 "foreign TU index ({2}) with no CU index.\n",
1781 }
else if (CUIndex) {
1787 if (!UnitOffset || UnitOffset == UINT32_MAX)
1792 DWARFUnit *DU = DCtx.getUnitForOffset(*UnitOffset);
1793 if (DU ==
nullptr || DU->
getOffset() != *UnitOffset) {
1796 ErrorCategory.Report(
1797 "Name Index entry contains invalid CU or TU offset", [&]() {
1798 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1799 "invalid CU or TU offset {2:x}.\n",
1818 auto IsSkeletonCU = [&]() {
1820 return UnitDie.
getTag() == dwarf::DW_TAG_skeleton_unit;
1823 bool IsSkeleton = DU->
getDWOId() && IsSkeletonCU();
1824 DWARFUnit *NonSkeletonUnit =
nullptr;
1827 NonSkeletonUnit = Iter->second;
1829 NonSkeletonUnit = DU;
1831 if (IsSkeleton && !NonSkeletonUnit->
isDWOUnit()) {
1832 ErrorCategory.Report(
"Unable to get load .dwo file", [&]() {
1834 "Name Index @ {0:x}: Entry @ {1:x} unable to load "
1835 ".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
1843 if (TUIndex && *TUIndex >= NumLocalTUs) {
1851 const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs;
1853 llvm::DWARFContext &NonSkeletonDCtx = NonSkeletonUnit->
getContext();
1861 if (NonSkeletonDCtx.
isDWP()) {
1862 DWARFDie NonSkeletonUnitDie = NonSkeletonUnit->
getUnitDIE(
true);
1864 UnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1866 NonSkeletonUnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1867 if (DUDwoName != TUDwoName)
1872 NonSkeletonUnit->
getOffset() + *EntryOr->getDIEUnitOffset();
1876 if (DIEOffset >= NextUnitOffset) {
1877 ErrorCategory.Report(
"NameIndex relative DIE offset too large", [&]() {
1878 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1879 "DIE @ {2:x} when CU or TU ends at {3:x}.\n",
1887 ErrorCategory.Report(
"NameIndex references nonexistent DIE", [&]() {
1888 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1889 "non-existing DIE @ {2:x}.\n",
1900 ErrorCategory.Report(
"Name index contains mismatched CU of DIE", [&]() {
1902 "Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
1903 "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
1908 if (DIE.
getTag() != EntryOr->tag()) {
1909 ErrorCategory.Report(
"Name Index contains mismatched Tag of DIE", [&]() {
1911 "Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
1912 "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1920 auto IncludeStrippedTemplateNames =
1921 DIE.
getTag() == DW_TAG_subprogram ||
1922 DIE.
getTag() == DW_TAG_inlined_subroutine;
1923 auto EntryNames =
getNames(DIE, IncludeStrippedTemplateNames);
1925 ErrorCategory.Report(
"Name Index contains mismatched name of DIE", [&]() {
1926 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
1927 "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1929 make_range(EntryNames.begin(), EntryNames.end()));
1934 EntryOr.takeError(),
1935 [&](
const DWARFDebugNames::SentinelError &) {
1938 ErrorCategory.Report(
1939 "NameIndex Name is not associated with any entries", [&]() {
1940 error() << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
1941 "not associated with any entries.\n",
1942 NI.getUnitOffset(), NTE.getIndex(), Str);
1946 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
1947 error() <<
formatv(
"Name Index @ {0:x}: Name {1} ({2}): {3}\n",
1962 for (
const auto &Entry : *
Loc) {
1965 U->getFormParams().Format);
1966 bool IsInteresting =
1969 return !
Op.isError() && (
Op.getCode() == DW_OP_addr ||
1970 Op.getCode() == DW_OP_form_tls_address ||
1971 Op.getCode() == DW_OP_GNU_push_tls_address);
1979void DWARFVerifier::verifyNameIndexCompleteness(
1988 if (Die.
find(DW_AT_declaration))
1998 auto IncludeLinkageName = Die.
getTag() == DW_TAG_subprogram ||
1999 Die.
getTag() == DW_TAG_inlined_subroutine;
2002 auto IncludeStrippedTemplateNames =
false;
2003 auto IncludeObjCNames =
false;
2004 auto EntryNames =
getNames(Die, IncludeStrippedTemplateNames,
2005 IncludeObjCNames, IncludeLinkageName);
2006 if (EntryNames.empty())
2016 case DW_TAG_compile_unit:
2022 case DW_TAG_formal_parameter:
2023 case DW_TAG_template_value_parameter:
2024 case DW_TAG_template_type_parameter:
2025 case DW_TAG_GNU_template_parameter_pack:
2026 case DW_TAG_GNU_template_template_param:
2033 case DW_TAG_property:
2039 case DW_TAG_LLVM_annotation:
2045 case DW_TAG_enumerator:
2050 case DW_TAG_imported_declaration:
2056 case DW_TAG_subprogram:
2057 case DW_TAG_inlined_subroutine:
2060 {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
2069 case DW_TAG_variable:
2081 for (StringRef Name : EntryNames) {
2082 auto iter = NamesToDieOffsets.find(Name);
2083 if (iter == NamesToDieOffsets.end() || !iter->second.count(DieUnitOffset)) {
2084 ErrorCategory.Report(
2085 "Name Index DIE entry missing name",
2088 "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
2089 "name {3} missing.\n",
2090 NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name);
2102 CUTU->getBaseAddress();
2105 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2106 DCtx.getRecoverableErrorHandler()(std::move(E));
2112 if (!
CU->getDWOId())
2115 CU->getNonSkeletonUnitDIE().getDwarfUnit()->getContext();
2117 for (
auto &CUTU : NonSkeletonContext.
dwo_units()) {
2119 CUTU->getBaseAddress();
2122 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2123 DCtx.getRecoverableErrorHandler()(std::move(E));
2126 if (NonSkeletonContext.
isDWP())
2131void DWARFVerifier::verifyDebugNames(
const DWARFSection &AccelSection,
2133 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,
2134 DCtx.isLittleEndian(), 0);
2135 DWARFDebugNames AccelTable(AccelSectionData, StrData);
2137 OS <<
"Verifying .debug_names...\n";
2143 ErrorCategory.Report(
"Accelerator Table Error",
2144 [&]() {
error() <<
Msg <<
'\n'; });
2147 const uint64_t OriginalNumErrors = ErrorCategory.GetNumErrors();
2148 verifyDebugNamesCULists(AccelTable);
2149 for (
const auto &NI : AccelTable)
2150 verifyNameIndexBuckets(NI, StrData);
2151 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
2152 verifyNameIndexAbbrevs(NI);
2156 if (OriginalNumErrors != ErrorCategory.GetNumErrors())
2158 DenseMap<uint64_t, DWARFUnit *> CUOffsetsToDUMap;
2159 for (
const auto &CU : DCtx.compile_units()) {
2160 if (!(CU->getVersion() >= 5 && CU->getDWOId()))
2162 CUOffsetsToDUMap[CU->getOffset()] =
2163 CU->getNonSkeletonUnitDIE().getDwarfUnit();
2166 for (
const DWARFDebugNames::NameIndex &NI : AccelTable) {
2168 verifyNameIndexEntries(NI, NTE, CUOffsetsToDUMap);
2172 auto populateNameToOffset =
2173 [&](
const DWARFDebugNames::NameIndex &NI,
2174 StringMap<DenseSet<uint64_t>> &NamesToDieOffsets) {
2175 for (
const DWARFDebugNames::NameTableEntry &NTE : NI) {
2177 const std::string
Name = tName ? std::string(tName) :
"";
2179 Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&EntryID);
2180 auto Iter = NamesToDieOffsets.insert({
Name, DenseSet<uint64_t>(3)});
2181 for (; EntryOr; EntryOr = NI.getEntry(&EntryID)) {
2182 if (std::optional<uint64_t> DieOffset = EntryOr->getDIEUnitOffset())
2183 Iter.first->second.insert(*DieOffset);
2187 [&](
const DWARFDebugNames::SentinelError &) {
2188 if (!NamesToDieOffsets.empty())
2190 ErrorCategory.Report(
2191 "NameIndex Name is not associated with any entries", [&]() {
2193 << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
2194 "not associated with any entries.\n",
2195 NI.getUnitOffset(), NTE.getIndex(), Name);
2198 [&](
const ErrorInfoBase &
Info) {
2199 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
2201 "Name Index @ {0:x}: Name {1} ({2}): {3}\n",
2202 NI.getUnitOffset(), NTE.
getIndex(), Name,
Info.message());
2211 populateNameToOffset(NI, NamesToDieOffsets);
2212 for (uint32_t i = 0, iEnd = NI.getCUCount(); i < iEnd; ++i) {
2213 const uint64_t CUOffset = NI.getCUOffset(i);
2214 DWARFUnit *
U = DCtx.getUnitForOffset(CUOffset);
2221 if (CUDie != NonSkeletonUnitDie) {
2225 verifyNameIndexCompleteness(
2226 DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), NI,
2232 verifyNameIndexCompleteness(DWARFDie(CU, &Die), NI,
2244 if (!
D.getAppleNamesSection().Data.empty())
2245 verifyAppleAccelTable(&
D.getAppleNamesSection(), &StrData,
".apple_names");
2246 if (!
D.getAppleTypesSection().Data.empty())
2247 verifyAppleAccelTable(&
D.getAppleTypesSection(), &StrData,
".apple_types");
2248 if (!
D.getAppleNamespacesSection().Data.empty())
2249 verifyAppleAccelTable(&
D.getAppleNamespacesSection(), &StrData,
2250 ".apple_namespaces");
2251 if (!
D.getAppleObjCSection().Data.empty())
2252 verifyAppleAccelTable(&
D.getAppleObjCSection(), &StrData,
".apple_objc");
2254 if (!
D.getNamesSection().Data.empty())
2255 verifyDebugNames(
D.getNamesSection(), StrData);
2256 return ErrorCategory.GetNumErrors() == 0;
2260 OS <<
"Verifying .debug_str_offsets...\n";
2269 std::optional<DwarfFormat> DwoLegacyDwarf4Format;
2271 if (DwoLegacyDwarf4Format)
2276 if (uint16_t InfoVersion = DebugInfoData.
getU16(&
Offset); InfoVersion <= 4)
2277 DwoLegacyDwarf4Format = InfoFormat;
2281 DwoLegacyDwarf4Format,
".debug_str_offsets.dwo",
2284 std::nullopt,
".debug_str_offsets",
2296 uint64_t NextUnit = 0;
2298 while (
C.seek(NextUnit),
C.tell() < DA.getData().size()) {
2301 uint64_t StartOffset =
C.tell();
2304 Length = DA.getData().size();
2310 if (
C.tell() +
Length > DA.getData().size()) {
2311 ErrorCategory.Report(
2312 "Section contribution length exceeds available space", [&]() {
2314 "{0}: contribution {1:X}: length exceeds available space "
2316 "offset ({1:X}) + length field space ({2:X}) + length "
2318 "{4:X} > section size {5:X})\n",
2320 C.tell() +
Length, DA.getData().size());
2329 ErrorCategory.Report(
"Invalid Section version", [&]() {
2330 error() <<
formatv(
"{0}: contribution {1:X}: invalid version {2}\n",
2341 DA.setAddressSize(OffsetByteSize);
2342 uint64_t Remainder = (
Length - 4) % OffsetByteSize;
2343 if (Remainder != 0) {
2344 ErrorCategory.Report(
"Invalid section contribution length", [&]() {
2346 "{0}: contribution {1:X}: invalid length ((length ({2:X}) "
2347 "- header (0x4)) % offset size {3:X} == {4:X} != 0)\n",
2352 for (uint64_t
Index = 0;
C &&
C.tell() + OffsetByteSize <= NextUnit;
2354 uint64_t OffOff =
C.tell();
2355 uint64_t StrOff = DA.getAddress(
C);
2359 if (StrData.
size() <= StrOff) {
2360 ErrorCategory.Report(
2361 "String offset out of bounds of string section", [&]() {
2363 "{0}: contribution {1:X}: index {2:X}: invalid string "
2364 "offset *{3:X} == {4:X}, is beyond the bounds of the string "
2365 "section of length {5:X}\n",
2371 if (StrData[StrOff - 1] ==
'\0')
2373 ErrorCategory.Report(
2374 "Section contribution contains invalid string offset", [&]() {
2376 "{0}: contribution {1:X}: index {2:X}: invalid string "
2377 "offset *{3:X} == {4:X}, is neither zero nor "
2378 "immediately following a null character\n",
2385 if (
Error E =
C.takeError()) {
2387 ErrorCategory.Report(
"String offset error", [&]() {
2396 Report(s,
"", detailCallback);
2402 std::lock_guard<std::mutex> Lock(WriteMutex);
2404 std::string category_str = std::string(category);
2407 if (!sub_category.
empty()) {
2416 for (
const auto &[
name, aggData] : Aggregation) {
2417 handleCounts(
name, aggData.OverallCount);
2422 const auto Agg = Aggregation.find(category);
2423 if (Agg != Aggregation.end()) {
2425 handleCounts(
name, aggData);
2431 if (DumpOpts.ShowAggregateErrors && ErrorCategory.GetNumCategories()) {
2432 error() <<
"Aggregated error counts:\n";
2433 ErrorCategory.EnumerateResults([&](
StringRef s,
unsigned count) {
2437 if (!DumpOpts.JsonErrSummaryFile.empty()) {
2443 "unable to open json summary file {0} for writing: {1}\n",
2444 DumpOpts.JsonErrSummaryFile, EC.message());
2449 uint64_t ErrorCount = 0;
2450 ErrorCategory.EnumerateResults([&](
StringRef Category,
unsigned Count) {
2454 ErrorCategory.EnumerateDetailedResultsFor(
2455 Category, [&](
StringRef SubCategory,
unsigned SubCount) {
2460 ErrorCount +=
Count;
2463 RootNode.
try_emplace(
"error-categories", std::move(Categories));
2477 Die.
dump(OS, indent, DumpOpts);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ArrayRef< TableEntry > TableRef
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void extractCUsTus(DWARFContext &DCtx)
Extracts all the data for CU/TUs so we can access it in parallel without locks.
static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx)
static SmallVector< std::string, 3 > getNames(const DWARFDie &DIE, bool IncludeStrippedTemplateNames, bool IncludeObjCNames=true, bool IncludeLinkageName=true)
Constructs a full name for a DIE.
This file contains constants used for implementing Dwarf debug support.
This file implements a coalescing interval map for small objects.
This file supports working with JSON data.
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
This file defines the SmallSet class.
This class holds an abstract representation of an Accelerator Table, consisting of a sequence of buck...
This implements the Apple accelerator table format, a precursor of the DWARF 5 accelerator table form...
A structured debug information entry.
dwarf::Tag getTag() const
DWARFContext This data structure is the top level entity that deals with dwarf debug information pars...
static bool isSupportedVersion(unsigned version)
compile_unit_range compile_units()
Get compile units in this context.
const DWARFDebugAbbrev * getDebugAbbrev()
Get a pointer to the parsed DebugAbbrev object.
bool isDWP() const
Return true of this DWARF context is a DWP file.
bool isLittleEndian() const
DWARFTypeUnit * getTypeUnitForHash(uint64_t Hash, bool IsDWO)
unit_iterator_range normal_units()
Get all normal compile/type units in this context.
static bool isAddressSizeSupported(unsigned AddressSize)
unit_iterator_range dwo_units()
Get all units in the DWO context.
const DWARFObject & getDWARFObj() const
LLVM_ABI Expected< const DWARFAbbreviationDeclarationSet * > getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const
DWARFDebugInfoEntry - A DIE with only the minimum required data.
Represents a single accelerator table within the DWARF v5 .debug_names section.
LLVM_ABI uint32_t getHashArrayEntry(uint32_t Index) const
Reads an entry in the Hash Array for the given Index.
LLVM_ABI uint64_t getLocalTUOffset(uint32_t TU) const
Reads offset of local type unit TU, TU is 0-based.
LLVM_ABI uint32_t getBucketArrayEntry(uint32_t Bucket) const
Reads an entry in the Bucket Array for the given Bucket.
uint64_t getUnitOffset() const
uint32_t getCUCount() const
LLVM_ABI uint64_t getCUOffset(uint32_t CU) const
Reads offset of compilation unit CU. CU is 0-based.
LLVM_ABI Expected< Entry > getEntry(uint64_t *Offset) const
LLVM_ABI NameTableEntry getNameTableEntry(uint32_t Index) const
Reads an entry in the Name Table for the given Index.
uint32_t getNameCount() const
const DenseSet< Abbrev, AbbrevMapInfo > & getAbbrevs() const
uint32_t getForeignTUCount() const
LLVM_ABI uint64_t getForeignTUSignature(uint32_t TU) const
Reads signature of foreign type unit TU. TU is 0-based.
uint32_t getBucketCount() const
uint32_t getLocalTUCount() const
A single entry in the Name Table (DWARF v5 sect.
uint64_t getEntryOffset() const
Returns the offset of the first Entry in the list.
const char * getString() const
Return the string referenced by this name table entry or nullptr if the string offset is not valid.
uint32_t getIndex() const
Return the index of this name in the parent Name Index.
.debug_names section consists of one or more units.
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
LLVM_ABI void getFullName(raw_string_ostream &, std::string *OriginalFullName=nullptr) const
uint64_t getOffset() const
Get the absolute offset into the debug info or types section.
LLVM_ABI Expected< DWARFAddressRangesVector > getAddressRanges() const
Get the address ranges for this DIE.
LLVM_ABI DWARFDie getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE as the referenced DIE.
LLVM_ABI DWARFDie getParent() const
Get the parent of this DIE object.
LLVM_ABI std::optional< DWARFFormValue > find(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE.
DWARFUnit * getDwarfUnit() const
LLVM_ABI bool isSubprogramDIE() const
Returns true if DIE represents a subprogram (not inlined).
LLVM_ABI std::optional< DWARFFormValue > findRecursively(ArrayRef< dwarf::Attribute > Attrs) const
Extract the first value of any attribute in Attrs from this DIE and recurse into any DW_AT_specificat...
LLVM_ABI DWARFDie getFirstChild() const
Get the first child of this DIE object.
dwarf::Tag getTag() const
LLVM_ABI Expected< DWARFLocationExpressionsVector > getLocations(dwarf::Attribute Attr) const
LLVM_ABI iterator_range< attribute_iterator > attributes() const
Get an iterator range to all attributes in the current DIE only.
LLVM_ABI void dump(raw_ostream &OS, unsigned indent=0, DIDumpOptions DumpOpts=DIDumpOptions()) const
Dump the DIE and all of its attributes to the supplied stream.
This class represents an Operation in the Expression.
virtual StringRef getStrDWOSection() const
virtual StringRef getAbbrevDWOSection() const
virtual StringRef getAbbrevSection() const
virtual const DWARFSection & getStrOffsetsDWOSection() const
virtual void forEachInfoDWOSections(function_ref< void(const DWARFSection &)> F) const
virtual void forEachInfoSections(function_ref< void(const DWARFSection &)> F) const
virtual const DWARFSection & getRangesSection() const
virtual void forEachTypesSections(function_ref< void(const DWARFSection &)> F) const
virtual const DWARFSection & getStrOffsetsSection() const
virtual const DWARFSection & getRnglistsSection() const
virtual StringRef getStrSection() const
uint64_t getLength() const
uint64_t getOffset() const
Describe a collection of units.
std::optional< uint64_t > getDWOId()
DWARFDie getNonSkeletonUnitDIE(bool ExtractUnitDIEOnly=true, StringRef DWOAlternativeLocation={})
DWARFDie getUnitDIE(bool ExtractUnitDIEOnly=true)
DWARFContext & getContext() const
DWARFDie getDIEForOffset(uint64_t Offset)
Return the DIE object for a given offset Offset inside the unit's DIE vector.
uint16_t getVersion() const
die_iterator_range dies()
static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag)
uint64_t getNextUnitOffset() const
uint64_t getOffset() const
LLVM_ABI bool handleAccelTables()
Verify the information in accelerator tables, if they exist.
LLVM_ABI bool verifyDebugStrOffsets(std::optional< dwarf::DwarfFormat > LegacyFormat, StringRef SectionName, const DWARFSection &Section, StringRef StrData)
LLVM_ABI bool handleDebugTUIndex()
Verify the information in the .debug_tu_index section.
LLVM_ABI bool handleDebugStrOffsets()
Verify the information in the .debug_str_offsets[.dwo].
LLVM_ABI bool handleDebugCUIndex()
Verify the information in the .debug_cu_index section.
LLVM_ABI DWARFVerifier(raw_ostream &S, DWARFContext &D, DIDumpOptions DumpOpts=DIDumpOptions::getForSingleDIE())
LLVM_ABI bool handleDebugInfo()
Verify the information in the .debug_info and .debug_types sections.
LLVM_ABI bool handleDebugLine()
Verify the information in the .debug_line section.
LLVM_ABI void summarize()
Emits any aggregate information collected, depending on the dump options.
LLVM_ABI bool handleDebugAbbrev()
Verify the information in any of the following sections, if available: .debug_abbrev,...
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
iterator find(const_arg_type_t< KeyT > Val)
void reserve(size_type NumEntries)
Grow the DenseMap so that it can contain at least NumEntries items before resizing again.
Implements a dense probed hash-table based set.
Base class for error info classes.
Lightweight error class with error context and mandatory checking.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
Class representing an expression and its matching format.
LLVM_ABI void Report(StringRef category, function_ref< void()> detailCallback)
LLVM_ABI void EnumerateDetailedResultsFor(StringRef category, function_ref< void(StringRef, unsigned)> handleCounts)
LLVM_ABI void EnumerateResults(function_ref< void(StringRef, unsigned)> handleCounts)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
std::pair< iterator, bool > try_emplace(StringRef Key, ArgsTy &&...Args)
Emplace a new element for the specified key into the map if the key isn't already in the map.
Represent a constant reference to a string, i.e.
constexpr bool empty() const
Check if the string is empty.
constexpr size_t size() const
Get the string size.
static LLVM_ABI raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
static LLVM_ABI raw_ostream & error()
Convenience method for printing "error: " to stderr.
static LLVM_ABI raw_ostream & note()
Convenience method for printing "note: " to stderr.
std::pair< iterator, bool > insert(const ValueT &V)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
An efficient, type-erasing, non-owning reference to a callable.
An Object is a JSON object, which maps strings to heterogenous JSON values.
std::pair< iterator, bool > try_emplace(const ObjectKey &K, Ts &&... Args)
A Value is an JSON value of unknown type.
A raw_ostream that writes to a file descriptor.
This class implements an extremely fast bulk output stream that can only output to a stream.
LLVM_ABI StringRef AttributeString(unsigned Attribute)
LLVM_ABI StringRef FormEncodingString(unsigned Encoding)
LLVM_ABI StringRef UnitTypeString(unsigned)
LLVM_ABI StringRef TagString(unsigned Tag)
Calculates the starting offsets for various sections within the .debug_names section.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
bool isUnitType(uint8_t UnitType)
UnitType
Constants for unit types in DWARF v5.
DwarfFormat
Constants that define the DWARF format as 32 or 64 bit.
std::optional< uint64_t > toSectionOffset(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an section offset.
StringRef toStringRef(const std::optional< DWARFFormValue > &V, StringRef Default={})
Take an optional DWARFFormValue and try to extract a string value from it.
uint8_t getDwarfOffsetByteSize(DwarfFormat Format)
The size of a reference determined by the DWARF 32/64-bit format.
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
bool operator<(int64_t V1, const APSInt &V2)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
DWARFSectionKind
The enum of section identifiers to be used in internal interfaces.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ABI std::optional< StringRef > StripTemplateParameters(StringRef Name)
If Name is the name of a templated function that includes template parameters, returns a substring of...
@ Success
The lock was released successfully.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
LLVM_ABI uint32_t caseFoldingDjbHash(StringRef Buffer, uint32_t H=5381)
Computes the Bernstein hash after folding the input according to the Dwarf 5 standard case folding ru...
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI std::optional< ObjCSelectorNames > getObjCNamesIfSelector(StringRef Name)
If Name is the AT_name of a DIE which refers to an Objective-C selector, returns an instance of ObjCS...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
void array_pod_sort(IteratorTy Start, IteratorTy End)
array_pod_sort - This sorts an array with the specified start and end extent.
void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn)
@ End
Run the machine verifier once, at the end of the pipeline.
void consumeError(Error Err)
Consume a Error without doing anything.
std::vector< DWARFAddressRange > DWARFAddressRangesVector
DWARFAddressRangesVector - represents a set of absolute address ranges.
Implement std::hash so that hash_code can be used in STL containers.
std::map< std::string, unsigned > DetailedCounts
Container for dump options that control which debug information will be dumped.
unsigned ChildRecurseDepth
DWARFFormValue Value
The form and value for this attribute.
dwarf::Attribute Attr
The attribute enumeration of this attribute.
static LLVM_ABI void dumpTableHeader(raw_ostream &OS, unsigned Indent)
Abbreviation describing the encoding of Name Index entries.
uint32_t Code
< Abbreviation offset in the .debug_names section
Index attribute and its encoding.
SmallVector< Encoding > Op
Encoding for Op operands.
A class that keeps the address range information for a single DIE.
std::vector< DWARFAddressRange > Ranges
Sorted DWARFAddressRanges.
LLVM_ABI bool contains(const DieRangeInfo &RHS) const
Return true if ranges in this object contains all ranges within RHS.
std::set< DieRangeInfo >::const_iterator die_range_info_iterator
LLVM_ABI bool intersects(const DieRangeInfo &RHS) const
Return true if any range in this object intersects with any range in RHS.
std::set< DieRangeInfo > Children
Sorted DWARFAddressRangeInfo.
LLVM_ABI std::optional< DWARFAddressRange > insert(const DWARFAddressRange &R)
Inserts the address range.