51std::optional<DWARFAddressRange>
53 auto Begin =
Ranges.begin();
55 auto Pos = std::lower_bound(Begin, End, R);
58 if (Pos != End && *Pos == R) {
86 if (Iter->intersects(RI))
96 auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();
102 bool Covered = I1->LowPC <= R.LowPC;
103 if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) {
111 if (R.LowPC < I1->HighPC)
112 R.LowPC = I1->HighPC;
120 auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();
121 while (I1 != E1 && I2 != E2) {
122 if (I1->intersects(*I2)) {
127 if (I1->LowPC < I2->LowPC)
143 bool ValidLength =
false;
144 bool ValidVersion =
false;
145 bool ValidAddrSize =
false;
146 bool ValidType =
true;
147 bool ValidAbbrevOffset =
true;
168 if (!AbbrevSetOrErr) {
169 ValidAbbrevOffset =
false;
179 if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
182 bool HeaderShown =
false;
183 auto ShowHeaderOnce = [&]() {
185 error() <<
format(
"Units[%d] - start offset: 0x%08" PRIx64
" \n",
186 UnitIndex, OffsetStart);
191 ErrorCategory.Report(
192 "Unit Header Length: Unit too large for .debug_info provided", [&]() {
194 note() <<
"The length for this unit is too "
195 "large for the .debug_info provided.\n";
198 ErrorCategory.Report(
199 "Unit Header Length: 16 bit unit header version is not valid", [&]() {
201 note() <<
"The 16 bit unit header version is not valid.\n";
204 ErrorCategory.Report(
205 "Unit Header Length: Unit type encoding is not valid", [&]() {
207 note() <<
"The unit type encoding is not valid.\n";
209 if (!ValidAbbrevOffset)
210 ErrorCategory.Report(
211 "Unit Header Length: Offset into the .debug_abbrev section is not "
215 note() <<
"The offset into the .debug_abbrev section is "
219 ErrorCategory.Report(
"Unit Header Length: Address size is unsupported",
222 note() <<
"The address size is unsupported.\n";
225 *
Offset = OffsetStart +
Length + (isUnitDWARF64 ? 12 : 4);
229bool DWARFVerifier::verifyName(
const DWARFDie &Die) {
233 std::string ReconstructedName;
234 raw_string_ostream OS(ReconstructedName);
235 std::string OriginalFullName;
238 if (OriginalFullName.empty() || OriginalFullName == ReconstructedName)
241 ErrorCategory.Report(
242 "Simplified template DW_AT_name could not be reconstituted", [&]() {
244 <<
"Simplified template DW_AT_name could not be reconstituted:\n"
246 " reconstituted: {1}\n",
247 OriginalFullName, ReconstructedName);
254unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit,
255 ReferenceMap &UnitLocalReferences,
256 ReferenceMap &CrossUnitReferences) {
257 unsigned NumUnitErrors = 0;
258 unsigned NumDies =
Unit.getNumDIEs();
259 for (
unsigned I = 0;
I < NumDies; ++
I) {
260 auto Die =
Unit.getDIEAtIndex(
I);
262 if (Die.
getTag() == DW_TAG_null)
266 NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
267 NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences,
268 CrossUnitReferences);
271 NumUnitErrors += verifyName(Die);
277 <<
" has DW_CHILDREN_yes but DIE has no children: ";
282 NumUnitErrors += verifyDebugInfoCallSite(Die);
285 DWARFDie Die =
Unit.getUnitDIE(
false);
287 ErrorCategory.Report(
"Compilation unit missing DIE", [&]() {
288 error() <<
"Compilation unit without DIE.\n";
291 return NumUnitErrors;
295 ErrorCategory.Report(
"Compilation unit root DIE is not a unit DIE", [&]() {
296 error() <<
"Compilation unit root DIE is not a unit DIE: "
304 ErrorCategory.Report(
"Mismatched unit type", [&]() {
307 <<
") do not match.\n";
316 ErrorCategory.Report(
"Skeleton CU has children", [&]() {
317 error() <<
"Skeleton compilation unit has children.\n";
323 NumUnitErrors += verifyDieRanges(Die, RI);
325 return NumUnitErrors;
328unsigned DWARFVerifier::verifyDebugInfoCallSite(
const DWARFDie &Die) {
329 if (Die.
getTag() != DW_TAG_call_site && Die.
getTag() != DW_TAG_GNU_call_site)
334 if (Curr.
getTag() == DW_TAG_inlined_subroutine) {
335 ErrorCategory.Report(
336 "Call site nested entry within inlined subroutine", [&]() {
337 error() <<
"Call site entry nested within inlined subroutine:";
345 ErrorCategory.Report(
346 "Call site entry not nested within valid subprogram", [&]() {
347 error() <<
"Call site entry not nested within a valid subprogram:";
353 std::optional<DWARFFormValue> CallAttr = Curr.
find(
354 {DW_AT_call_all_calls, DW_AT_call_all_source_calls,
355 DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,
356 DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites});
358 ErrorCategory.Report(
359 "Subprogram with call site entry has no DW_AT_call attribute", [&]() {
361 <<
"Subprogram with call site entry has no DW_AT_call attribute:";
371unsigned DWARFVerifier::verifyAbbrevSection(
const DWARFDebugAbbrev *Abbrev) {
375 Expected<const DWARFAbbreviationDeclarationSet *> AbbrDeclsOrErr =
377 if (!AbbrDeclsOrErr) {
379 ErrorCategory.Report(
"Abbreviation Declaration error",
380 [&]() {
error() << ErrMsg <<
"\n"; });
384 const auto *AbbrDecls = *AbbrDeclsOrErr;
385 unsigned NumErrors = 0;
386 for (
auto AbbrDecl : *AbbrDecls) {
387 SmallDenseSet<uint16_t> AttributeSet;
388 for (
auto Attribute : AbbrDecl.attributes()) {
391 ErrorCategory.Report(
392 "Abbreviation declartion contains multiple attributes", [&]() {
393 error() <<
"Abbreviation declaration contains multiple "
405 OS <<
"Verifying .debug_abbrev...\n";
408 unsigned NumErrors = 0;
410 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
412 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
414 return NumErrors == 0;
418 unsigned NumDebugInfoErrors = 0;
419 ReferenceMap CrossUnitReferences;
422 for (
const auto &Unit : Units) {
423 OS <<
"Verifying unit: " <<
Index <<
" / " << Units.getNumUnits();
424 if (
const char* Name = Unit->getUnitDIE(
true).getShortName())
425 OS <<
", \"" << Name <<
'\"';
428 ReferenceMap UnitLocalReferences;
429 NumDebugInfoErrors +=
430 verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences);
431 NumDebugInfoErrors += verifyDebugInfoReferences(
432 UnitLocalReferences, [&](
uint64_t Offset) {
return Unit.get(); });
436 NumDebugInfoErrors += verifyDebugInfoReferences(
437 CrossUnitReferences, [&](uint64_t
Offset) -> DWARFUnit * {
438 if (DWARFUnit *U = Units.getUnitForOffset(
Offset))
443 return NumDebugInfoErrors;
446unsigned DWARFVerifier::verifyUnitSection(
const DWARFSection &S) {
447 const DWARFObject &DObj = DCtx.getDWARFObj();
448 DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);
449 unsigned NumDebugInfoErrors = 0;
450 uint64_t
Offset = 0, UnitIdx = 0;
452 bool isUnitDWARF64 =
false;
453 bool isHeaderChainValid =
true;
455 DWARFUnitVector TypeUnitVector;
456 DWARFUnitVector CompileUnitVector;
460 isHeaderChainValid =
false;
467 if (UnitIdx == 0 && !hasDIE) {
468 warn() <<
"Section is empty.\n";
469 isHeaderChainValid =
true;
471 if (!isHeaderChainValid)
472 ++NumDebugInfoErrors;
473 return NumDebugInfoErrors;
476unsigned DWARFVerifier::verifyIndex(StringRef Name,
478 StringRef IndexStr) {
479 if (IndexStr.
empty())
481 OS <<
"Verifying " <<
Name <<
"...\n";
482 DWARFUnitIndex
Index(InfoColumnKind);
483 DataExtractor
D(IndexStr, DCtx.isLittleEndian(), 0);
486 using MapType = IntervalMap<uint64_t, uint64_t>;
487 MapType::Allocator
Alloc;
488 std::vector<std::unique_ptr<MapType>> Sections(
Index.getColumnKinds().size());
489 for (
const DWARFUnitIndex::Entry &
E :
Index.getRows()) {
490 uint64_t Sig =
E.getSignature();
491 if (!
E.getContributions())
494 InfoColumnKind == DW_SECT_INFO
497 const DWARFUnitIndex::Entry::SectionContribution &SC =
E.value();
502 Sections[Col] = std::make_unique<MapType>(
Alloc);
503 auto &
M = *Sections[Col];
506 StringRef Category = InfoColumnKind == DWARFSectionKind::DW_SECT_INFO
507 ?
"Overlapping CU index entries"
508 :
"Overlapping TU index entries";
509 ErrorCategory.Report(Category, [&]() {
511 "overlapping index entries for entries {0:x16} "
512 "and {1:x16} for column {2}\n",
525 return verifyIndex(
".debug_cu_index", DWARFSectionKind::DW_SECT_INFO,
526 DCtx.getDWARFObj().getCUIndexSection()) == 0;
531 DCtx.getDWARFObj().getTUIndexSection()) == 0;
536 unsigned NumErrors = 0;
538 OS <<
"Verifying .debug_info Unit Header Chain...\n";
540 NumErrors += verifyUnitSection(S);
543 OS <<
"Verifying .debug_types Unit Header Chain...\n";
545 NumErrors += verifyUnitSection(S);
548 OS <<
"Verifying non-dwo Units...\n";
549 NumErrors += verifyUnits(DCtx.getNormalUnitsVector());
551 OS <<
"Verifying dwo Units...\n";
552 NumErrors += verifyUnits(DCtx.getDWOUnitsVector());
553 return NumErrors == 0;
556unsigned DWARFVerifier::verifyDieRanges(
const DWARFDie &Die,
557 DieRangeInfo &ParentRI) {
558 unsigned NumErrors = 0;
566 if (!RangesOrError) {
568 if (!Unit->isDWOUnit())
577 DieRangeInfo RI(Die);
598 if (!IsObjectFile || IsMachOObject || Die.
getTag() != DW_TAG_compile_unit) {
599 bool DumpDieAfterError =
false;
600 for (
const auto &
Range : Ranges) {
601 if (!
Range.valid()) {
603 ErrorCategory.
Report(
"Invalid address range", [&]() {
604 error() <<
"Invalid address range " <<
Range <<
"\n";
605 DumpDieAfterError =
true;
616 if (
auto PrevRange = RI.insert(
Range)) {
618 ErrorCategory.Report(
"DIE has overlapping DW_AT_ranges", [&]() {
619 error() <<
"DIE has overlapping ranges in DW_AT_ranges attribute: "
620 << *PrevRange <<
" and " <<
Range <<
'\n';
621 DumpDieAfterError =
true;
625 if (DumpDieAfterError)
626 dump(Die, 2) <<
'\n';
630 const auto IntersectingChild = ParentRI.insert(RI);
631 if (IntersectingChild != ParentRI.Children.end()) {
633 ErrorCategory.Report(
"DIEs have overlapping address ranges", [&]() {
634 error() <<
"DIEs have overlapping address ranges:";
636 dump(IntersectingChild->Die) <<
'\n';
641 bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() &&
642 !(Die.
getTag() == DW_TAG_subprogram &&
643 ParentRI.Die.getTag() == DW_TAG_subprogram);
644 if (ShouldBeContained && !ParentRI.contains(RI)) {
646 ErrorCategory.Report(
647 "DIE address ranges are not contained by parent ranges", [&]() {
649 <<
"DIE address ranges are not contained in its parent's ranges:";
651 dump(Die, 2) <<
'\n';
656 for (DWARFDie Child : Die)
657 NumErrors += verifyDieRanges(Child, RI);
662bool DWARFVerifier::verifyExpressionOp(
const DWARFExpression::Operation &
Op,
664 for (
unsigned Operand = 0; Operand <
Op.Desc.
Op.
size(); ++Operand) {
665 unsigned Size =
Op.Desc.
Op[Operand];
672 if (
Op.Opcode == DW_OP_convert &&
Op.Operands[Operand] == 0)
674 auto Die =
U->getDIEForOffset(
U->getOffset() +
Op.Operands[Operand]);
675 if (!Die || Die.
getTag() != dwarf::DW_TAG_base_type)
683bool DWARFVerifier::verifyExpression(
const DWARFExpression &
E, DWARFUnit *U) {
685 if (!verifyExpressionOp(
Op, U))
691unsigned DWARFVerifier::verifyDebugInfoAttribute(
const DWARFDie &Die,
692 DWARFAttribute &AttrValue) {
693 unsigned NumErrors = 0;
694 auto ReportError = [&](StringRef category,
const Twine &TitleMsg) {
696 ErrorCategory.Report(category, [&]() {
697 error() << TitleMsg <<
'\n';
702 const DWARFObject &DObj = DCtx.getDWARFObj();
704 const auto Attr = AttrValue.
Attr;
709 unsigned DwarfVersion =
U->getVersion();
710 const DWARFSection &RangeSection = DwarfVersion < 5
713 if (
U->isDWOUnit() && RangeSection.
Data.
empty())
715 if (*SectionOffset >= RangeSection.
Data.
size())
716 ReportError(
"DW_AT_ranges offset out of bounds",
717 "DW_AT_ranges offset is beyond " +
718 StringRef(DwarfVersion < 5 ?
".debug_ranges"
719 :
".debug_rnglists") +
723 ReportError(
"Invalid DW_AT_ranges encoding",
724 "DIE has invalid DW_AT_ranges encoding:");
726 case DW_AT_stmt_list:
729 if (*SectionOffset >=
U->getLineSection().Data.size())
730 ReportError(
"DW_AT_stmt_list offset out of bounds",
731 "DW_AT_stmt_list offset is beyond .debug_line bounds: " +
735 ReportError(
"Invalid DW_AT_stmt_list encoding",
736 "DIE has invalid DW_AT_stmt_list encoding:");
738 case DW_AT_location: {
749 if (Expected<std::vector<DWARFLocationExpression>> Loc =
751 for (
const auto &Entry : *Loc) {
753 DWARFExpression Expression(
Data,
U->getAddressByteSize(),
754 U->getFormParams().Format);
756 any_of(Expression, [](
const DWARFExpression::Operation &
Op) {
759 if (
Error || !verifyExpression(Expression, U))
760 ReportError(
"Invalid DWARF expressions",
761 "DIE contains invalid DWARF expression:");
764 Loc.takeError(), [&](std::unique_ptr<ResolverError>
E) {
765 return U->isDWOUnit() ? Error::success()
766 : Error(std::move(E));
768 ReportError(
"Invalid DW_AT_location",
toString(std::move(Err)));
771 case DW_AT_specification:
772 case DW_AT_abstract_origin: {
774 auto DieTag = Die.
getTag();
775 auto RefTag = ReferencedDie.getTag();
776 if (DieTag == RefTag)
778 if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
780 if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
783 if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)
785 ReportError(
"Incompatible DW_AT_abstract_origin tag reference",
786 "DIE with tag " +
TagString(DieTag) +
" has " +
788 " that points to DIE with "
789 "incompatible tag " +
797 ReportError(
"Incompatible DW_AT_type attribute tag",
803 case DW_AT_call_file:
804 case DW_AT_decl_file: {
806 if (
U->isDWOUnit() && !
U->isTypeUnit())
808 const auto *
LT =
U->getContext().getLineTableForUnit(U);
810 if (!
LT->hasFileAtIndex(*FileIdx)) {
811 bool IsZeroIndexed =
LT->Prologue.getVersion() >= 5;
812 if (std::optional<uint64_t> LastFileIdx =
813 LT->getLastValidFileIndex()) {
814 ReportError(
"Invalid file index in DW_AT_decl_file",
816 " with an invalid file index " +
818 " (valid values are [" +
819 (IsZeroIndexed ?
"0-" :
"1-") +
822 ReportError(
"Invalid file index in DW_AT_decl_file",
824 " with an invalid file index " +
826 " (the file table in the prologue is empty)");
831 "File index in DW_AT_decl_file reference CU with no line table",
833 " that references a file with index " +
835 " and the compile unit has no line table");
838 ReportError(
"Invalid encoding in DW_AT_decl_file",
840 " with invalid encoding");
844 case DW_AT_call_line:
845 case DW_AT_decl_line: {
848 Attr == DW_AT_call_line ?
"Invalid file index in DW_AT_decl_line"
849 :
"Invalid file index in DW_AT_call_line",
854 case DW_AT_LLVM_stmt_sequence: {
858 if (!SectionOffset) {
859 ReportError(
"Invalid DW_AT_LLVM_stmt_sequence encoding",
860 "DIE has invalid DW_AT_LLVM_stmt_sequence encoding");
863 if (*SectionOffset >=
U->getLineSection().Data.size()) {
865 "DW_AT_LLVM_stmt_sequence offset out of bounds",
866 "DW_AT_LLVM_stmt_sequence offset is beyond .debug_line bounds: " +
872 const auto *LineTable = DCtx.getLineTableForUnit(U);
874 ReportError(
"DW_AT_LLVM_stmt_sequence without line table",
875 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
881 DWARFDie CUDie =
U->getUnitDIE();
883 if (!StmtListOffset) {
884 ReportError(
"DW_AT_LLVM_stmt_sequence without DW_AT_stmt_list",
885 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
890 const int8_t DwarfOffset =
891 LineTable->Prologue.getFormParams().getDwarfOffsetByteSize();
893 uint64_t LineTableStart = *StmtListOffset;
894 uint64_t PrologueLength = LineTable->Prologue.PrologueLength;
895 uint64_t TotalLength = LineTable->Prologue.TotalLength;
896 uint64_t LineTableEnd = LineTableStart + TotalLength + DwarfOffset;
901 uint64_t InitialLengthSize = DwarfOffset;
903 uint64_t VersionSize = 2;
904 uint64_t PrologueLengthSize = DwarfOffset;
905 uint64_t SequencesStart = LineTableStart + InitialLengthSize + VersionSize +
906 PrologueLengthSize + PrologueLength;
909 if (*SectionOffset < SequencesStart || *SectionOffset >= LineTableEnd) {
910 ReportError(
"DW_AT_LLVM_stmt_sequence offset out of line table bounds",
911 "DW_AT_LLVM_stmt_sequence offset " +
913 " is not within the line table bounds [" +
921 std::find_if(LineTable->Sequences.begin(), LineTable->Sequences.end(),
922 [SectionOffset](
const auto &Sequence) {
923 return Sequence.StmtSeqOffset == *SectionOffset;
926 if (It == LineTable->Sequences.end())
928 "Invalid DW_AT_LLVM_stmt_sequence offset",
929 "DW_AT_LLVM_stmt_sequence offset " +
931 " does not point to a valid sequence offset in the line table");
940unsigned DWARFVerifier::verifyDebugInfoForm(
const DWARFDie &Die,
941 DWARFAttribute &AttrValue,
942 ReferenceMap &LocalReferences,
943 ReferenceMap &CrossUnitReferences) {
945 unsigned NumErrors = 0;
952 case DW_FORM_ref_udata: {
957 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
959 if (CUOffset >= CUSize) {
961 ErrorCategory.Report(
"Invalid CU offset", [&]() {
963 <<
format(
"0x%08" PRIx64, CUOffset)
964 <<
" is invalid (must be less than CU size of "
965 <<
format(
"0x%08" PRIx64, CUSize) <<
"):\n";
966 Die.
dump(OS, 0, DumpOpts);
978 case DW_FORM_ref_addr: {
984 if (*RefVal >= DieCU->getInfoSection().Data.size()) {
986 ErrorCategory.Report(
"DW_FORM_ref_addr offset out of bounds", [&]() {
987 error() <<
"DW_FORM_ref_addr offset beyond .debug_info "
994 CrossUnitReferences[*RefVal].insert(Die.
getOffset());
1005 case DW_FORM_line_strp: {
1008 std::string ErrMsg =
toString(std::move(
E));
1009 ErrorCategory.Report(
"Invalid DW_FORM attribute", [&]() {
1010 error() << ErrMsg <<
":\n";
1022unsigned DWARFVerifier::verifyDebugInfoReferences(
1023 const ReferenceMap &References,
1024 llvm::function_ref<DWARFUnit *(uint64_t)> GetUnitForOffset) {
1025 auto GetDIEForOffset = [&](uint64_t
Offset) {
1026 if (DWARFUnit *U = GetUnitForOffset(
Offset))
1027 return U->getDIEForOffset(
Offset);
1030 unsigned NumErrors = 0;
1031 for (
const std::pair<
const uint64_t, std::set<uint64_t>> &Pair :
1033 if (GetDIEForOffset(Pair.first))
1036 ErrorCategory.Report(
"Invalid DIE reference", [&]() {
1037 error() <<
"invalid DIE reference " <<
format(
"0x%08" PRIx64, Pair.first)
1038 <<
". Offset is in between DIEs:\n";
1039 for (
auto Offset : Pair.second)
1047void DWARFVerifier::verifyDebugLineStmtOffsets() {
1048 std::map<uint64_t, DWARFDie> StmtListToDie;
1049 for (
const auto &CU : DCtx.compile_units()) {
1050 auto Die = CU->getUnitDIE();
1055 if (!StmtSectionOffset)
1057 const uint64_t LineTableOffset = *StmtSectionOffset;
1058 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1059 if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
1061 ++NumDebugLineErrors;
1062 ErrorCategory.Report(
"Unparsable .debug_line entry", [&]() {
1063 error() <<
".debug_line[" <<
format(
"0x%08" PRIx64, LineTableOffset)
1064 <<
"] was not able to be parsed for CU:\n";
1071 assert(LineTable ==
nullptr);
1076 auto [Iter,
Inserted] = StmtListToDie.try_emplace(LineTableOffset, Die);
1078 ++NumDebugLineErrors;
1079 const auto &OldDie = Iter->second;
1080 ErrorCategory.Report(
"Identical DW_AT_stmt_list section offset", [&]() {
1081 error() <<
"two compile unit DIEs, "
1082 <<
format(
"0x%08" PRIx64, OldDie.getOffset()) <<
" and "
1084 <<
", have the same DW_AT_stmt_list section offset:\n";
1093void DWARFVerifier::verifyDebugLineRows() {
1094 for (
const auto &CU : DCtx.compile_units()) {
1095 auto Die = CU->getUnitDIE();
1096 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1103 bool isDWARF5 = LineTable->Prologue.getVersion() >= 5;
1104 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
1105 uint32_t MinFileIndex = isDWARF5 ? 0 : 1;
1106 uint32_t FileIndex = MinFileIndex;
1107 StringMap<uint16_t> FullPathMap;
1108 for (
const auto &FileName : LineTable->Prologue.FileNames) {
1110 if (FileName.DirIdx > MaxDirIndex) {
1111 ++NumDebugLineErrors;
1112 ErrorCategory.Report(
1113 "Invalid index in .debug_line->prologue.file_names->dir_idx",
1115 error() <<
".debug_line["
1116 <<
format(
"0x%08" PRIx64,
1118 <<
"].prologue.file_names[" << FileIndex
1119 <<
"].dir_idx contains an invalid index: "
1120 << FileName.DirIdx <<
"\n";
1125 std::string FullPath;
1126 const bool HasFullPath = LineTable->getFileNameByIndex(
1127 FileIndex, CU->getCompilationDir(),
1129 assert(HasFullPath &&
"Invalid index?");
1132 if (!Inserted && It->second != FileIndex && DumpOpts.Verbose) {
1133 warn() <<
".debug_line["
1134 <<
format(
"0x%08" PRIx64,
1136 <<
"].prologue.file_names[" << FileIndex
1137 <<
"] is a duplicate of file_names[" << It->second <<
"]\n";
1145 if (LineTable->Rows.size() == 1 && LineTable->Rows.front().EndSequence)
1149 uint64_t PrevAddress = 0;
1150 uint32_t RowIndex = 0;
1151 for (
const auto &Row : LineTable->Rows) {
1153 if (Row.Address.Address < PrevAddress) {
1154 ++NumDebugLineErrors;
1155 ErrorCategory.Report(
1156 "decreasing address between debug_line rows", [&]() {
1157 error() <<
".debug_line["
1158 <<
format(
"0x%08" PRIx64,
1160 <<
"] row[" << RowIndex
1161 <<
"] decreases in address from previous row:\n";
1165 LineTable->Rows[RowIndex - 1].dump(OS);
1171 if (!LineTable->hasFileAtIndex(Row.File)) {
1172 ++NumDebugLineErrors;
1173 ErrorCategory.Report(
"Invalid file index in debug_line", [&]() {
1174 error() <<
".debug_line["
1175 <<
format(
"0x%08" PRIx64,
1177 <<
"][" << RowIndex <<
"] has invalid file index " << Row.File
1178 <<
" (valid values are [" << MinFileIndex <<
','
1179 << LineTable->Prologue.FileNames.size()
1180 << (isDWARF5 ?
")" :
"]") <<
"):\n";
1186 if (Row.EndSequence)
1189 PrevAddress = Row.Address.Address;
1197 : OS(S), DCtx(
D), DumpOpts(
std::
move(DumpOpts)), IsObjectFile(
false),
1198 IsMachOObject(
false) {
1199 ErrorCategory.ShowDetail(this->DumpOpts.
Verbose ||
1200 !this->DumpOpts.ShowAggregateErrors);
1201 if (
const auto *
F = DCtx.getDWARFObj().getFile()) {
1202 IsObjectFile = F->isRelocatableObject();
1203 IsMachOObject = F->isMachO();
1208 NumDebugLineErrors = 0;
1209 OS <<
"Verifying .debug_line...\n";
1210 verifyDebugLineStmtOffsets();
1211 verifyDebugLineRows();
1212 return NumDebugLineErrors == 0;
1215void DWARFVerifier::verifyAppleAccelTable(
const DWARFSection *AccelSection,
1225 if (!AccelSectionData.isValidOffset(
AccelTable.getSizeHdr())) {
1226 ErrorCategory.
Report(
"Section is too small to fit a section header", [&]() {
1227 error() <<
"Section is too small to fit a section header.\n";
1233 if (
Error E = AccelTable.extract()) {
1234 std::string Msg =
toString(std::move(
E));
1235 ErrorCategory.Report(
"Section is too small to fit a section header",
1236 [&]() {
error() << Msg <<
'\n'; });
1241 uint32_t NumBuckets = AccelTable.getNumBuckets();
1242 uint32_t NumHashes = AccelTable.getNumHashes();
1244 uint64_t BucketsOffset =
1245 AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
1246 uint64_t HashesBase = BucketsOffset + NumBuckets * 4;
1247 uint64_t OffsetsBase = HashesBase + NumHashes * 4;
1248 for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
1249 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
1250 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
1251 ErrorCategory.Report(
"Invalid hash index", [&]() {
1252 error() <<
format(
"Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
1257 uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
1258 if (NumAtoms == 0) {
1259 ErrorCategory.Report(
"No atoms", [&]() {
1260 error() <<
"No atoms: failed to read HashData.\n";
1264 if (!AccelTable.validateForms()) {
1265 ErrorCategory.Report(
"Unsupported form", [&]() {
1266 error() <<
"Unsupported form: failed to read HashData.\n";
1271 for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
1272 uint64_t HashOffset = HashesBase + 4 * HashIdx;
1273 uint64_t DataOffset = OffsetsBase + 4 * HashIdx;
1274 uint32_t Hash = AccelSectionData.getU32(&HashOffset);
1275 uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
1276 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
1277 sizeof(uint64_t))) {
1278 ErrorCategory.Report(
"Invalid HashData offset", [&]() {
1279 error() <<
format(
"Hash[%d] has invalid HashData offset: "
1280 "0x%08" PRIx64
".\n",
1281 HashIdx, HashDataOffset);
1285 uint64_t StrpOffset;
1286 uint64_t StringOffset;
1287 uint32_t StringCount = 0;
1290 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
1291 const uint32_t NumHashDataObjects =
1292 AccelSectionData.getU32(&HashDataOffset);
1293 for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
1295 std::tie(
Offset,
Tag) = AccelTable.readAtoms(&HashDataOffset);
1296 auto Die = DCtx.getDIEForOffset(
Offset);
1298 const uint32_t BucketIdx =
1299 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
1300 StringOffset = StrpOffset;
1301 const char *
Name = StrData->
getCStr(&StringOffset);
1305 ErrorCategory.Report(
"Invalid DIE offset", [&]() {
1307 "%s Bucket[%d] Hash[%d] = 0x%08x "
1308 "Str[%u] = 0x%08" PRIx64
" DIE[%d] = 0x%08" PRIx64
" "
1309 "is not a valid DIE offset for \"%s\".\n",
1310 SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
1311 HashDataIdx,
Offset, Name);
1315 if ((
Tag != dwarf::DW_TAG_null) && (Die.
getTag() !=
Tag)) {
1316 ErrorCategory.Report(
"Mismatched Tag in accellerator table", [&]() {
1318 <<
" in accelerator table does not match Tag "
1320 << HashDataIdx <<
"].\n";
1331 DenseMap<uint64_t, uint64_t> CUMap;
1332 CUMap.
reserve(DCtx.getNumCompileUnits());
1334 DenseSet<uint64_t> CUOffsets;
1335 for (
const auto &CU : DCtx.compile_units())
1336 CUOffsets.
insert(CU->getOffset());
1338 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
1340 ErrorCategory.Report(
"Name Index doesn't index any CU", [&]() {
1341 error() <<
formatv(
"Name Index @ {0:x} does not index any CU\n",
1346 for (uint32_t CU = 0, End = NI.
getCUCount(); CU < End; ++CU) {
1349 ErrorCategory.Report(
"Name Index references non-existing CU", [&]() {
1351 "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
1356 uint64_t DuplicateCUOffset = 0;
1358 std::lock_guard<std::mutex> Lock(AccessMutex);
1360 if (Iter != CUMap.
end())
1361 DuplicateCUOffset = Iter->second;
1365 if (DuplicateCUOffset) {
1366 ErrorCategory.Report(
"Duplicate Name Index", [&]() {
1368 "Name Index @ {0:x} references a CU @ {1:x}, but "
1369 "this CU is already indexed by Name Index @ {2:x}\n",
1377 for (
const auto &CU : DCtx.compile_units()) {
1378 if (CUMap.
count(CU->getOffset()) == 0)
1379 warn() <<
formatv(
"CU @ {0:x} not covered by any Name Index\n",
1390 constexpr BucketInfo(uint32_t Bucket, uint32_t
Index)
1396 warn() <<
formatv(
"Name Index @ {0:x} does not contain a hash table.\n",
1403 std::vector<BucketInfo> BucketStarts;
1405 const uint64_t OrigNumberOfErrors = ErrorCategory.GetNumErrors();
1406 for (uint32_t Bucket = 0, End = NI.
getBucketCount(); Bucket < End; ++Bucket) {
1409 ErrorCategory.Report(
"Name Index Bucket contains invalid value", [&]() {
1410 error() <<
formatv(
"Bucket {0} of Name Index @ {1:x} contains invalid "
1411 "value {2}. Valid range is [0, {3}].\n",
1418 BucketStarts.emplace_back(Bucket,
Index);
1424 if (OrigNumberOfErrors != ErrorCategory.GetNumErrors())
1437 uint32_t NextUncovered = 1;
1438 for (
const BucketInfo &
B : BucketStarts) {
1445 if (
B.Index > NextUncovered) {
1446 ErrorCategory.Report(
"Name table entries uncovered by hash table", [&]() {
1447 error() <<
formatv(
"Name Index @ {0:x}: Name table entries [{1}, {2}] "
1448 "are not covered by the hash table.\n",
1452 uint32_t Idx =
B.Index;
1465 ErrorCategory.Report(
"Name Index point to mismatched hash value", [&]() {
1467 "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
1468 "mismatched hash value {2:x} (belonging to bucket {3}).\n",
1484 ErrorCategory.Report(
1485 "String hash doesn't match Name Index hash", [&]() {
1487 "Name Index @ {0:x}: String ({1}) at index {2} "
1488 "hashes to {3:x}, but "
1489 "the Name Index hash is {4:x}\n",
1495 NextUncovered = std::max(NextUncovered, Idx);
1499void DWARFVerifier::verifyNameIndexAttribute(
1503 if (FormName.
empty()) {
1504 ErrorCategory.Report(
"Unknown NameIndex Abbreviation", [&]() {
1505 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1506 "unknown form: {3}.\n",
1513 if (AttrEnc.
Index == DW_IDX_type_hash) {
1514 if (AttrEnc.
Form != dwarf::DW_FORM_data8) {
1515 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1517 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
1518 "uses an unexpected form {2} (should be {3}).\n",
1526 if (AttrEnc.
Index == dwarf::DW_IDX_parent) {
1527 constexpr static auto AllowedForms = {dwarf::Form::DW_FORM_flag_present,
1528 dwarf::Form::DW_FORM_ref4};
1530 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1532 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_parent "
1533 "uses an unexpected form {2} (should be "
1534 "DW_FORM_ref4 or DW_FORM_flag_present).\n",
1545 struct FormClassTable {
1548 StringLiteral ClassName;
1550 static constexpr FormClassTable Table[] = {
1558 return T.Index == AttrEnc.
Index;
1561 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} contains an "
1562 "unknown index attribute: {2}.\n",
1567 if (!DWARFFormValue(AttrEnc.
Form).isFormClass(Iter->Class)) {
1568 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1569 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1570 "unexpected form {3} (expected form class {4}).\n",
1572 AttrEnc.
Form, Iter->ClassName);
1578void DWARFVerifier::verifyNameIndexAbbrevs(
1582 if (TagName.
empty()) {
1583 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} references an "
1584 "unknown tag: {2}.\n",
1588 for (
const auto &AttrEnc : Abbrev.Attributes) {
1590 ErrorCategory.Report(
1591 "NameIndex Abbreviateion contains multiple attributes", [&]() {
1593 "NameIndex @ {0:x}: Abbreviation {1:x} contains "
1594 "multiple {2} attributes.\n",
1599 verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
1603 !
Attributes.count(dwarf::DW_IDX_type_unit)) {
1604 ErrorCategory.Report(
"Abbreviation contains no attribute", [&]() {
1605 error() <<
formatv(
"NameIndex @ {0:x}: Indexing multiple compile units "
1606 "and abbreviation {1:x} has no DW_IDX_compile_unit "
1607 "or DW_IDX_type_unit attribute.\n",
1611 if (!
Attributes.count(dwarf::DW_IDX_die_offset)) {
1612 ErrorCategory.Report(
"Abbreviate in NameIndex missing attribute", [&]() {
1614 "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
1624 bool IncludeStrippedTemplateNames,
1625 bool IncludeObjCNames =
true,
1626 bool IncludeLinkageName =
true) {
1628 if (
const char *Str =
DIE.getShortName()) {
1630 Result.emplace_back(Name);
1631 if (IncludeStrippedTemplateNames) {
1632 if (std::optional<StringRef> StrippedName =
1636 Result.push_back(StrippedName->str());
1639 if (IncludeObjCNames) {
1640 if (std::optional<ObjCSelectorNames> ObjCNames =
1642 Result.emplace_back(ObjCNames->ClassName);
1643 Result.emplace_back(ObjCNames->Selector);
1644 if (ObjCNames->ClassNameNoCategory)
1645 Result.emplace_back(*ObjCNames->ClassNameNoCategory);
1646 if (ObjCNames->MethodNameNoCategory)
1647 Result.push_back(std::move(*ObjCNames->MethodNameNoCategory));
1650 }
else if (
DIE.
getTag() == dwarf::DW_TAG_namespace)
1651 Result.emplace_back(
"(anonymous namespace)");
1653 if (IncludeLinkageName) {
1654 if (
const char *Str =
DIE.getLinkageName())
1655 Result.emplace_back(Str);
1661void DWARFVerifier::verifyNameIndexEntries(
1667 ErrorCategory.Report(
"Unable to get string associated with name", [&]() {
1668 error() <<
formatv(
"Name Index @ {0:x}: Unable to get string associated "
1674 StringRef Str(CStr);
1677 uint64_t NextEntryID = EntryID;
1678 Expected<DWARFDebugNames::Entry> EntryOr = NI.
getEntry(&NextEntryID);
1679 for (; EntryOr; ++
NumEntries, EntryID = NextEntryID,
1680 EntryOr = NI.
getEntry(&NextEntryID)) {
1682 std::optional<uint64_t> CUIndex = EntryOr->getRelatedCUIndex();
1683 std::optional<uint64_t> TUIndex = EntryOr->getTUIndex();
1684 if (CUIndex && *CUIndex >= NI.
getCUCount()) {
1685 ErrorCategory.Report(
"Name Index entry contains invalid CU index", [&]() {
1686 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1687 "invalid CU index ({2}).\n",
1694 if (TUIndex && *TUIndex >= (NumLocalTUs + NumForeignTUs)) {
1695 ErrorCategory.Report(
"Name Index entry contains invalid TU index", [&]() {
1696 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1697 "invalid TU index ({2}).\n",
1702 std::optional<uint64_t> UnitOffset;
1705 if (*TUIndex >= NumLocalTUs) {
1718 ErrorCategory.Report(
1719 "Name Index entry contains foreign TU index with invalid CU "
1723 "Name Index @ {0:x}: Entry @ {1:x} contains an "
1724 "foreign TU index ({2}) with no CU index.\n",
1733 }
else if (CUIndex) {
1739 if (!UnitOffset || UnitOffset == UINT32_MAX)
1744 DWARFUnit *DU = DCtx.getUnitForOffset(*UnitOffset);
1745 if (DU ==
nullptr || DU->
getOffset() != *UnitOffset) {
1748 ErrorCategory.Report(
1749 "Name Index entry contains invalid CU or TU offset", [&]() {
1750 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1751 "invalid CU or TU offset {2:x}.\n",
1767 DWARFUnit *NonSkeletonUnit =
nullptr;
1770 NonSkeletonUnit = Iter->second;
1772 NonSkeletonUnit = DU;
1776 ErrorCategory.Report(
"Unable to get load .dwo file", [&]() {
1778 "Name Index @ {0:x}: Entry @ {1:x} unable to load "
1779 ".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
1787 if (TUIndex && *TUIndex >= NumLocalTUs) {
1795 const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs;
1797 llvm::DWARFContext &NonSkeletonDCtx = NonSkeletonUnit->
getContext();
1805 if (NonSkeletonDCtx.
isDWP()) {
1806 DWARFDie NonSkeletonUnitDie = NonSkeletonUnit->
getUnitDIE(
true);
1808 UnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1810 NonSkeletonUnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1811 if (DUDwoName != TUDwoName)
1815 uint64_t DIEOffset =
1816 NonSkeletonUnit->
getOffset() + *EntryOr->getDIEUnitOffset();
1820 if (DIEOffset >= NextUnitOffset) {
1821 ErrorCategory.Report(
"NameIndex relative DIE offset too large", [&]() {
1822 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1823 "DIE @ {2:x} when CU or TU ends at {3:x}.\n",
1831 ErrorCategory.Report(
"NameIndex references nonexistent DIE", [&]() {
1832 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1833 "non-existing DIE @ {2:x}.\n",
1844 ErrorCategory.Report(
"Name index contains mismatched CU of DIE", [&]() {
1846 "Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
1847 "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
1852 if (DIE.
getTag() != EntryOr->tag()) {
1853 ErrorCategory.Report(
"Name Index contains mismatched Tag of DIE", [&]() {
1855 "Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
1856 "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1864 auto IncludeStrippedTemplateNames =
1865 DIE.
getTag() == DW_TAG_subprogram ||
1866 DIE.
getTag() == DW_TAG_inlined_subroutine;
1867 auto EntryNames =
getNames(DIE, IncludeStrippedTemplateNames);
1869 ErrorCategory.Report(
"Name Index contains mismatched name of DIE", [&]() {
1870 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
1871 "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1873 make_range(EntryNames.begin(), EntryNames.end()));
1878 EntryOr.takeError(),
1879 [&](
const DWARFDebugNames::SentinelError &) {
1882 ErrorCategory.Report(
1883 "NameIndex Name is not associated with any entries", [&]() {
1884 error() << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
1885 "not associated with any entries.\n",
1886 NI.getUnitOffset(), NTE.getIndex(), Str);
1890 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
1891 error() <<
formatv(
"Name Index @ {0:x}: Name {1} ({2}): {3}\n",
1906 for (
const auto &Entry : *
Loc) {
1908 U->getAddressByteSize());
1910 U->getFormParams().Format);
1911 bool IsInteresting =
1913 return !
Op.isError() && (
Op.getCode() == DW_OP_addr ||
1914 Op.getCode() == DW_OP_form_tls_address ||
1915 Op.getCode() == DW_OP_GNU_push_tls_address);
1923void DWARFVerifier::verifyNameIndexCompleteness(
1932 if (Die.
find(DW_AT_declaration))
1942 auto IncludeLinkageName = Die.
getTag() == DW_TAG_subprogram ||
1943 Die.
getTag() == DW_TAG_inlined_subroutine;
1946 auto IncludeStrippedTemplateNames =
false;
1947 auto IncludeObjCNames =
false;
1948 auto EntryNames =
getNames(Die, IncludeStrippedTemplateNames,
1949 IncludeObjCNames, IncludeLinkageName);
1950 if (EntryNames.empty())
1960 case DW_TAG_compile_unit:
1966 case DW_TAG_formal_parameter:
1967 case DW_TAG_template_value_parameter:
1968 case DW_TAG_template_type_parameter:
1969 case DW_TAG_GNU_template_parameter_pack:
1970 case DW_TAG_GNU_template_template_param:
1980 case DW_TAG_enumerator:
1985 case DW_TAG_imported_declaration:
1991 case DW_TAG_subprogram:
1992 case DW_TAG_inlined_subroutine:
1995 {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
2004 case DW_TAG_variable:
2016 for (StringRef Name : EntryNames) {
2017 auto iter = NamesToDieOffsets.find(Name);
2018 if (iter == NamesToDieOffsets.end() || !iter->second.count(DieUnitOffset)) {
2019 ErrorCategory.Report(
2020 "Name Index DIE entry missing name",
2023 "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
2024 "name {3} missing.\n",
2025 NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name);
2037 CUTU->getBaseAddress();
2040 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2041 DCtx.getRecoverableErrorHandler()(std::move(E));
2047 if (!
CU->getDWOId())
2050 CU->getNonSkeletonUnitDIE().getDwarfUnit()->getContext();
2052 for (
auto &CUTU : NonSkeletonContext.
dwo_units()) {
2054 CUTU->getBaseAddress();
2057 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2058 DCtx.getRecoverableErrorHandler()(std::move(E));
2061 if (NonSkeletonContext.
isDWP())
2066void DWARFVerifier::verifyDebugNames(
const DWARFSection &AccelSection,
2068 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,
2069 DCtx.isLittleEndian(), 0);
2070 DWARFDebugNames AccelTable(AccelSectionData, StrData);
2072 OS <<
"Verifying .debug_names...\n";
2077 std::string Msg =
toString(std::move(
E));
2078 ErrorCategory.Report(
"Accelerator Table Error",
2079 [&]() {
error() << Msg <<
'\n'; });
2082 const uint64_t OriginalNumErrors = ErrorCategory.GetNumErrors();
2083 verifyDebugNamesCULists(AccelTable);
2084 for (
const auto &NI : AccelTable)
2085 verifyNameIndexBuckets(NI, StrData);
2086 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
2087 verifyNameIndexAbbrevs(NI);
2091 if (OriginalNumErrors != ErrorCategory.GetNumErrors())
2093 DenseMap<uint64_t, DWARFUnit *> CUOffsetsToDUMap;
2094 for (
const auto &CU : DCtx.compile_units()) {
2095 if (!(CU->getVersion() >= 5 && CU->getDWOId()))
2097 CUOffsetsToDUMap[CU->getOffset()] =
2098 CU->getNonSkeletonUnitDIE().getDwarfUnit();
2101 for (
const DWARFDebugNames::NameIndex &NI : AccelTable) {
2103 verifyNameIndexEntries(NI, NTE, CUOffsetsToDUMap);
2107 auto populateNameToOffset =
2108 [&](
const DWARFDebugNames::NameIndex &NI,
2109 StringMap<DenseSet<uint64_t>> &NamesToDieOffsets) {
2110 for (
const DWARFDebugNames::NameTableEntry &NTE : NI) {
2112 const std::string
Name = tName ? std::string(tName) :
"";
2114 Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&EntryID);
2115 auto Iter = NamesToDieOffsets.insert({
Name, DenseSet<uint64_t>(3)});
2116 for (; EntryOr; EntryOr = NI.getEntry(&EntryID)) {
2117 if (std::optional<uint64_t> DieOffset = EntryOr->getDIEUnitOffset())
2118 Iter.first->second.insert(*DieOffset);
2122 [&](
const DWARFDebugNames::SentinelError &) {
2123 if (!NamesToDieOffsets.empty())
2125 ErrorCategory.Report(
2126 "NameIndex Name is not associated with any entries", [&]() {
2128 << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
2129 "not associated with any entries.\n",
2130 NI.getUnitOffset(), NTE.getIndex(), Name);
2133 [&](
const ErrorInfoBase &
Info) {
2134 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
2136 "Name Index @ {0:x}: Name {1} ({2}): {3}\n",
2137 NI.getUnitOffset(), NTE.
getIndex(), Name,
Info.message());
2146 populateNameToOffset(NI, NamesToDieOffsets);
2147 for (uint32_t i = 0, iEnd = NI.getCUCount(); i < iEnd; ++i) {
2148 const uint64_t CUOffset = NI.getCUOffset(i);
2149 DWARFUnit *
U = DCtx.getUnitForOffset(CUOffset);
2156 if (CUDie != NonSkeletonUnitDie) {
2160 verifyNameIndexCompleteness(
2161 DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), NI,
2167 verifyNameIndexCompleteness(DWARFDie(CU, &Die), NI,
2178 DataExtractor StrData(
D.getStrSection(), DCtx.isLittleEndian(), 0);
2179 if (!
D.getAppleNamesSection().Data.empty())
2180 verifyAppleAccelTable(&
D.getAppleNamesSection(), &StrData,
".apple_names");
2181 if (!
D.getAppleTypesSection().Data.empty())
2182 verifyAppleAccelTable(&
D.getAppleTypesSection(), &StrData,
".apple_types");
2183 if (!
D.getAppleNamespacesSection().Data.empty())
2184 verifyAppleAccelTable(&
D.getAppleNamespacesSection(), &StrData,
2185 ".apple_namespaces");
2186 if (!
D.getAppleObjCSection().Data.empty())
2187 verifyAppleAccelTable(&
D.getAppleObjCSection(), &StrData,
".apple_objc");
2189 if (!
D.getNamesSection().Data.empty())
2190 verifyDebugNames(
D.getNamesSection(), StrData);
2191 return ErrorCategory.GetNumErrors() == 0;
2195 OS <<
"Verifying .debug_str_offsets...\n";
2204 std::optional<DwarfFormat> DwoLegacyDwarf4Format;
2206 if (DwoLegacyDwarf4Format)
2212 DwoLegacyDwarf4Format = InfoFormat;
2216 DwoLegacyDwarf4Format,
".debug_str_offsets.dwo",
2219 std::nullopt,
".debug_str_offsets",
2233 while (
C.seek(NextUnit),
C.tell() < DA.getData().size()) {
2239 Length = DA.getData().size();
2245 if (
C.tell() +
Length > DA.getData().size()) {
2246 ErrorCategory.Report(
2247 "Section contribution length exceeds available space", [&]() {
2249 "{0}: contribution {1:X}: length exceeds available space "
2251 "offset ({1:X}) + length field space ({2:X}) + length "
2253 "{4:X} > section size {5:X})\n",
2255 C.tell() +
Length, DA.getData().size());
2264 ErrorCategory.Report(
"Invalid Section version", [&]() {
2265 error() <<
formatv(
"{0}: contribution {1:X}: invalid version {2}\n",
2276 DA.setAddressSize(OffsetByteSize);
2278 if (Remainder != 0) {
2279 ErrorCategory.Report(
"Invalid section contribution length", [&]() {
2281 "{0}: contribution {1:X}: invalid length ((length ({2:X}) "
2282 "- header (0x4)) % offset size {3:X} == {4:X} != 0)\n",
2293 if (StrData.
size() <= StrOff) {
2294 ErrorCategory.Report(
2295 "String offset out of bounds of string section", [&]() {
2297 "{0}: contribution {1:X}: index {2:X}: invalid string "
2298 "offset *{3:X} == {4:X}, is beyond the bounds of the string "
2299 "section of length {5:X}\n",
2305 if (StrData[StrOff - 1] ==
'\0')
2307 ErrorCategory.Report(
2308 "Section contribution contains invalid string offset", [&]() {
2310 "{0}: contribution {1:X}: index {2:X}: invalid string "
2311 "offset *{3:X} == {4:X}, is neither zero nor "
2312 "immediately following a null character\n",
2319 if (
Error E =
C.takeError()) {
2320 std::string Msg =
toString(std::move(E));
2321 ErrorCategory.Report(
"String offset error", [&]() {
2330 StringRef s, std::function<
void(
void)> detailCallback) {
2331 this->
Report(s,
"", detailCallback);
2336 std::function<
void(
void)> detailCallback) {
2337 std::lock_guard<std::mutex> Lock(WriteMutex);
2339 std::string category_str = std::string(category);
2342 if (!sub_category.
empty()) {
2350 std::function<
void(
StringRef,
unsigned)> handleCounts) {
2351 for (
const auto &[
name, aggData] : Aggregation) {
2352 handleCounts(
name, aggData.OverallCount);
2357 const auto Agg = Aggregation.find(category);
2358 if (Agg != Aggregation.end()) {
2360 handleCounts(
name, aggData);
2366 if (DumpOpts.ShowAggregateErrors && ErrorCategory.GetNumCategories()) {
2367 error() <<
"Aggregated error counts:\n";
2368 ErrorCategory.EnumerateResults([&](
StringRef s,
unsigned count) {
2369 error() << s <<
" occurred " <<
count <<
" time(s).\n";
2372 if (!DumpOpts.JsonErrSummaryFile.empty()) {
2377 error() <<
"unable to open json summary file '"
2378 << DumpOpts.JsonErrSummaryFile
2379 <<
"' for writing: " << EC.message() <<
'\n';
2385 ErrorCategory.EnumerateResults([&](
StringRef Category,
unsigned Count) {
2389 ErrorCategory.EnumerateDetailedResultsFor(
2390 Category, [&](
StringRef SubCategory,
unsigned SubCount) {
2395 ErrorCount +=
Count;
2398 RootNode.
try_emplace(
"error-categories", std::move(Categories));
2412 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")
Analysis containing CSE Info
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...
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
@ 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.