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() <<
formatv(
"Units[{0}] - start offset: {1:x+8}\n", UnitIndex,
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;
237 if (OriginalFullName.empty() || OriginalFullName == ReconstructedName)
240 ErrorCategory.Report(
241 "Simplified template DW_AT_name could not be reconstituted", [&]() {
243 <<
"Simplified template DW_AT_name could not be reconstituted:\n"
245 " reconstituted: {1}\n",
246 OriginalFullName, ReconstructedName);
253unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit,
254 ReferenceMap &UnitLocalReferences,
255 ReferenceMap &CrossUnitReferences) {
256 unsigned NumUnitErrors = 0;
257 unsigned NumDies =
Unit.getNumDIEs();
258 for (
unsigned I = 0;
I < NumDies; ++
I) {
259 auto Die =
Unit.getDIEAtIndex(
I);
261 if (Die.
getTag() == DW_TAG_null)
265 NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
266 NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences,
267 CrossUnitReferences);
270 NumUnitErrors += verifyName(Die);
275 warn() <<
formatv(
"{0} has DW_CHILDREN_yes but DIE has no children: ",
281 NumUnitErrors += verifyDebugInfoCallSite(Die);
284 DWARFDie Die =
Unit.getUnitDIE(
false);
286 ErrorCategory.Report(
"Compilation unit missing DIE", [&]() {
287 error() <<
"Compilation unit without DIE.\n";
290 return NumUnitErrors;
294 ErrorCategory.Report(
"Compilation unit root DIE is not a unit DIE", [&]() {
295 error() <<
formatv(
"Compilation unit root DIE is not a unit DIE: {0}.\n",
303 ErrorCategory.Report(
"Mismatched unit type", [&]() {
305 "Compilation unit type ({0}) and root DIE ({1}) do not match.\n",
315 ErrorCategory.Report(
"Skeleton CU has children", [&]() {
316 error() <<
"Skeleton compilation unit has children.\n";
322 NumUnitErrors += verifyDieRanges(Die, RI);
324 return NumUnitErrors;
327unsigned DWARFVerifier::verifyDebugInfoCallSite(
const DWARFDie &Die) {
328 if (Die.
getTag() != DW_TAG_call_site && Die.
getTag() != DW_TAG_GNU_call_site)
333 if (Curr.
getTag() == DW_TAG_inlined_subroutine) {
334 ErrorCategory.Report(
335 "Call site nested entry within inlined subroutine", [&]() {
336 error() <<
"Call site entry nested within inlined subroutine:";
344 ErrorCategory.Report(
345 "Call site entry not nested within valid subprogram", [&]() {
346 error() <<
"Call site entry not nested within a valid subprogram:";
352 std::optional<DWARFFormValue> CallAttr = Curr.
find(
353 {DW_AT_call_all_calls, DW_AT_call_all_source_calls,
354 DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,
355 DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites});
357 ErrorCategory.Report(
358 "Subprogram with call site entry has no DW_AT_call attribute", [&]() {
360 <<
"Subprogram with call site entry has no DW_AT_call attribute:";
370unsigned DWARFVerifier::verifyAbbrevSection(
const DWARFDebugAbbrev *Abbrev) {
374 Expected<const DWARFAbbreviationDeclarationSet *> AbbrDeclsOrErr =
376 if (!AbbrDeclsOrErr) {
378 ErrorCategory.Report(
"Abbreviation Declaration error",
379 [&]() {
error() << ErrMsg <<
"\n"; });
383 const auto *AbbrDecls = *AbbrDeclsOrErr;
384 unsigned NumErrors = 0;
385 for (
auto AbbrDecl : *AbbrDecls) {
386 SmallDenseSet<uint16_t> AttributeSet;
387 for (
auto Attribute : AbbrDecl.attributes()) {
390 ErrorCategory.Report(
391 "Abbreviation declartion contains multiple attributes", [&]() {
392 error() <<
formatv(
"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;
423 for (
const auto &Unit : Units) {
424 OS <<
formatv(
"Verifying unit: {0} / {1}",
Index, Units.getNumUnits());
425 if (
const char* Name = Unit->getUnitDIE(
true).getShortName())
426 OS <<
formatv(
", \"{0}\"", Name);
429 ReferenceMap UnitLocalReferences;
430 NumDebugInfoErrors +=
431 verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences);
432 NumDebugInfoErrors += verifyDebugInfoReferences(
433 UnitLocalReferences, [&](
uint64_t Offset) {
return Unit.get(); });
437 NumDebugInfoErrors += verifyDebugInfoReferences(
438 CrossUnitReferences, [&](uint64_t
Offset) -> DWARFUnit * {
439 if (DWARFUnit *U = Units.getUnitForOffset(
Offset))
444 return NumDebugInfoErrors;
447unsigned DWARFVerifier::verifyUnitSection(
const DWARFSection &S) {
448 const DWARFObject &DObj = DCtx.getDWARFObj();
449 DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);
450 unsigned NumDebugInfoErrors = 0;
451 uint64_t
Offset = 0, UnitIdx = 0;
453 bool isUnitDWARF64 =
false;
454 bool isHeaderChainValid =
true;
456 DWARFUnitVector TypeUnitVector;
457 DWARFUnitVector CompileUnitVector;
461 isHeaderChainValid =
false;
468 if (UnitIdx == 0 && !hasDIE) {
469 warn() <<
"Section is empty.\n";
470 isHeaderChainValid =
true;
472 if (!isHeaderChainValid)
473 ++NumDebugInfoErrors;
474 return NumDebugInfoErrors;
477unsigned DWARFVerifier::verifyIndex(StringRef Name,
479 StringRef IndexStr) {
480 if (IndexStr.
empty())
482 OS <<
"Verifying " <<
Name <<
"...\n";
483 DWARFUnitIndex
Index(InfoColumnKind);
484 DataExtractor
D(IndexStr, DCtx.isLittleEndian(), 0);
487 using MapType = IntervalMap<uint64_t, uint64_t>;
488 MapType::Allocator
Alloc;
489 std::vector<std::unique_ptr<MapType>> Sections(
Index.getColumnKinds().size());
490 for (
const DWARFUnitIndex::Entry &
E :
Index.getRows()) {
491 uint64_t Sig =
E.getSignature();
492 if (!
E.getContributions())
495 InfoColumnKind == DW_SECT_INFO
498 const DWARFUnitIndex::Entry::SectionContribution &SC =
E.value();
503 Sections[Col] = std::make_unique<MapType>(
Alloc);
504 auto &
M = *Sections[Col];
507 StringRef Category = InfoColumnKind == DWARFSectionKind::DW_SECT_INFO
508 ?
"Overlapping CU index entries"
509 :
"Overlapping TU index entries";
510 ErrorCategory.Report(Category, [&]() {
512 "overlapping index entries for entries {0:x16} "
513 "and {1:x16} for column {2}\n",
526 return verifyIndex(
".debug_cu_index", DWARFSectionKind::DW_SECT_INFO,
527 DCtx.getDWARFObj().getCUIndexSection()) == 0;
532 DCtx.getDWARFObj().getTUIndexSection()) == 0;
537 unsigned NumErrors = 0;
539 OS <<
"Verifying .debug_info Unit Header Chain...\n";
541 NumErrors += verifyUnitSection(S);
544 OS <<
"Verifying .debug_types Unit Header Chain...\n";
546 NumErrors += verifyUnitSection(S);
549 OS <<
"Verifying non-dwo Units...\n";
550 NumErrors += verifyUnits(DCtx.getNormalUnitsVector());
552 OS <<
"Verifying dwo Units...\n";
553 NumErrors += verifyUnits(DCtx.getDWOUnitsVector());
554 return NumErrors == 0;
557unsigned DWARFVerifier::verifyDieRanges(
const DWARFDie &Die,
558 DieRangeInfo &ParentRI) {
559 unsigned NumErrors = 0;
567 if (!RangesOrError) {
569 if (!Unit->isDWOUnit())
578 DieRangeInfo RI(Die);
599 if (!IsObjectFile || IsMachOObject || Die.
getTag() != DW_TAG_compile_unit) {
600 bool DumpDieAfterError =
false;
601 for (
const auto &
Range : Ranges) {
602 if (!
Range.valid()) {
604 ErrorCategory.
Report(
"Invalid address range", [&]() {
606 DumpDieAfterError =
true;
617 if (
auto PrevRange = RI.insert(
Range)) {
619 ErrorCategory.Report(
"DIE has overlapping DW_AT_ranges", [&]() {
620 error() <<
formatv(
"DIE has overlapping ranges in DW_AT_ranges "
621 "attribute: {0} and {1}\n",
623 DumpDieAfterError =
true;
627 if (DumpDieAfterError)
628 dump(Die, 2) <<
'\n';
632 const auto IntersectingChild = ParentRI.insert(RI);
633 if (IntersectingChild != ParentRI.Children.end()) {
635 ErrorCategory.Report(
"DIEs have overlapping address ranges", [&]() {
636 error() <<
"DIEs have overlapping address ranges:";
638 dump(IntersectingChild->Die) <<
'\n';
643 bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() &&
644 !(Die.
getTag() == DW_TAG_subprogram &&
645 ParentRI.Die.getTag() == DW_TAG_subprogram);
646 if (ShouldBeContained && !ParentRI.contains(RI)) {
648 ErrorCategory.Report(
649 "DIE address ranges are not contained by parent ranges", [&]() {
651 <<
"DIE address ranges are not contained in its parent's ranges:";
653 dump(Die, 2) <<
'\n';
658 for (DWARFDie Child : Die)
659 NumErrors += verifyDieRanges(Child, RI);
664bool DWARFVerifier::verifyExpressionOp(
const DWARFExpression::Operation &
Op,
666 for (
unsigned Operand = 0; Operand <
Op.Desc.
Op.
size(); ++Operand) {
667 unsigned Size =
Op.Desc.
Op[Operand];
674 if (
Op.Opcode == DW_OP_convert &&
Op.Operands[Operand] == 0)
676 auto Die =
U->getDIEForOffset(
U->getOffset() +
Op.Operands[Operand]);
677 if (!Die || Die.
getTag() != dwarf::DW_TAG_base_type)
685bool DWARFVerifier::verifyExpression(
const DWARFExpression &
E, DWARFUnit *U) {
687 if (!verifyExpressionOp(
Op, U))
693unsigned DWARFVerifier::verifyDebugInfoAttribute(
const DWARFDie &Die,
694 DWARFAttribute &AttrValue) {
695 unsigned NumErrors = 0;
696 auto ReportError = [&](StringRef category,
const Twine &TitleMsg) {
698 ErrorCategory.Report(category, [&]() {
704 const DWARFObject &DObj = DCtx.getDWARFObj();
706 const auto Attr = AttrValue.
Attr;
711 unsigned DwarfVersion =
U->getVersion();
712 const DWARFSection &RangeSection = DwarfVersion < 5
715 if (
U->isDWOUnit() && RangeSection.
Data.
empty())
717 if (*SectionOffset >= RangeSection.
Data.
size())
719 "DW_AT_ranges offset out of bounds",
720 llvm::formatv(
"DW_AT_ranges offset is beyond {0} bounds: {1:x8}",
721 StringRef(DwarfVersion < 5 ?
".debug_ranges"
722 :
".debug_rnglists"),
726 ReportError(
"Invalid DW_AT_ranges encoding",
727 "DIE has invalid DW_AT_ranges encoding:");
729 case DW_AT_stmt_list:
732 if (*SectionOffset >=
U->getLineSection().Data.size())
734 "DW_AT_stmt_list offset out of bounds",
736 "DW_AT_stmt_list offset is beyond .debug_line bounds: {0:x8}",
740 ReportError(
"Invalid DW_AT_stmt_list encoding",
741 "DIE has invalid DW_AT_stmt_list encoding:");
743 case DW_AT_location: {
754 if (Expected<std::vector<DWARFLocationExpression>> Loc =
756 for (
const auto &Entry : *Loc) {
758 DWARFExpression Expression(
Data,
U->getAddressByteSize(),
759 U->getFormParams().Format);
761 any_of(Expression, [](
const DWARFExpression::Operation &
Op) {
764 if (
Error || !verifyExpression(Expression, U))
765 ReportError(
"Invalid DWARF expressions",
766 "DIE contains invalid DWARF expression:");
769 Loc.takeError(), [&](std::unique_ptr<ResolverError>
E) {
770 return U->isDWOUnit() ? Error::success()
771 : Error(std::move(E));
773 ReportError(
"Invalid DW_AT_location",
toString(std::move(Err)));
776 case DW_AT_specification:
777 case DW_AT_abstract_origin: {
779 auto DieTag = Die.
getTag();
780 auto RefTag = ReferencedDie.getTag();
781 if (DieTag == RefTag)
783 if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
785 if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
788 if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)
790 ReportError(
"Incompatible DW_AT_abstract_origin tag reference",
791 formatv(
"DIE with tag {0} has {1} that points to DIE with "
792 "incompatible tag {2}",
801 ReportError(
"Incompatible DW_AT_type attribute tag",
802 formatv(
"DIE has {0} with incompatible tag {1}",
807 case DW_AT_call_file:
808 case DW_AT_decl_file: {
810 if (
U->isDWOUnit() && !
U->isTypeUnit())
812 const auto *
LT =
U->getContext().getLineTableForUnit(U);
814 if (!
LT->hasFileAtIndex(*FileIdx)) {
815 bool IsZeroIndexed =
LT->Prologue.getVersion() >= 5;
816 if (std::optional<uint64_t> LastFileIdx =
817 LT->getLastValidFileIndex()) {
818 ReportError(
"Invalid file index in DW_AT_decl_file",
820 "{1} (valid values are [{2}-{3}])",
822 (IsZeroIndexed ?
"0" :
"1"),
826 "Invalid file index in DW_AT_decl_file",
827 llvm::formatv(
"DIE has {0} with an invalid file index {1} (the "
828 "file table in the prologue is empty)",
834 "File index in DW_AT_decl_file reference CU with no line table",
835 llvm::formatv(
"DIE has {0} that references a file with index {1} "
836 "and the compile unit has no line table",
840 ReportError(
"Invalid encoding in DW_AT_decl_file",
846 case DW_AT_call_line:
847 case DW_AT_decl_line: {
850 Attr == DW_AT_call_line ?
"Invalid file index in DW_AT_decl_line"
851 :
"Invalid file index in DW_AT_call_line",
856 case DW_AT_LLVM_stmt_sequence: {
860 if (!SectionOffset) {
861 ReportError(
"Invalid DW_AT_LLVM_stmt_sequence encoding",
862 "DIE has invalid DW_AT_LLVM_stmt_sequence encoding");
865 if (*SectionOffset >=
U->getLineSection().Data.size()) {
867 "DW_AT_LLVM_stmt_sequence offset out of bounds",
868 "DW_AT_LLVM_stmt_sequence offset is beyond .debug_line bounds: " +
874 const auto *LineTable = DCtx.getLineTableForUnit(U);
876 ReportError(
"DW_AT_LLVM_stmt_sequence without line table",
877 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
883 DWARFDie CUDie =
U->getUnitDIE();
885 if (!StmtListOffset) {
886 ReportError(
"DW_AT_LLVM_stmt_sequence without DW_AT_stmt_list",
887 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
892 const int8_t DwarfOffset =
893 LineTable->Prologue.getFormParams().getDwarfOffsetByteSize();
895 uint64_t LineTableStart = *StmtListOffset;
896 uint64_t PrologueLength = LineTable->Prologue.PrologueLength;
897 uint64_t TotalLength = LineTable->Prologue.TotalLength;
898 uint64_t LineTableEnd = LineTableStart + TotalLength + DwarfOffset;
903 uint64_t InitialLengthSize = DwarfOffset;
905 uint64_t VersionSize = 2;
906 uint64_t PrologueLengthSize = DwarfOffset;
907 uint64_t SequencesStart = LineTableStart + InitialLengthSize + VersionSize +
908 PrologueLengthSize + PrologueLength;
911 if (*SectionOffset < SequencesStart || *SectionOffset >= LineTableEnd) {
912 ReportError(
"DW_AT_LLVM_stmt_sequence offset out of line table bounds",
913 llvm::formatv(
"DW_AT_LLVM_stmt_sequence offset {0:x8} is not "
914 "within the line table bounds [{1:x8}, {2:x8})",
915 *SectionOffset, SequencesStart, LineTableEnd));
921 [SectionOffset](
const auto &Sequence) {
922 return Sequence.StmtSeqOffset == *SectionOffset;
925 if (It == LineTable->Sequences.end())
927 "Invalid DW_AT_LLVM_stmt_sequence offset",
928 llvm::formatv(
"DW_AT_LLVM_stmt_sequence offset {0:x8} does not point "
929 "to a valid sequence offset in the line table",
939unsigned DWARFVerifier::verifyDebugInfoForm(
const DWARFDie &Die,
940 DWARFAttribute &AttrValue,
941 ReferenceMap &LocalReferences,
942 ReferenceMap &CrossUnitReferences) {
944 unsigned NumErrors = 0;
951 case DW_FORM_ref_udata: {
956 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
958 if (CUOffset >= CUSize) {
960 ErrorCategory.Report(
"Invalid CU offset", [&]() {
961 error() <<
formatv(
"{0} CU offset {1:x+8} is invalid (must be less "
962 "than CU size of {2:x+8}):\n",
964 Die.
dump(OS, 0, DumpOpts);
976 case DW_FORM_ref_addr: {
982 if (*RefVal >= DieCU->getInfoSection().Data.size()) {
984 ErrorCategory.Report(
"DW_FORM_ref_addr offset out of bounds", [&]() {
985 error() <<
"DW_FORM_ref_addr offset beyond .debug_info "
992 CrossUnitReferences[*RefVal].insert(Die.
getOffset());
1003 case DW_FORM_line_strp: {
1006 std::string ErrMsg =
toString(std::move(
E));
1007 ErrorCategory.Report(
"Invalid DW_FORM attribute", [&]() {
1020unsigned DWARFVerifier::verifyDebugInfoReferences(
1021 const ReferenceMap &References,
1022 llvm::function_ref<DWARFUnit *(uint64_t)> GetUnitForOffset) {
1023 auto GetDIEForOffset = [&](uint64_t
Offset) {
1024 if (DWARFUnit *U = GetUnitForOffset(
Offset))
1025 return U->getDIEForOffset(
Offset);
1028 unsigned NumErrors = 0;
1029 for (
const std::pair<
const uint64_t, std::set<uint64_t>> &Pair :
1031 if (GetDIEForOffset(Pair.first))
1034 ErrorCategory.Report(
"Invalid DIE reference", [&]() {
1036 "invalid DIE reference {0:x+8}. Offset is in between DIEs:\n",
1038 for (
auto Offset : Pair.second)
1046void DWARFVerifier::verifyDebugLineStmtOffsets() {
1047 std::map<uint64_t, DWARFDie> StmtListToDie;
1048 for (
const auto &CU : DCtx.compile_units()) {
1049 auto Die = CU->getUnitDIE();
1054 if (!StmtSectionOffset)
1056 const uint64_t LineTableOffset = *StmtSectionOffset;
1057 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1058 if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
1060 ++NumDebugLineErrors;
1061 ErrorCategory.Report(
"Unparsable .debug_line entry", [&]() {
1063 ".debug_line[{0:x+8}] 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() <<
formatv(
"two compile unit DIEs, {0:x+8} and {1:x+8}, have "
1082 "the same DW_AT_stmt_list section offset:\n",
1092void DWARFVerifier::verifyDebugLineRows() {
1093 for (
const auto &CU : DCtx.compile_units()) {
1094 auto Die = CU->getUnitDIE();
1095 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1102 bool isDWARF5 = LineTable->Prologue.getVersion() >= 5;
1103 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
1104 uint32_t MinFileIndex = isDWARF5 ? 0 : 1;
1105 uint32_t FileIndex = MinFileIndex;
1106 StringMap<uint16_t> FullPathMap;
1107 for (
const auto &FileName : LineTable->Prologue.FileNames) {
1109 if (FileName.DirIdx > MaxDirIndex) {
1110 ++NumDebugLineErrors;
1111 ErrorCategory.Report(
1112 "Invalid index in .debug_line->prologue.file_names->dir_idx",
1114 error() <<
formatv(
".debug_line[{0:x+8}].prologue.file_names[{1}]"
1115 ".dir_idx contains an invalid index: {2}\n",
1117 FileIndex, FileName.DirIdx);
1122 std::string FullPath;
1123 const bool HasFullPath = LineTable->getFileNameByIndex(
1124 FileIndex, CU->getCompilationDir(),
1126 assert(HasFullPath &&
"Invalid index?");
1129 if (!Inserted && It->second != FileIndex && DumpOpts.Verbose) {
1130 warn() <<
formatv(
".debug_line[{0:x+8}].prologue.file_names[{1}] is a "
1131 "duplicate of file_names[{2}]\n",
1133 FileIndex, It->second);
1141 if (LineTable->Rows.size() == 1 && LineTable->Rows.front().EndSequence)
1145 uint64_t PrevAddress = 0;
1146 uint32_t RowIndex = 0;
1147 for (
const auto &Row : LineTable->Rows) {
1149 if (Row.Address.Address < PrevAddress) {
1150 ++NumDebugLineErrors;
1151 ErrorCategory.Report(
1152 "decreasing address between debug_line rows", [&]() {
1153 error() <<
formatv(
".debug_line[{0:x+8}] row[{1}] decreases in "
1154 "address from previous row:\n",
1160 LineTable->Rows[RowIndex - 1].dump(OS);
1166 if (!LineTable->hasFileAtIndex(Row.File)) {
1167 ++NumDebugLineErrors;
1168 ErrorCategory.Report(
"Invalid file index in debug_line", [&]() {
1169 error() <<
formatv(
".debug_line[{0:x+8}][{1}] has invalid file index "
1170 "{2} (valid values are [{3},{4}{5}):\n",
1172 RowIndex, Row.File, MinFileIndex,
1173 LineTable->Prologue.FileNames.size(),
1174 (isDWARF5 ?
")" :
"]"));
1180 if (Row.EndSequence)
1183 PrevAddress = Row.Address.Address;
1191 : OS(S), DCtx(
D), DumpOpts(
std::
move(DumpOpts)), IsObjectFile(
false),
1192 IsMachOObject(
false) {
1193 ErrorCategory.ShowDetail(this->DumpOpts.
Verbose ||
1194 !this->DumpOpts.ShowAggregateErrors);
1195 if (
const auto *
F = DCtx.getDWARFObj().getFile()) {
1196 IsObjectFile = F->isRelocatableObject();
1197 IsMachOObject = F->isMachO();
1202 NumDebugLineErrors = 0;
1203 OS <<
"Verifying .debug_line...\n";
1204 verifyDebugLineStmtOffsets();
1205 verifyDebugLineRows();
1206 return NumDebugLineErrors == 0;
1209void DWARFVerifier::verifyAppleAccelTable(
const DWARFSection *AccelSection,
1219 if (!AccelSectionData.isValidOffset(
AccelTable.getSizeHdr())) {
1220 ErrorCategory.
Report(
"Section is too small to fit a section header", [&]() {
1221 error() <<
"Section is too small to fit a section header.\n";
1227 if (
Error E = AccelTable.extract()) {
1228 std::string Msg =
toString(std::move(
E));
1229 ErrorCategory.Report(
"Section is too small to fit a section header",
1230 [&]() {
error() << Msg <<
'\n'; });
1235 uint32_t NumBuckets = AccelTable.getNumBuckets();
1236 uint32_t NumHashes = AccelTable.getNumHashes();
1238 uint64_t BucketsOffset =
1239 AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
1240 uint64_t HashesBase = BucketsOffset + NumBuckets * 4;
1241 uint64_t OffsetsBase = HashesBase + NumHashes * 4;
1242 for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
1243 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
1244 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
1245 ErrorCategory.Report(
"Invalid hash index", [&]() {
1246 error() <<
formatv(
"Bucket[{0}] has invalid hash index: {1}.\n",
1247 BucketIdx, HashIdx);
1251 uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
1252 if (NumAtoms == 0) {
1253 ErrorCategory.Report(
"No atoms", [&]() {
1254 error() <<
"No atoms: failed to read HashData.\n";
1258 if (!AccelTable.validateForms()) {
1259 ErrorCategory.Report(
"Unsupported form", [&]() {
1260 error() <<
"Unsupported form: failed to read HashData.\n";
1265 for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
1266 uint64_t HashOffset = HashesBase + 4 * HashIdx;
1267 uint64_t DataOffset = OffsetsBase + 4 * HashIdx;
1268 uint32_t Hash = AccelSectionData.getU32(&HashOffset);
1269 uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
1270 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
1271 sizeof(uint64_t))) {
1272 ErrorCategory.Report(
"Invalid HashData offset", [&]() {
1273 error() <<
formatv(
"Hash[{0}] has invalid HashData offset: {1:x+8}.\n",
1274 HashIdx, HashDataOffset);
1278 uint64_t StrpOffset;
1279 uint64_t StringOffset;
1280 uint32_t StringCount = 0;
1283 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
1284 const uint32_t NumHashDataObjects =
1285 AccelSectionData.getU32(&HashDataOffset);
1286 for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
1288 std::tie(
Offset,
Tag) = AccelTable.readAtoms(&HashDataOffset);
1289 auto Die = DCtx.getDIEForOffset(
Offset);
1291 const uint32_t BucketIdx =
1292 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
1293 StringOffset = StrpOffset;
1294 const char *
Name = StrData->
getCStr(&StringOffset);
1298 ErrorCategory.Report(
"Invalid DIE offset", [&]() {
1299 error() <<
formatv(
"{0} Bucket[{1}] Hash[{2}] = {3:x+8} "
1300 "Str[{4}] = {5:x+8} DIE[{6}] = {7:x+8} "
1301 "is not a valid DIE offset for \"{8}\".\n",
1302 SectionName, BucketIdx, HashIdx, Hash,
1303 StringCount, StrpOffset, HashDataIdx,
Offset,
1308 if ((
Tag != dwarf::DW_TAG_null) && (Die.
getTag() !=
Tag)) {
1309 ErrorCategory.Report(
"Mismatched Tag in accellerator table", [&]() {
1310 error() <<
formatv(
"Tag {0} in accelerator table does not match "
1311 "Tag {1} of DIE[{2}].\n",
1324 DenseMap<uint64_t, uint64_t> CUMap;
1325 CUMap.
reserve(DCtx.getNumCompileUnits());
1327 DenseSet<uint64_t> CUOffsets;
1328 for (
const auto &CU : DCtx.compile_units())
1329 CUOffsets.
insert(CU->getOffset());
1331 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
1333 ErrorCategory.Report(
"Name Index doesn't index any CU", [&]() {
1334 error() <<
formatv(
"Name Index @ {0:x} does not index any CU\n",
1339 for (uint32_t CU = 0, End = NI.
getCUCount(); CU < End; ++CU) {
1342 ErrorCategory.Report(
"Name Index references non-existing CU", [&]() {
1344 "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
1349 uint64_t DuplicateCUOffset = 0;
1351 std::lock_guard<std::mutex> Lock(AccessMutex);
1353 if (Iter != CUMap.
end())
1354 DuplicateCUOffset = Iter->second;
1358 if (DuplicateCUOffset) {
1359 ErrorCategory.Report(
"Duplicate Name Index", [&]() {
1361 "Name Index @ {0:x} references a CU @ {1:x}, but "
1362 "this CU is already indexed by Name Index @ {2:x}\n",
1370 for (
const auto &CU : DCtx.compile_units()) {
1371 if (CUMap.
count(CU->getOffset()) == 0)
1372 warn() <<
formatv(
"CU @ {0:x} not covered by any Name Index\n",
1383 constexpr BucketInfo(uint32_t Bucket, uint32_t
Index)
1389 warn() <<
formatv(
"Name Index @ {0:x} does not contain a hash table.\n",
1396 std::vector<BucketInfo> BucketStarts;
1398 const uint64_t OrigNumberOfErrors = ErrorCategory.GetNumErrors();
1399 for (uint32_t Bucket = 0, End = NI.
getBucketCount(); Bucket < End; ++Bucket) {
1402 ErrorCategory.Report(
"Name Index Bucket contains invalid value", [&]() {
1403 error() <<
formatv(
"Bucket {0} of Name Index @ {1:x} contains invalid "
1404 "value {2}. Valid range is [0, {3}].\n",
1411 BucketStarts.emplace_back(Bucket,
Index);
1417 if (OrigNumberOfErrors != ErrorCategory.GetNumErrors())
1430 uint32_t NextUncovered = 1;
1431 for (
const BucketInfo &
B : BucketStarts) {
1438 if (
B.Index > NextUncovered) {
1439 ErrorCategory.Report(
"Name table entries uncovered by hash table", [&]() {
1440 error() <<
formatv(
"Name Index @ {0:x}: Name table entries [{1}, {2}] "
1441 "are not covered by the hash table.\n",
1445 uint32_t Idx =
B.Index;
1458 ErrorCategory.Report(
"Name Index point to mismatched hash value", [&]() {
1460 "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
1461 "mismatched hash value {2:x} (belonging to bucket {3}).\n",
1477 ErrorCategory.Report(
1478 "String hash doesn't match Name Index hash", [&]() {
1480 "Name Index @ {0:x}: String ({1}) at index {2} "
1481 "hashes to {3:x}, but "
1482 "the Name Index hash is {4:x}\n",
1488 NextUncovered = std::max(NextUncovered, Idx);
1492void DWARFVerifier::verifyNameIndexAttribute(
1496 if (FormName.
empty()) {
1497 ErrorCategory.Report(
"Unknown NameIndex Abbreviation", [&]() {
1498 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1499 "unknown form: {3}.\n",
1506 if (AttrEnc.
Index == DW_IDX_type_hash) {
1507 if (AttrEnc.
Form != dwarf::DW_FORM_data8) {
1508 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1510 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
1511 "uses an unexpected form {2} (should be {3}).\n",
1519 if (AttrEnc.
Index == dwarf::DW_IDX_parent) {
1520 constexpr static auto AllowedForms = {dwarf::Form::DW_FORM_flag_present,
1521 dwarf::Form::DW_FORM_ref4};
1523 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1525 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_parent "
1526 "uses an unexpected form {2} (should be "
1527 "DW_FORM_ref4 or DW_FORM_flag_present).\n",
1538 struct FormClassTable {
1541 StringLiteral ClassName;
1543 static constexpr FormClassTable Table[] = {
1551 return T.Index == AttrEnc.
Index;
1554 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} contains an "
1555 "unknown index attribute: {2}.\n",
1560 if (!DWARFFormValue(AttrEnc.
Form).isFormClass(Iter->Class)) {
1561 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1562 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1563 "unexpected form {3} (expected form class {4}).\n",
1565 AttrEnc.
Form, Iter->ClassName);
1571void DWARFVerifier::verifyNameIndexAbbrevs(
1575 if (TagName.
empty()) {
1576 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} references an "
1577 "unknown tag: {2}.\n",
1581 for (
const auto &AttrEnc : Abbrev.Attributes) {
1583 ErrorCategory.Report(
1584 "NameIndex Abbreviateion contains multiple attributes", [&]() {
1586 "NameIndex @ {0:x}: Abbreviation {1:x} contains "
1587 "multiple {2} attributes.\n",
1592 verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
1596 !
Attributes.count(dwarf::DW_IDX_type_unit)) {
1597 ErrorCategory.Report(
"Abbreviation contains no attribute", [&]() {
1598 error() <<
formatv(
"NameIndex @ {0:x}: Indexing multiple compile units "
1599 "and abbreviation {1:x} has no DW_IDX_compile_unit "
1600 "or DW_IDX_type_unit attribute.\n",
1604 if (!
Attributes.count(dwarf::DW_IDX_die_offset)) {
1605 ErrorCategory.Report(
"Abbreviate in NameIndex missing attribute", [&]() {
1607 "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
1617 bool IncludeStrippedTemplateNames,
1618 bool IncludeObjCNames =
true,
1619 bool IncludeLinkageName =
true) {
1621 if (
const char *Str =
DIE.getShortName()) {
1623 Result.emplace_back(Name);
1624 if (IncludeStrippedTemplateNames) {
1625 if (std::optional<StringRef> StrippedName =
1629 Result.push_back(StrippedName->str());
1632 if (IncludeObjCNames) {
1633 if (std::optional<ObjCSelectorNames> ObjCNames =
1635 Result.emplace_back(ObjCNames->ClassName);
1636 Result.emplace_back(ObjCNames->Selector);
1637 if (ObjCNames->ClassNameNoCategory)
1638 Result.emplace_back(*ObjCNames->ClassNameNoCategory);
1639 if (ObjCNames->MethodNameNoCategory)
1640 Result.push_back(std::move(*ObjCNames->MethodNameNoCategory));
1643 }
else if (
DIE.
getTag() == dwarf::DW_TAG_namespace)
1644 Result.emplace_back(
"(anonymous namespace)");
1646 if (IncludeLinkageName) {
1647 if (
const char *Str =
DIE.getLinkageName())
1648 Result.emplace_back(Str);
1654void DWARFVerifier::verifyNameIndexEntries(
1660 ErrorCategory.Report(
"Unable to get string associated with name", [&]() {
1661 error() <<
formatv(
"Name Index @ {0:x}: Unable to get string associated "
1667 StringRef Str(CStr);
1670 uint64_t NextEntryID = EntryID;
1671 Expected<DWARFDebugNames::Entry> EntryOr = NI.
getEntry(&NextEntryID);
1672 for (; EntryOr; ++
NumEntries, EntryID = NextEntryID,
1673 EntryOr = NI.
getEntry(&NextEntryID)) {
1675 std::optional<uint64_t> CUIndex = EntryOr->getRelatedCUIndex();
1676 std::optional<uint64_t> TUIndex = EntryOr->getTUIndex();
1677 if (CUIndex && *CUIndex >= NI.
getCUCount()) {
1678 ErrorCategory.Report(
"Name Index entry contains invalid CU index", [&]() {
1679 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1680 "invalid CU index ({2}).\n",
1687 if (TUIndex && *TUIndex >= (NumLocalTUs + NumForeignTUs)) {
1688 ErrorCategory.Report(
"Name Index entry contains invalid TU index", [&]() {
1689 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1690 "invalid TU index ({2}).\n",
1695 std::optional<uint64_t> UnitOffset;
1698 if (*TUIndex >= NumLocalTUs) {
1711 ErrorCategory.Report(
1712 "Name Index entry contains foreign TU index with invalid CU "
1716 "Name Index @ {0:x}: Entry @ {1:x} contains an "
1717 "foreign TU index ({2}) with no CU index.\n",
1726 }
else if (CUIndex) {
1732 if (!UnitOffset || UnitOffset == UINT32_MAX)
1737 DWARFUnit *DU = DCtx.getUnitForOffset(*UnitOffset);
1738 if (DU ==
nullptr || DU->
getOffset() != *UnitOffset) {
1741 ErrorCategory.Report(
1742 "Name Index entry contains invalid CU or TU offset", [&]() {
1743 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1744 "invalid CU or TU offset {2:x}.\n",
1760 DWARFUnit *NonSkeletonUnit =
nullptr;
1763 NonSkeletonUnit = Iter->second;
1765 NonSkeletonUnit = DU;
1769 ErrorCategory.Report(
"Unable to get load .dwo file", [&]() {
1771 "Name Index @ {0:x}: Entry @ {1:x} unable to load "
1772 ".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
1780 if (TUIndex && *TUIndex >= NumLocalTUs) {
1788 const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs;
1790 llvm::DWARFContext &NonSkeletonDCtx = NonSkeletonUnit->
getContext();
1798 if (NonSkeletonDCtx.
isDWP()) {
1799 DWARFDie NonSkeletonUnitDie = NonSkeletonUnit->
getUnitDIE(
true);
1801 UnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1803 NonSkeletonUnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1804 if (DUDwoName != TUDwoName)
1808 uint64_t DIEOffset =
1809 NonSkeletonUnit->
getOffset() + *EntryOr->getDIEUnitOffset();
1813 if (DIEOffset >= NextUnitOffset) {
1814 ErrorCategory.Report(
"NameIndex relative DIE offset too large", [&]() {
1815 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1816 "DIE @ {2:x} when CU or TU ends at {3:x}.\n",
1824 ErrorCategory.Report(
"NameIndex references nonexistent DIE", [&]() {
1825 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1826 "non-existing DIE @ {2:x}.\n",
1837 ErrorCategory.Report(
"Name index contains mismatched CU of DIE", [&]() {
1839 "Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
1840 "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
1845 if (DIE.
getTag() != EntryOr->tag()) {
1846 ErrorCategory.Report(
"Name Index contains mismatched Tag of DIE", [&]() {
1848 "Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
1849 "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1857 auto IncludeStrippedTemplateNames =
1858 DIE.
getTag() == DW_TAG_subprogram ||
1859 DIE.
getTag() == DW_TAG_inlined_subroutine;
1860 auto EntryNames =
getNames(DIE, IncludeStrippedTemplateNames);
1862 ErrorCategory.Report(
"Name Index contains mismatched name of DIE", [&]() {
1863 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
1864 "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1866 make_range(EntryNames.begin(), EntryNames.end()));
1871 EntryOr.takeError(),
1872 [&](
const DWARFDebugNames::SentinelError &) {
1875 ErrorCategory.Report(
1876 "NameIndex Name is not associated with any entries", [&]() {
1877 error() << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
1878 "not associated with any entries.\n",
1879 NI.getUnitOffset(), NTE.getIndex(), Str);
1883 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
1884 error() <<
formatv(
"Name Index @ {0:x}: Name {1} ({2}): {3}\n",
1899 for (
const auto &Entry : *
Loc) {
1901 U->getAddressByteSize());
1903 U->getFormParams().Format);
1904 bool IsInteresting =
1906 return !
Op.isError() && (
Op.getCode() == DW_OP_addr ||
1907 Op.getCode() == DW_OP_form_tls_address ||
1908 Op.getCode() == DW_OP_GNU_push_tls_address);
1916void DWARFVerifier::verifyNameIndexCompleteness(
1925 if (Die.
find(DW_AT_declaration))
1935 auto IncludeLinkageName = Die.
getTag() == DW_TAG_subprogram ||
1936 Die.
getTag() == DW_TAG_inlined_subroutine;
1939 auto IncludeStrippedTemplateNames =
false;
1940 auto IncludeObjCNames =
false;
1941 auto EntryNames =
getNames(Die, IncludeStrippedTemplateNames,
1942 IncludeObjCNames, IncludeLinkageName);
1943 if (EntryNames.empty())
1953 case DW_TAG_compile_unit:
1959 case DW_TAG_formal_parameter:
1960 case DW_TAG_template_value_parameter:
1961 case DW_TAG_template_type_parameter:
1962 case DW_TAG_GNU_template_parameter_pack:
1963 case DW_TAG_GNU_template_template_param:
1973 case DW_TAG_enumerator:
1978 case DW_TAG_imported_declaration:
1984 case DW_TAG_subprogram:
1985 case DW_TAG_inlined_subroutine:
1988 {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
1997 case DW_TAG_variable:
2009 for (StringRef Name : EntryNames) {
2010 auto iter = NamesToDieOffsets.find(Name);
2011 if (iter == NamesToDieOffsets.end() || !iter->second.count(DieUnitOffset)) {
2012 ErrorCategory.Report(
2013 "Name Index DIE entry missing name",
2016 "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
2017 "name {3} missing.\n",
2018 NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name);
2030 CUTU->getBaseAddress();
2033 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2034 DCtx.getRecoverableErrorHandler()(std::move(E));
2040 if (!
CU->getDWOId())
2043 CU->getNonSkeletonUnitDIE().getDwarfUnit()->getContext();
2045 for (
auto &CUTU : NonSkeletonContext.
dwo_units()) {
2047 CUTU->getBaseAddress();
2050 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2051 DCtx.getRecoverableErrorHandler()(std::move(E));
2054 if (NonSkeletonContext.
isDWP())
2059void DWARFVerifier::verifyDebugNames(
const DWARFSection &AccelSection,
2061 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,
2062 DCtx.isLittleEndian(), 0);
2063 DWARFDebugNames AccelTable(AccelSectionData, StrData);
2065 OS <<
"Verifying .debug_names...\n";
2070 std::string Msg =
toString(std::move(
E));
2071 ErrorCategory.Report(
"Accelerator Table Error",
2072 [&]() {
error() << Msg <<
'\n'; });
2075 const uint64_t OriginalNumErrors = ErrorCategory.GetNumErrors();
2076 verifyDebugNamesCULists(AccelTable);
2077 for (
const auto &NI : AccelTable)
2078 verifyNameIndexBuckets(NI, StrData);
2079 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
2080 verifyNameIndexAbbrevs(NI);
2084 if (OriginalNumErrors != ErrorCategory.GetNumErrors())
2086 DenseMap<uint64_t, DWARFUnit *> CUOffsetsToDUMap;
2087 for (
const auto &CU : DCtx.compile_units()) {
2088 if (!(CU->getVersion() >= 5 && CU->getDWOId()))
2090 CUOffsetsToDUMap[CU->getOffset()] =
2091 CU->getNonSkeletonUnitDIE().getDwarfUnit();
2094 for (
const DWARFDebugNames::NameIndex &NI : AccelTable) {
2096 verifyNameIndexEntries(NI, NTE, CUOffsetsToDUMap);
2100 auto populateNameToOffset =
2101 [&](
const DWARFDebugNames::NameIndex &NI,
2102 StringMap<DenseSet<uint64_t>> &NamesToDieOffsets) {
2103 for (
const DWARFDebugNames::NameTableEntry &NTE : NI) {
2105 const std::string
Name = tName ? std::string(tName) :
"";
2107 Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&EntryID);
2108 auto Iter = NamesToDieOffsets.insert({
Name, DenseSet<uint64_t>(3)});
2109 for (; EntryOr; EntryOr = NI.getEntry(&EntryID)) {
2110 if (std::optional<uint64_t> DieOffset = EntryOr->getDIEUnitOffset())
2111 Iter.first->second.insert(*DieOffset);
2115 [&](
const DWARFDebugNames::SentinelError &) {
2116 if (!NamesToDieOffsets.empty())
2118 ErrorCategory.Report(
2119 "NameIndex Name is not associated with any entries", [&]() {
2121 << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
2122 "not associated with any entries.\n",
2123 NI.getUnitOffset(), NTE.getIndex(), Name);
2126 [&](
const ErrorInfoBase &
Info) {
2127 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
2129 "Name Index @ {0:x}: Name {1} ({2}): {3}\n",
2130 NI.getUnitOffset(), NTE.
getIndex(), Name,
Info.message());
2139 populateNameToOffset(NI, NamesToDieOffsets);
2140 for (uint32_t i = 0, iEnd = NI.getCUCount(); i < iEnd; ++i) {
2141 const uint64_t CUOffset = NI.getCUOffset(i);
2142 DWARFUnit *
U = DCtx.getUnitForOffset(CUOffset);
2149 if (CUDie != NonSkeletonUnitDie) {
2153 verifyNameIndexCompleteness(
2154 DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), NI,
2160 verifyNameIndexCompleteness(DWARFDie(CU, &Die), NI,
2171 DataExtractor StrData(
D.getStrSection(), DCtx.isLittleEndian(), 0);
2172 if (!
D.getAppleNamesSection().Data.empty())
2173 verifyAppleAccelTable(&
D.getAppleNamesSection(), &StrData,
".apple_names");
2174 if (!
D.getAppleTypesSection().Data.empty())
2175 verifyAppleAccelTable(&
D.getAppleTypesSection(), &StrData,
".apple_types");
2176 if (!
D.getAppleNamespacesSection().Data.empty())
2177 verifyAppleAccelTable(&
D.getAppleNamespacesSection(), &StrData,
2178 ".apple_namespaces");
2179 if (!
D.getAppleObjCSection().Data.empty())
2180 verifyAppleAccelTable(&
D.getAppleObjCSection(), &StrData,
".apple_objc");
2182 if (!
D.getNamesSection().Data.empty())
2183 verifyDebugNames(
D.getNamesSection(), StrData);
2184 return ErrorCategory.GetNumErrors() == 0;
2188 OS <<
"Verifying .debug_str_offsets...\n";
2197 std::optional<DwarfFormat> DwoLegacyDwarf4Format;
2199 if (DwoLegacyDwarf4Format)
2205 DwoLegacyDwarf4Format = InfoFormat;
2209 DwoLegacyDwarf4Format,
".debug_str_offsets.dwo",
2212 std::nullopt,
".debug_str_offsets",
2226 while (
C.seek(NextUnit),
C.tell() < DA.getData().size()) {
2232 Length = DA.getData().size();
2238 if (
C.tell() +
Length > DA.getData().size()) {
2239 ErrorCategory.Report(
2240 "Section contribution length exceeds available space", [&]() {
2242 "{0}: contribution {1:X}: length exceeds available space "
2244 "offset ({1:X}) + length field space ({2:X}) + length "
2246 "{4:X} > section size {5:X})\n",
2248 C.tell() +
Length, DA.getData().size());
2257 ErrorCategory.Report(
"Invalid Section version", [&]() {
2258 error() <<
formatv(
"{0}: contribution {1:X}: invalid version {2}\n",
2269 DA.setAddressSize(OffsetByteSize);
2271 if (Remainder != 0) {
2272 ErrorCategory.Report(
"Invalid section contribution length", [&]() {
2274 "{0}: contribution {1:X}: invalid length ((length ({2:X}) "
2275 "- header (0x4)) % offset size {3:X} == {4:X} != 0)\n",
2286 if (StrData.
size() <= StrOff) {
2287 ErrorCategory.Report(
2288 "String offset out of bounds of string section", [&]() {
2290 "{0}: contribution {1:X}: index {2:X}: invalid string "
2291 "offset *{3:X} == {4:X}, is beyond the bounds of the string "
2292 "section of length {5:X}\n",
2298 if (StrData[StrOff - 1] ==
'\0')
2300 ErrorCategory.Report(
2301 "Section contribution contains invalid string offset", [&]() {
2303 "{0}: contribution {1:X}: index {2:X}: invalid string "
2304 "offset *{3:X} == {4:X}, is neither zero nor "
2305 "immediately following a null character\n",
2312 if (
Error E =
C.takeError()) {
2313 std::string Msg =
toString(std::move(E));
2314 ErrorCategory.Report(
"String offset error", [&]() {
2323 StringRef s, std::function<
void(
void)> detailCallback) {
2324 this->
Report(s,
"", detailCallback);
2329 std::function<
void(
void)> detailCallback) {
2330 std::lock_guard<std::mutex> Lock(WriteMutex);
2332 std::string category_str = std::string(category);
2335 if (!sub_category.
empty()) {
2343 std::function<
void(
StringRef,
unsigned)> handleCounts) {
2344 for (
const auto &[
name, aggData] : Aggregation) {
2345 handleCounts(
name, aggData.OverallCount);
2350 const auto Agg = Aggregation.find(category);
2351 if (Agg != Aggregation.end()) {
2353 handleCounts(
name, aggData);
2359 if (DumpOpts.ShowAggregateErrors && ErrorCategory.GetNumCategories()) {
2360 error() <<
"Aggregated error counts:\n";
2361 ErrorCategory.EnumerateResults([&](
StringRef s,
unsigned count) {
2365 if (!DumpOpts.JsonErrSummaryFile.empty()) {
2371 "unable to open json summary file {0} for writing: {1}\n",
2372 DumpOpts.JsonErrSummaryFile, EC.message());
2378 ErrorCategory.EnumerateResults([&](
StringRef Category,
unsigned Count) {
2382 ErrorCategory.EnumerateDetailedResultsFor(
2383 Category, [&](
StringRef SubCategory,
unsigned SubCount) {
2388 ErrorCount +=
Count;
2391 RootNode.
try_emplace(
"error-categories", std::move(Categories));
2405 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.