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)
160 bool ValidLength =
false;
161 bool ValidVersion =
false;
162 bool ValidAddrSize =
false;
163 bool ValidType =
true;
164 bool ValidAbbrevOffset =
true;
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);
303 DWARFDie Die =
Unit.getUnitDIE(
false);
305 ErrorCategory.Report(
"Compilation unit missing DIE", [&]() {
306 error() <<
"Compilation unit without DIE.\n";
309 return NumUnitErrors;
313 ErrorCategory.Report(
"Compilation unit root DIE is not a unit DIE", [&]() {
314 error() <<
formatv(
"Compilation unit root DIE is not a unit DIE: {0}.\n",
322 ErrorCategory.Report(
"Mismatched unit type", [&]() {
324 "Compilation unit type ({0}) and root DIE ({1}) do not match.\n",
334 ErrorCategory.Report(
"Skeleton CU has children", [&]() {
335 error() <<
"Skeleton compilation unit has children.\n";
341 NumUnitErrors += verifyDieRanges(Die, RI);
343 return NumUnitErrors;
346unsigned DWARFVerifier::verifyDebugInfoCallSite(
const DWARFDie &Die) {
347 if (Die.
getTag() != DW_TAG_call_site && Die.
getTag() != DW_TAG_GNU_call_site)
352 if (Curr.
getTag() == DW_TAG_inlined_subroutine) {
353 ErrorCategory.Report(
354 "Call site nested entry within inlined subroutine", [&]() {
355 error() <<
"Call site entry nested within inlined subroutine:";
363 ErrorCategory.Report(
364 "Call site entry not nested within valid subprogram", [&]() {
365 error() <<
"Call site entry not nested within a valid subprogram:";
371 std::optional<DWARFFormValue> CallAttr = Curr.
find(
372 {DW_AT_call_all_calls, DW_AT_call_all_source_calls,
373 DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,
374 DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites});
376 ErrorCategory.Report(
377 "Subprogram with call site entry has no DW_AT_call attribute", [&]() {
379 <<
"Subprogram with call site entry has no DW_AT_call attribute:";
389unsigned DWARFVerifier::verifyAbbrevSection(
const DWARFDebugAbbrev *Abbrev) {
393 Expected<const DWARFAbbreviationDeclarationSet *> AbbrDeclsOrErr =
395 if (!AbbrDeclsOrErr) {
397 ErrorCategory.Report(
"Abbreviation Declaration error",
398 [&]() {
error() << ErrMsg <<
"\n"; });
402 const auto *AbbrDecls = *AbbrDeclsOrErr;
403 unsigned NumErrors = 0;
404 for (
auto AbbrDecl : *AbbrDecls) {
405 SmallDenseSet<uint16_t> AttributeSet;
406 for (
auto Attribute : AbbrDecl.attributes()) {
409 ErrorCategory.Report(
410 "Abbreviation declartion contains multiple attributes", [&]() {
411 error() <<
formatv(
"Abbreviation declaration contains multiple "
424 OS <<
"Verifying .debug_abbrev...\n";
427 unsigned NumErrors = 0;
429 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
431 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
433 return NumErrors == 0;
437 unsigned NumDebugInfoErrors = 0;
438 ReferenceMap CrossUnitReferences;
442 for (
const auto &Unit : Units) {
443 OS <<
formatv(
"Verifying unit: {0} / {1}",
Index, Units.getNumUnits());
444 if (
const char *Name = Unit->getUnitDIE(
true).getShortName())
445 OS <<
formatv(
", \"{0}\"", Name);
448 ReferenceMap UnitLocalReferences;
449 NumDebugInfoErrors +=
450 verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences);
451 NumDebugInfoErrors += verifyDebugInfoReferences(
452 UnitLocalReferences, [&](
uint64_t Offset) {
return Unit.get(); });
456 NumDebugInfoErrors += verifyDebugInfoReferences(
457 CrossUnitReferences, [&](uint64_t
Offset) -> DWARFUnit * {
458 if (DWARFUnit *U = Units.getUnitForOffset(
Offset))
463 return NumDebugInfoErrors;
466unsigned DWARFVerifier::verifyUnitSection(
const DWARFSection &S) {
467 const DWARFObject &DObj = DCtx.getDWARFObj();
468 DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);
469 unsigned NumDebugInfoErrors = 0;
470 uint64_t
Offset = 0, UnitIdx = 0;
472 bool isUnitDWARF64 =
false;
473 bool isHeaderChainValid =
true;
475 DWARFUnitVector TypeUnitVector;
476 DWARFUnitVector CompileUnitVector;
480 isHeaderChainValid =
false;
487 if (UnitIdx == 0 && !hasDIE) {
488 warn() <<
"Section is empty.\n";
489 isHeaderChainValid =
true;
491 if (!isHeaderChainValid)
492 ++NumDebugInfoErrors;
493 return NumDebugInfoErrors;
496unsigned DWARFVerifier::verifyIndex(StringRef Name,
498 StringRef IndexStr) {
499 if (IndexStr.
empty())
501 OS <<
"Verifying " <<
Name <<
"...\n";
502 DWARFUnitIndex
Index(InfoColumnKind);
503 DataExtractor
D(IndexStr, DCtx.isLittleEndian(), 0);
506 using MapType = IntervalMap<uint64_t, uint64_t>;
507 MapType::Allocator
Alloc;
508 std::vector<std::unique_ptr<MapType>> Sections(
Index.getColumnKinds().size());
509 for (
const DWARFUnitIndex::Entry &
E :
Index.getRows()) {
510 uint64_t Sig =
E.getSignature();
511 if (!
E.getContributions())
514 InfoColumnKind == DW_SECT_INFO
517 const DWARFUnitIndex::Entry::SectionContribution &SC =
E.value();
522 Sections[Col] = std::make_unique<MapType>(
Alloc);
523 auto &
M = *Sections[Col];
526 StringRef Category = InfoColumnKind == DWARFSectionKind::DW_SECT_INFO
527 ?
"Overlapping CU index entries"
528 :
"Overlapping TU index entries";
529 ErrorCategory.Report(Category, [&]() {
531 "overlapping index entries for entries {0:x16} "
532 "and {1:x16} for column {2}\n",
545 return verifyIndex(
".debug_cu_index", DWARFSectionKind::DW_SECT_INFO,
546 DCtx.getDWARFObj().getCUIndexSection()) == 0;
551 DCtx.getDWARFObj().getTUIndexSection()) == 0;
556 unsigned NumErrors = 0;
558 OS <<
"Verifying .debug_info Unit Header Chain...\n";
560 [&](
const DWARFSection &S) { NumErrors += verifyUnitSection(S); });
562 OS <<
"Verifying .debug_types Unit Header Chain...\n";
564 [&](
const DWARFSection &S) { NumErrors += verifyUnitSection(S); });
566 OS <<
"Verifying non-dwo Units...\n";
567 NumErrors += verifyUnits(DCtx.getNormalUnitsVector());
569 OS <<
"Verifying dwo Units...\n";
570 NumErrors += verifyUnits(DCtx.getDWOUnitsVector());
571 return NumErrors == 0;
574unsigned DWARFVerifier::verifyDieRanges(
const DWARFDie &Die,
575 DieRangeInfo &ParentRI) {
576 unsigned NumErrors = 0;
584 if (!RangesOrError) {
586 if (!Unit->isDWOUnit())
595 DieRangeInfo RI(Die);
616 if (!IsObjectFile || IsMachOObject || Die.
getTag() != DW_TAG_compile_unit) {
617 bool DumpDieAfterError =
false;
618 for (
const auto &
Range : Ranges) {
619 if (!
Range.valid()) {
621 ErrorCategory.
Report(
"Invalid address range", [&]() {
623 DumpDieAfterError =
true;
634 if (
auto PrevRange = RI.insert(
Range)) {
636 ErrorCategory.Report(
"DIE has overlapping DW_AT_ranges", [&]() {
637 error() <<
formatv(
"DIE has overlapping ranges in DW_AT_ranges "
638 "attribute: {0} and {1}\n",
640 DumpDieAfterError =
true;
644 if (DumpDieAfterError)
645 dump(Die, 2) <<
'\n';
649 const auto IntersectingChild = ParentRI.insert(RI);
650 if (IntersectingChild != ParentRI.Children.end()) {
652 ErrorCategory.Report(
"DIEs have overlapping address ranges", [&]() {
653 error() <<
"DIEs have overlapping address ranges:";
655 dump(IntersectingChild->Die) <<
'\n';
660 bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() &&
661 !(Die.
getTag() == DW_TAG_subprogram &&
662 ParentRI.Die.getTag() == DW_TAG_subprogram);
663 if (ShouldBeContained && !ParentRI.contains(RI)) {
665 ErrorCategory.Report(
666 "DIE address ranges are not contained by parent ranges", [&]() {
668 <<
"DIE address ranges are not contained in its parent's ranges:";
670 dump(Die, 2) <<
'\n';
675 for (DWARFDie Child : Die)
676 NumErrors += verifyDieRanges(Child, RI);
681bool DWARFVerifier::verifyExpressionOp(
const DWARFExpression::Operation &
Op,
683 for (
unsigned Operand = 0; Operand <
Op.Desc.
Op.
size(); ++Operand) {
684 unsigned Size =
Op.Desc.
Op[Operand];
691 if (
Op.Opcode == DW_OP_convert &&
Op.Operands[Operand] == 0)
693 auto Die =
U->getDIEForOffset(
U->getOffset() +
Op.Operands[Operand]);
694 if (!Die || Die.
getTag() != dwarf::DW_TAG_base_type)
702bool DWARFVerifier::verifyExpression(
const DWARFExpression &
E, DWARFUnit *U) {
704 if (!verifyExpressionOp(
Op, U))
710unsigned DWARFVerifier::verifyDebugInfoAttribute(
const DWARFDie &Die,
711 DWARFAttribute &AttrValue) {
712 unsigned NumErrors = 0;
713 auto ReportError = [&](StringRef category,
const Twine &TitleMsg) {
715 ErrorCategory.Report(category, [&]() {
721 const DWARFObject &DObj = DCtx.getDWARFObj();
723 const auto Attr = AttrValue.
Attr;
728 unsigned DwarfVersion =
U->getVersion();
729 const DWARFSection &RangeSection = DwarfVersion < 5
732 if (
U->isDWOUnit() && RangeSection.
Data.
empty())
734 if (*SectionOffset >= RangeSection.
Data.
size())
736 "DW_AT_ranges offset out of bounds",
737 llvm::formatv(
"DW_AT_ranges offset is beyond {0} bounds: {1:x8}",
738 StringRef(DwarfVersion < 5 ?
".debug_ranges"
739 :
".debug_rnglists"),
743 ReportError(
"Invalid DW_AT_ranges encoding",
744 "DIE has invalid DW_AT_ranges encoding:");
746 case DW_AT_stmt_list:
749 if (*SectionOffset >=
U->getLineSection().Data.size())
751 "DW_AT_stmt_list offset out of bounds",
753 "DW_AT_stmt_list offset is beyond .debug_line bounds: {0:x8}",
757 ReportError(
"Invalid DW_AT_stmt_list encoding",
758 "DIE has invalid DW_AT_stmt_list encoding:");
760 case DW_AT_location: {
771 if (Expected<std::vector<DWARFLocationExpression>> Loc =
773 for (
const auto &Entry : *Loc) {
775 DWARFExpression Expression(
Data,
U->getAddressByteSize(),
776 U->getFormParams().Format);
778 any_of(Expression, [](
const DWARFExpression::Operation &
Op) {
781 if (
Error || !verifyExpression(Expression, U))
782 ReportError(
"Invalid DWARF expressions",
783 "DIE contains invalid DWARF expression:");
786 Loc.takeError(), [&](std::unique_ptr<ResolverError>
E) {
787 return U->isDWOUnit() ? Error::success()
788 : Error(std::move(E));
790 ReportError(
"Invalid DW_AT_location",
toString(std::move(Err)));
793 case DW_AT_specification:
794 case DW_AT_abstract_origin: {
796 auto DieTag = Die.
getTag();
797 auto RefTag = ReferencedDie.getTag();
798 if (DieTag == RefTag)
800 if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
802 if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
805 if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)
807 ReportError(
"Incompatible DW_AT_abstract_origin tag reference",
808 formatv(
"DIE with tag {0} has {1} that points to DIE with "
809 "incompatible tag {2}",
818 ReportError(
"Incompatible DW_AT_type attribute tag",
819 formatv(
"DIE has {0} with incompatible tag {1}",
824 case DW_AT_call_file:
825 case DW_AT_decl_file: {
827 if (
U->isDWOUnit() && !
U->isTypeUnit())
829 const auto *
LT =
U->getContext().getLineTableForUnit(U);
831 if (!
LT->hasFileAtIndex(*FileIdx)) {
832 bool IsZeroIndexed =
LT->Prologue.getVersion() >= 5;
833 if (std::optional<uint64_t> LastFileIdx =
834 LT->getLastValidFileIndex()) {
835 ReportError(
"Invalid file index in DW_AT_decl_file",
837 "{1} (valid values are [{2}-{3}])",
839 (IsZeroIndexed ?
"0" :
"1"),
843 "Invalid file index in DW_AT_decl_file",
844 llvm::formatv(
"DIE has {0} with an invalid file index {1} (the "
845 "file table in the prologue is empty)",
851 "File index in DW_AT_decl_file reference CU with no line table",
852 llvm::formatv(
"DIE has {0} that references a file with index {1} "
853 "and the compile unit has no line table",
857 ReportError(
"Invalid encoding in DW_AT_decl_file",
863 case DW_AT_call_line:
864 case DW_AT_decl_line: {
867 Attr == DW_AT_call_line ?
"Invalid file index in DW_AT_decl_line"
868 :
"Invalid file index in DW_AT_call_line",
873 case DW_AT_LLVM_stmt_sequence: {
877 if (!SectionOffset) {
878 ReportError(
"Invalid DW_AT_LLVM_stmt_sequence encoding",
879 "DIE has invalid DW_AT_LLVM_stmt_sequence encoding");
882 if (*SectionOffset >=
U->getLineSection().Data.size()) {
884 "DW_AT_LLVM_stmt_sequence offset out of bounds",
885 "DW_AT_LLVM_stmt_sequence offset is beyond .debug_line bounds: " +
891 const auto *LineTable = DCtx.getLineTableForUnit(U);
893 ReportError(
"DW_AT_LLVM_stmt_sequence without line table",
894 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
900 DWARFDie CUDie =
U->getUnitDIE();
902 if (!StmtListOffset) {
903 ReportError(
"DW_AT_LLVM_stmt_sequence without DW_AT_stmt_list",
904 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
909 const int8_t DwarfOffset =
910 LineTable->Prologue.getFormParams().getDwarfOffsetByteSize();
912 uint64_t LineTableStart = *StmtListOffset;
913 uint64_t PrologueLength = LineTable->Prologue.PrologueLength;
914 uint64_t TotalLength = LineTable->Prologue.TotalLength;
915 uint64_t LineTableEnd = LineTableStart + TotalLength + DwarfOffset;
920 uint64_t InitialLengthSize = DwarfOffset;
922 uint64_t VersionSize = 2;
923 uint64_t PrologueLengthSize = DwarfOffset;
924 uint64_t SequencesStart = LineTableStart + InitialLengthSize + VersionSize +
925 PrologueLengthSize + PrologueLength;
928 if (*SectionOffset < SequencesStart || *SectionOffset >= LineTableEnd) {
929 ReportError(
"DW_AT_LLVM_stmt_sequence offset out of line table bounds",
930 llvm::formatv(
"DW_AT_LLVM_stmt_sequence offset {0:x8} is not "
931 "within the line table bounds [{1:x8}, {2:x8})",
932 *SectionOffset, SequencesStart, LineTableEnd));
938 [SectionOffset](
const auto &Sequence) {
939 return Sequence.StmtSeqOffset == *SectionOffset;
942 if (It == LineTable->Sequences.end())
944 "Invalid DW_AT_LLVM_stmt_sequence offset",
945 llvm::formatv(
"DW_AT_LLVM_stmt_sequence offset {0:x8} does not point "
946 "to a valid sequence offset in the line table",
956unsigned DWARFVerifier::verifyDebugInfoForm(
const DWARFDie &Die,
957 DWARFAttribute &AttrValue,
958 ReferenceMap &LocalReferences,
959 ReferenceMap &CrossUnitReferences) {
961 unsigned NumErrors = 0;
968 case DW_FORM_ref_udata: {
973 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
975 if (CUOffset >= CUSize) {
977 ErrorCategory.Report(
"Invalid CU offset", [&]() {
978 error() <<
formatv(
"{0} CU offset {1:x+8} is invalid (must be less "
979 "than CU size of {2:x+8}):\n",
981 Die.
dump(OS, 0, DumpOpts);
993 case DW_FORM_ref_addr: {
999 if (*RefVal >= DieCU->getInfoSection().Data.size()) {
1001 ErrorCategory.Report(
"DW_FORM_ref_addr offset out of bounds", [&]() {
1002 error() <<
"DW_FORM_ref_addr offset beyond .debug_info "
1009 CrossUnitReferences[*RefVal].insert(Die.
getOffset());
1020 case DW_FORM_line_strp: {
1023 std::string ErrMsg =
toString(std::move(
E));
1024 ErrorCategory.Report(
"Invalid DW_FORM attribute", [&]() {
1037unsigned DWARFVerifier::verifyDebugInfoReferences(
1038 const ReferenceMap &References,
1039 llvm::function_ref<DWARFUnit *(uint64_t)> GetUnitForOffset) {
1040 auto GetDIEForOffset = [&](uint64_t
Offset) {
1041 if (DWARFUnit *U = GetUnitForOffset(
Offset))
1042 return U->getDIEForOffset(
Offset);
1045 unsigned NumErrors = 0;
1046 for (
const std::pair<
const uint64_t, std::set<uint64_t>> &Pair : References) {
1047 if (GetDIEForOffset(Pair.first))
1050 ErrorCategory.Report(
"Invalid DIE reference", [&]() {
1052 "invalid DIE reference {0:x+8}. Offset is in between DIEs:\n",
1054 for (
auto Offset : Pair.second)
1062void DWARFVerifier::verifyDebugLineStmtOffsets() {
1063 std::map<uint64_t, DWARFDie> StmtListToDie;
1064 for (
const auto &CU : DCtx.compile_units()) {
1065 auto Die = CU->getUnitDIE();
1070 if (!StmtSectionOffset)
1072 const uint64_t LineTableOffset = *StmtSectionOffset;
1073 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1074 if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
1076 ++NumDebugLineErrors;
1077 ErrorCategory.Report(
"Unparsable .debug_line entry", [&]() {
1079 ".debug_line[{0:x+8}] was not able to be parsed for CU:\n",
1087 assert(LineTable ==
nullptr);
1092 auto [Iter,
Inserted] = StmtListToDie.try_emplace(LineTableOffset, Die);
1094 ++NumDebugLineErrors;
1095 const auto &OldDie = Iter->second;
1096 ErrorCategory.Report(
"Identical DW_AT_stmt_list section offset", [&]() {
1097 error() <<
formatv(
"two compile unit DIEs, {0:x+8} and {1:x+8}, have "
1098 "the same DW_AT_stmt_list section offset:\n",
1108void DWARFVerifier::verifyDebugLineRows() {
1109 for (
const auto &CU : DCtx.compile_units()) {
1110 auto Die = CU->getUnitDIE();
1111 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1118 bool isDWARF5 = LineTable->Prologue.getVersion() >= 5;
1119 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
1120 uint32_t MinFileIndex = isDWARF5 ? 0 : 1;
1121 uint32_t FileIndex = MinFileIndex;
1122 StringMap<uint16_t> FullPathMap;
1123 for (
const auto &FileName : LineTable->Prologue.FileNames) {
1125 if (FileName.DirIdx > MaxDirIndex) {
1126 ++NumDebugLineErrors;
1127 ErrorCategory.Report(
1128 "Invalid index in .debug_line->prologue.file_names->dir_idx",
1130 error() <<
formatv(
".debug_line[{0:x+8}].prologue.file_names[{1}]"
1131 ".dir_idx contains an invalid index: {2}\n",
1133 FileIndex, FileName.DirIdx);
1138 std::string FullPath;
1139 const bool HasFullPath = LineTable->getFileNameByIndex(
1140 FileIndex, CU->getCompilationDir(),
1142 assert(HasFullPath &&
"Invalid index?");
1145 if (!Inserted && It->second != FileIndex && DumpOpts.Verbose) {
1146 warn() <<
formatv(
".debug_line[{0:x+8}].prologue.file_names[{1}] is a "
1147 "duplicate of file_names[{2}]\n",
1149 FileIndex, It->second);
1157 if (LineTable->Rows.size() == 1 && LineTable->Rows.front().EndSequence)
1161 uint64_t PrevAddress = 0;
1162 uint32_t RowIndex = 0;
1163 for (
const auto &Row : LineTable->Rows) {
1165 if (Row.Address.Address < PrevAddress) {
1166 ++NumDebugLineErrors;
1167 ErrorCategory.Report(
1168 "decreasing address between debug_line rows", [&]() {
1169 error() <<
formatv(
".debug_line[{0:x+8}] row[{1}] decreases in "
1170 "address from previous row:\n",
1176 LineTable->Rows[RowIndex - 1].dump(OS);
1182 if (!LineTable->hasFileAtIndex(Row.File)) {
1183 ++NumDebugLineErrors;
1184 ErrorCategory.Report(
"Invalid file index in debug_line", [&]() {
1185 error() <<
formatv(
".debug_line[{0:x+8}][{1}] has invalid file index "
1186 "{2} (valid values are [{3},{4}{5}):\n",
1188 RowIndex, Row.File, MinFileIndex,
1189 LineTable->Prologue.FileNames.size(),
1190 (isDWARF5 ?
")" :
"]"));
1196 if (Row.EndSequence)
1199 PrevAddress = Row.Address.Address;
1207 : OS(S), DCtx(
D), DumpOpts(
std::
move(DumpOpts)), IsObjectFile(
false),
1208 IsMachOObject(
false) {
1209 ErrorCategory.ShowDetail(this->DumpOpts.
Verbose ||
1210 !this->DumpOpts.ShowAggregateErrors);
1211 if (
const auto *
F = DCtx.getDWARFObj().getFile()) {
1212 IsObjectFile = F->isRelocatableObject();
1213 IsMachOObject = F->isMachO();
1218 NumDebugLineErrors = 0;
1219 OS <<
"Verifying .debug_line...\n";
1220 verifyDebugLineStmtOffsets();
1221 verifyDebugLineRows();
1222 return NumDebugLineErrors == 0;
1225void DWARFVerifier::verifyAppleAccelTable(
const DWARFSection *AccelSection,
1235 if (!AccelSectionData.isValidOffset(
AccelTable.getSizeHdr())) {
1236 ErrorCategory.
Report(
"Section is too small to fit a section header", [&]() {
1237 error() <<
"Section is too small to fit a section header.\n";
1243 if (
Error E = AccelTable.extract()) {
1244 std::string Msg =
toString(std::move(
E));
1245 ErrorCategory.Report(
"Section is too small to fit a section header",
1246 [&]() {
error() << Msg <<
'\n'; });
1251 uint32_t NumBuckets = AccelTable.getNumBuckets();
1252 uint32_t NumHashes = AccelTable.getNumHashes();
1254 uint64_t BucketsOffset =
1255 AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
1256 uint64_t HashesBase = BucketsOffset + NumBuckets * 4;
1257 uint64_t OffsetsBase = HashesBase + NumHashes * 4;
1258 for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
1259 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
1260 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
1261 ErrorCategory.Report(
"Invalid hash index", [&]() {
1262 error() <<
formatv(
"Bucket[{0}] has invalid hash index: {1}.\n",
1263 BucketIdx, HashIdx);
1267 uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
1268 if (NumAtoms == 0) {
1269 ErrorCategory.Report(
"No atoms", [&]() {
1270 error() <<
"No atoms: failed to read HashData.\n";
1274 if (!AccelTable.validateForms()) {
1275 ErrorCategory.Report(
"Unsupported form", [&]() {
1276 error() <<
"Unsupported form: failed to read HashData.\n";
1281 for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
1282 uint64_t HashOffset = HashesBase + 4 * HashIdx;
1283 uint64_t DataOffset = OffsetsBase + 4 * HashIdx;
1284 uint32_t Hash = AccelSectionData.getU32(&HashOffset);
1285 uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
1286 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
1287 sizeof(uint64_t))) {
1288 ErrorCategory.Report(
"Invalid HashData offset", [&]() {
1289 error() <<
formatv(
"Hash[{0}] has invalid HashData offset: {1:x+8}.\n",
1290 HashIdx, HashDataOffset);
1294 uint64_t StrpOffset;
1295 uint64_t StringOffset;
1296 uint32_t StringCount = 0;
1299 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
1300 const uint32_t NumHashDataObjects =
1301 AccelSectionData.getU32(&HashDataOffset);
1302 for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
1304 std::tie(
Offset,
Tag) = AccelTable.readAtoms(&HashDataOffset);
1305 auto Die = DCtx.getDIEForOffset(
Offset);
1307 const uint32_t BucketIdx =
1308 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
1309 StringOffset = StrpOffset;
1310 const char *
Name = StrData->
getCStr(&StringOffset);
1314 ErrorCategory.Report(
"Invalid DIE offset", [&]() {
1315 error() <<
formatv(
"{0} Bucket[{1}] Hash[{2}] = {3:x+8} "
1316 "Str[{4}] = {5:x+8} DIE[{6}] = {7:x+8} "
1317 "is not a valid DIE offset for \"{8}\".\n",
1318 SectionName, BucketIdx, HashIdx, Hash,
1319 StringCount, StrpOffset, HashDataIdx,
Offset,
1324 if ((
Tag != dwarf::DW_TAG_null) && (Die.
getTag() !=
Tag)) {
1325 ErrorCategory.Report(
"Mismatched Tag in accellerator table", [&]() {
1326 error() <<
formatv(
"Tag {0} in accelerator table does not match "
1327 "Tag {1} of DIE[{2}].\n",
1340 DenseMap<uint64_t, uint64_t> CUMap;
1341 CUMap.
reserve(DCtx.getNumCompileUnits());
1343 DenseSet<uint64_t> CUOffsets;
1344 for (
const auto &CU : DCtx.compile_units())
1345 CUOffsets.
insert(CU->getOffset());
1347 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
1349 ErrorCategory.Report(
"Name Index doesn't index any CU", [&]() {
1350 error() <<
formatv(
"Name Index @ {0:x} does not index any CU\n",
1355 for (uint32_t CU = 0, End = NI.
getCUCount(); CU < End; ++CU) {
1358 ErrorCategory.Report(
"Name Index references non-existing CU", [&]() {
1360 "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
1365 uint64_t DuplicateCUOffset = 0;
1367 std::lock_guard<std::mutex> Lock(AccessMutex);
1369 if (Iter != CUMap.
end())
1370 DuplicateCUOffset = Iter->second;
1374 if (DuplicateCUOffset) {
1375 ErrorCategory.Report(
"Duplicate Name Index", [&]() {
1377 "Name Index @ {0:x} references a CU @ {1:x}, but "
1378 "this CU is already indexed by Name Index @ {2:x}\n",
1386 for (
const auto &CU : DCtx.compile_units()) {
1387 if (CUMap.
count(CU->getOffset()) == 0)
1388 warn() <<
formatv(
"CU @ {0:x} not covered by any Name Index\n",
1399 constexpr BucketInfo(uint32_t Bucket, uint32_t
Index)
1405 warn() <<
formatv(
"Name Index @ {0:x} does not contain a hash table.\n",
1412 std::vector<BucketInfo> BucketStarts;
1414 const uint64_t OrigNumberOfErrors = ErrorCategory.GetNumErrors();
1415 for (uint32_t Bucket = 0, End = NI.
getBucketCount(); Bucket < End; ++Bucket) {
1418 ErrorCategory.Report(
"Name Index Bucket contains invalid value", [&]() {
1419 error() <<
formatv(
"Bucket {0} of Name Index @ {1:x} contains invalid "
1420 "value {2}. Valid range is [0, {3}].\n",
1427 BucketStarts.emplace_back(Bucket,
Index);
1433 if (OrigNumberOfErrors != ErrorCategory.GetNumErrors())
1446 uint32_t NextUncovered = 1;
1447 for (
const BucketInfo &
B : BucketStarts) {
1454 if (
B.Index > NextUncovered) {
1455 ErrorCategory.Report(
"Name table entries uncovered by hash table", [&]() {
1456 error() <<
formatv(
"Name Index @ {0:x}: Name table entries [{1}, {2}] "
1457 "are not covered by the hash table.\n",
1461 uint32_t Idx =
B.Index;
1474 ErrorCategory.Report(
"Name Index point to mismatched hash value", [&]() {
1476 "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
1477 "mismatched hash value {2:x} (belonging to bucket {3}).\n",
1493 ErrorCategory.Report(
1494 "String hash doesn't match Name Index hash", [&]() {
1496 "Name Index @ {0:x}: String ({1}) at index {2} "
1497 "hashes to {3:x}, but "
1498 "the Name Index hash is {4:x}\n",
1504 NextUncovered = std::max(NextUncovered, Idx);
1508void DWARFVerifier::verifyNameIndexAttribute(
1512 if (FormName.
empty()) {
1513 ErrorCategory.Report(
"Unknown NameIndex Abbreviation", [&]() {
1514 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1515 "unknown form: {3}.\n",
1522 if (AttrEnc.
Index == DW_IDX_type_hash) {
1523 if (AttrEnc.
Form != dwarf::DW_FORM_data8) {
1524 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1526 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
1527 "uses an unexpected form {2} (should be {3}).\n",
1535 if (AttrEnc.
Index == dwarf::DW_IDX_parent) {
1536 constexpr static auto AllowedForms = {dwarf::Form::DW_FORM_flag_present,
1537 dwarf::Form::DW_FORM_ref4};
1539 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1541 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_parent "
1542 "uses an unexpected form {2} (should be "
1543 "DW_FORM_ref4 or DW_FORM_flag_present).\n",
1554 struct FormClassTable {
1557 StringLiteral ClassName;
1559 static constexpr FormClassTable Table[] = {
1567 return T.Index == AttrEnc.
Index;
1570 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} contains an "
1571 "unknown index attribute: {2}.\n",
1576 if (!DWARFFormValue(AttrEnc.
Form).isFormClass(Iter->Class)) {
1577 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1578 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1579 "unexpected form {3} (expected form class {4}).\n",
1581 AttrEnc.
Form, Iter->ClassName);
1587void DWARFVerifier::verifyNameIndexAbbrevs(
1591 if (TagName.
empty()) {
1592 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} references an "
1593 "unknown tag: {2}.\n",
1597 for (
const auto &AttrEnc : Abbrev.Attributes) {
1599 ErrorCategory.Report(
1600 "NameIndex Abbreviateion contains multiple attributes", [&]() {
1602 "NameIndex @ {0:x}: Abbreviation {1:x} contains "
1603 "multiple {2} attributes.\n",
1608 verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
1612 !
Attributes.count(dwarf::DW_IDX_type_unit)) {
1613 ErrorCategory.Report(
"Abbreviation contains no attribute", [&]() {
1614 error() <<
formatv(
"NameIndex @ {0:x}: Indexing multiple compile units "
1615 "and abbreviation {1:x} has no DW_IDX_compile_unit "
1616 "or DW_IDX_type_unit attribute.\n",
1620 if (!
Attributes.count(dwarf::DW_IDX_die_offset)) {
1621 ErrorCategory.Report(
"Abbreviate in NameIndex missing attribute", [&]() {
1623 "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
1633 bool IncludeStrippedTemplateNames,
1634 bool IncludeObjCNames =
true,
1635 bool IncludeLinkageName =
true) {
1637 if (
const char *Str =
DIE.getShortName()) {
1639 Result.emplace_back(Name);
1640 if (IncludeStrippedTemplateNames) {
1641 if (std::optional<StringRef> StrippedName =
1645 Result.push_back(StrippedName->str());
1648 if (IncludeObjCNames) {
1649 if (std::optional<ObjCSelectorNames> ObjCNames =
1651 Result.emplace_back(ObjCNames->ClassName);
1652 Result.emplace_back(ObjCNames->Selector);
1653 if (ObjCNames->ClassNameNoCategory)
1654 Result.emplace_back(*ObjCNames->ClassNameNoCategory);
1655 if (ObjCNames->MethodNameNoCategory)
1656 Result.push_back(std::move(*ObjCNames->MethodNameNoCategory));
1659 }
else if (
DIE.
getTag() == dwarf::DW_TAG_namespace)
1660 Result.emplace_back(
"(anonymous namespace)");
1662 if (IncludeLinkageName) {
1663 if (
const char *Str =
DIE.getLinkageName())
1664 Result.emplace_back(Str);
1670void DWARFVerifier::verifyNameIndexEntries(
1676 ErrorCategory.Report(
"Unable to get string associated with name", [&]() {
1677 error() <<
formatv(
"Name Index @ {0:x}: Unable to get string associated "
1683 StringRef Str(CStr);
1686 uint64_t NextEntryID = EntryID;
1687 Expected<DWARFDebugNames::Entry> EntryOr = NI.
getEntry(&NextEntryID);
1688 for (; EntryOr; ++
NumEntries, EntryID = NextEntryID,
1689 EntryOr = NI.
getEntry(&NextEntryID)) {
1691 std::optional<uint64_t> CUIndex = EntryOr->getRelatedCUIndex();
1692 std::optional<uint64_t> TUIndex = EntryOr->getTUIndex();
1693 if (CUIndex && *CUIndex >= NI.
getCUCount()) {
1694 ErrorCategory.Report(
"Name Index entry contains invalid CU index", [&]() {
1695 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1696 "invalid CU index ({2}).\n",
1703 if (TUIndex && *TUIndex >= (NumLocalTUs + NumForeignTUs)) {
1704 ErrorCategory.Report(
"Name Index entry contains invalid TU index", [&]() {
1705 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1706 "invalid TU index ({2}).\n",
1711 std::optional<uint64_t> UnitOffset;
1714 if (*TUIndex >= NumLocalTUs) {
1727 ErrorCategory.Report(
1728 "Name Index entry contains foreign TU index with invalid CU "
1732 "Name Index @ {0:x}: Entry @ {1:x} contains an "
1733 "foreign TU index ({2}) with no CU index.\n",
1742 }
else if (CUIndex) {
1748 if (!UnitOffset || UnitOffset == UINT32_MAX)
1753 DWARFUnit *DU = DCtx.getUnitForOffset(*UnitOffset);
1754 if (DU ==
nullptr || DU->
getOffset() != *UnitOffset) {
1757 ErrorCategory.Report(
1758 "Name Index entry contains invalid CU or TU offset", [&]() {
1759 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1760 "invalid CU or TU offset {2:x}.\n",
1776 DWARFUnit *NonSkeletonUnit =
nullptr;
1779 NonSkeletonUnit = Iter->second;
1781 NonSkeletonUnit = DU;
1785 ErrorCategory.Report(
"Unable to get load .dwo file", [&]() {
1787 "Name Index @ {0:x}: Entry @ {1:x} unable to load "
1788 ".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
1796 if (TUIndex && *TUIndex >= NumLocalTUs) {
1804 const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs;
1806 llvm::DWARFContext &NonSkeletonDCtx = NonSkeletonUnit->
getContext();
1814 if (NonSkeletonDCtx.
isDWP()) {
1815 DWARFDie NonSkeletonUnitDie = NonSkeletonUnit->
getUnitDIE(
true);
1817 UnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1819 NonSkeletonUnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1820 if (DUDwoName != TUDwoName)
1824 uint64_t DIEOffset =
1825 NonSkeletonUnit->
getOffset() + *EntryOr->getDIEUnitOffset();
1829 if (DIEOffset >= NextUnitOffset) {
1830 ErrorCategory.Report(
"NameIndex relative DIE offset too large", [&]() {
1831 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1832 "DIE @ {2:x} when CU or TU ends at {3:x}.\n",
1840 ErrorCategory.Report(
"NameIndex references nonexistent DIE", [&]() {
1841 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1842 "non-existing DIE @ {2:x}.\n",
1853 ErrorCategory.Report(
"Name index contains mismatched CU of DIE", [&]() {
1855 "Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
1856 "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
1861 if (DIE.
getTag() != EntryOr->tag()) {
1862 ErrorCategory.Report(
"Name Index contains mismatched Tag of DIE", [&]() {
1864 "Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
1865 "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1873 auto IncludeStrippedTemplateNames =
1874 DIE.
getTag() == DW_TAG_subprogram ||
1875 DIE.
getTag() == DW_TAG_inlined_subroutine;
1876 auto EntryNames =
getNames(DIE, IncludeStrippedTemplateNames);
1878 ErrorCategory.Report(
"Name Index contains mismatched name of DIE", [&]() {
1879 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
1880 "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1882 make_range(EntryNames.begin(), EntryNames.end()));
1887 EntryOr.takeError(),
1888 [&](
const DWARFDebugNames::SentinelError &) {
1891 ErrorCategory.Report(
1892 "NameIndex Name is not associated with any entries", [&]() {
1893 error() << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
1894 "not associated with any entries.\n",
1895 NI.getUnitOffset(), NTE.getIndex(), Str);
1899 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
1900 error() <<
formatv(
"Name Index @ {0:x}: Name {1} ({2}): {3}\n",
1915 for (
const auto &Entry : *
Loc) {
1917 U->getAddressByteSize());
1919 U->getFormParams().Format);
1920 bool IsInteresting =
1922 return !
Op.isError() && (
Op.getCode() == DW_OP_addr ||
1923 Op.getCode() == DW_OP_form_tls_address ||
1924 Op.getCode() == DW_OP_GNU_push_tls_address);
1932void DWARFVerifier::verifyNameIndexCompleteness(
1941 if (Die.
find(DW_AT_declaration))
1951 auto IncludeLinkageName = Die.
getTag() == DW_TAG_subprogram ||
1952 Die.
getTag() == DW_TAG_inlined_subroutine;
1955 auto IncludeStrippedTemplateNames =
false;
1956 auto IncludeObjCNames =
false;
1957 auto EntryNames =
getNames(Die, IncludeStrippedTemplateNames,
1958 IncludeObjCNames, IncludeLinkageName);
1959 if (EntryNames.empty())
1969 case DW_TAG_compile_unit:
1975 case DW_TAG_formal_parameter:
1976 case DW_TAG_template_value_parameter:
1977 case DW_TAG_template_type_parameter:
1978 case DW_TAG_GNU_template_parameter_pack:
1979 case DW_TAG_GNU_template_template_param:
1989 case DW_TAG_enumerator:
1994 case DW_TAG_imported_declaration:
2000 case DW_TAG_subprogram:
2001 case DW_TAG_inlined_subroutine:
2004 {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
2013 case DW_TAG_variable:
2025 for (StringRef Name : EntryNames) {
2026 auto iter = NamesToDieOffsets.find(Name);
2027 if (iter == NamesToDieOffsets.end() || !iter->second.count(DieUnitOffset)) {
2028 ErrorCategory.Report(
2029 "Name Index DIE entry missing name",
2032 "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
2033 "name {3} missing.\n",
2034 NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name);
2046 CUTU->getBaseAddress();
2049 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2050 DCtx.getRecoverableErrorHandler()(std::move(E));
2056 if (!
CU->getDWOId())
2059 CU->getNonSkeletonUnitDIE().getDwarfUnit()->getContext();
2061 for (
auto &CUTU : NonSkeletonContext.
dwo_units()) {
2063 CUTU->getBaseAddress();
2066 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2067 DCtx.getRecoverableErrorHandler()(std::move(E));
2070 if (NonSkeletonContext.
isDWP())
2075void DWARFVerifier::verifyDebugNames(
const DWARFSection &AccelSection,
2077 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,
2078 DCtx.isLittleEndian(), 0);
2079 DWARFDebugNames AccelTable(AccelSectionData, StrData);
2081 OS <<
"Verifying .debug_names...\n";
2086 std::string Msg =
toString(std::move(
E));
2087 ErrorCategory.Report(
"Accelerator Table Error",
2088 [&]() {
error() << Msg <<
'\n'; });
2091 const uint64_t OriginalNumErrors = ErrorCategory.GetNumErrors();
2092 verifyDebugNamesCULists(AccelTable);
2093 for (
const auto &NI : AccelTable)
2094 verifyNameIndexBuckets(NI, StrData);
2095 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
2096 verifyNameIndexAbbrevs(NI);
2100 if (OriginalNumErrors != ErrorCategory.GetNumErrors())
2102 DenseMap<uint64_t, DWARFUnit *> CUOffsetsToDUMap;
2103 for (
const auto &CU : DCtx.compile_units()) {
2104 if (!(CU->getVersion() >= 5 && CU->getDWOId()))
2106 CUOffsetsToDUMap[CU->getOffset()] =
2107 CU->getNonSkeletonUnitDIE().getDwarfUnit();
2110 for (
const DWARFDebugNames::NameIndex &NI : AccelTable) {
2112 verifyNameIndexEntries(NI, NTE, CUOffsetsToDUMap);
2116 auto populateNameToOffset =
2117 [&](
const DWARFDebugNames::NameIndex &NI,
2118 StringMap<DenseSet<uint64_t>> &NamesToDieOffsets) {
2119 for (
const DWARFDebugNames::NameTableEntry &NTE : NI) {
2121 const std::string
Name = tName ? std::string(tName) :
"";
2123 Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&EntryID);
2124 auto Iter = NamesToDieOffsets.insert({
Name, DenseSet<uint64_t>(3)});
2125 for (; EntryOr; EntryOr = NI.getEntry(&EntryID)) {
2126 if (std::optional<uint64_t> DieOffset = EntryOr->getDIEUnitOffset())
2127 Iter.first->second.insert(*DieOffset);
2131 [&](
const DWARFDebugNames::SentinelError &) {
2132 if (!NamesToDieOffsets.empty())
2134 ErrorCategory.Report(
2135 "NameIndex Name is not associated with any entries", [&]() {
2137 << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
2138 "not associated with any entries.\n",
2139 NI.getUnitOffset(), NTE.getIndex(), Name);
2142 [&](
const ErrorInfoBase &
Info) {
2143 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
2145 "Name Index @ {0:x}: Name {1} ({2}): {3}\n",
2146 NI.getUnitOffset(), NTE.
getIndex(), Name,
Info.message());
2155 populateNameToOffset(NI, NamesToDieOffsets);
2156 for (uint32_t i = 0, iEnd = NI.getCUCount(); i < iEnd; ++i) {
2157 const uint64_t CUOffset = NI.getCUOffset(i);
2158 DWARFUnit *
U = DCtx.getUnitForOffset(CUOffset);
2165 if (CUDie != NonSkeletonUnitDie) {
2169 verifyNameIndexCompleteness(
2170 DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), NI,
2176 verifyNameIndexCompleteness(DWARFDie(CU, &Die), NI,
2187 DataExtractor StrData(
D.getStrSection(), DCtx.isLittleEndian(), 0);
2188 if (!
D.getAppleNamesSection().Data.empty())
2189 verifyAppleAccelTable(&
D.getAppleNamesSection(), &StrData,
".apple_names");
2190 if (!
D.getAppleTypesSection().Data.empty())
2191 verifyAppleAccelTable(&
D.getAppleTypesSection(), &StrData,
".apple_types");
2192 if (!
D.getAppleNamespacesSection().Data.empty())
2193 verifyAppleAccelTable(&
D.getAppleNamespacesSection(), &StrData,
2194 ".apple_namespaces");
2195 if (!
D.getAppleObjCSection().Data.empty())
2196 verifyAppleAccelTable(&
D.getAppleObjCSection(), &StrData,
".apple_objc");
2198 if (!
D.getNamesSection().Data.empty())
2199 verifyDebugNames(
D.getNamesSection(), StrData);
2200 return ErrorCategory.GetNumErrors() == 0;
2204 OS <<
"Verifying .debug_str_offsets...\n";
2213 std::optional<DwarfFormat> DwoLegacyDwarf4Format;
2215 if (DwoLegacyDwarf4Format)
2221 DwoLegacyDwarf4Format = InfoFormat;
2225 DwoLegacyDwarf4Format,
".debug_str_offsets.dwo",
2228 std::nullopt,
".debug_str_offsets",
2242 while (
C.seek(NextUnit),
C.tell() < DA.getData().size()) {
2248 Length = DA.getData().size();
2254 if (
C.tell() +
Length > DA.getData().size()) {
2255 ErrorCategory.Report(
2256 "Section contribution length exceeds available space", [&]() {
2258 "{0}: contribution {1:X}: length exceeds available space "
2260 "offset ({1:X}) + length field space ({2:X}) + length "
2262 "{4:X} > section size {5:X})\n",
2264 C.tell() +
Length, DA.getData().size());
2273 ErrorCategory.Report(
"Invalid Section version", [&]() {
2274 error() <<
formatv(
"{0}: contribution {1:X}: invalid version {2}\n",
2285 DA.setAddressSize(OffsetByteSize);
2287 if (Remainder != 0) {
2288 ErrorCategory.Report(
"Invalid section contribution length", [&]() {
2290 "{0}: contribution {1:X}: invalid length ((length ({2:X}) "
2291 "- header (0x4)) % offset size {3:X} == {4:X} != 0)\n",
2303 if (StrData.
size() <= StrOff) {
2304 ErrorCategory.Report(
2305 "String offset out of bounds of string section", [&]() {
2307 "{0}: contribution {1:X}: index {2:X}: invalid string "
2308 "offset *{3:X} == {4:X}, is beyond the bounds of the string "
2309 "section of length {5:X}\n",
2315 if (StrData[StrOff - 1] ==
'\0')
2317 ErrorCategory.Report(
2318 "Section contribution contains invalid string offset", [&]() {
2320 "{0}: contribution {1:X}: index {2:X}: invalid string "
2321 "offset *{3:X} == {4:X}, is neither zero nor "
2322 "immediately following a null character\n",
2329 if (
Error E =
C.takeError()) {
2330 std::string Msg =
toString(std::move(E));
2331 ErrorCategory.Report(
"String offset error", [&]() {
2340 StringRef s, std::function<
void(
void)> detailCallback) {
2341 this->
Report(s,
"", detailCallback);
2346 std::function<
void(
void)> detailCallback) {
2347 std::lock_guard<std::mutex> Lock(WriteMutex);
2349 std::string category_str = std::string(category);
2352 if (!sub_category.
empty()) {
2360 std::function<
void(
StringRef,
unsigned)> handleCounts) {
2361 for (
const auto &[
name, aggData] : Aggregation) {
2362 handleCounts(
name, aggData.OverallCount);
2367 const auto Agg = Aggregation.find(category);
2368 if (Agg != Aggregation.end()) {
2370 handleCounts(
name, aggData);
2376 if (DumpOpts.ShowAggregateErrors && ErrorCategory.GetNumCategories()) {
2377 error() <<
"Aggregated error counts:\n";
2378 ErrorCategory.EnumerateResults([&](
StringRef s,
unsigned count) {
2382 if (!DumpOpts.JsonErrSummaryFile.empty()) {
2388 "unable to open json summary file {0} for writing: {1}\n",
2389 DumpOpts.JsonErrSummaryFile, EC.message());
2395 ErrorCategory.EnumerateResults([&](
StringRef Category,
unsigned Count) {
2399 ErrorCategory.EnumerateDetailedResultsFor(
2400 Category, [&](
StringRef SubCategory,
unsigned SubCount) {
2405 ErrorCount +=
Count;
2408 RootNode.
try_emplace(
"error-categories", std::move(Categories));
2422 Die.
dump(OS, indent, DumpOpts);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ArrayRef< TableEntry > TableRef
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.
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,...
iterator find(const_arg_type_t< KeyT > Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
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 EnumerateResults(std::function< void(StringRef, unsigned)> handleCounts)
LLVM_ABI void EnumerateDetailedResultsFor(StringRef category, std::function< void(StringRef, unsigned)> handleCounts)
LLVM_ABI void Report(StringRef category, std::function< void()> detailCallback)
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.
StringRef - Represent a constant reference to a string, i.e.
constexpr bool empty() const
empty - Check if the string is empty.
constexpr size_t size() const
size - 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 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)
@ C
The default llvm calling convention, compatible with C.
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)
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)
FunctionAddr VTableAddr uintptr_t uintptr_t Version
FunctionAddr VTableAddr Count
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.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
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)
void consumeError(Error Err)
Consume a Error without doing anything.
StringRef toStringRef(bool B)
Construct a string ref from a boolean.
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.
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.