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;
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);
276 <<
" 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() <<
"Compilation unit root DIE is not a unit DIE: "
303 ErrorCategory.Report(
"Mismatched unit type", [&]() {
306 <<
") 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() <<
"Abbreviation declaration contains multiple "
404 OS <<
"Verifying .debug_abbrev...\n";
407 unsigned NumErrors = 0;
409 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
411 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
413 return NumErrors == 0;
417 unsigned NumDebugInfoErrors = 0;
418 ReferenceMap CrossUnitReferences;
421 for (
const auto &Unit : Units) {
422 OS <<
"Verifying unit: " <<
Index <<
" / " << Units.getNumUnits();
423 if (
const char* Name = Unit->getUnitDIE(
true).getShortName())
424 OS <<
", \"" << Name <<
'\"';
427 ReferenceMap UnitLocalReferences;
428 NumDebugInfoErrors +=
429 verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences);
430 NumDebugInfoErrors += verifyDebugInfoReferences(
431 UnitLocalReferences, [&](
uint64_t Offset) {
return Unit.get(); });
435 NumDebugInfoErrors += verifyDebugInfoReferences(
436 CrossUnitReferences, [&](uint64_t
Offset) -> DWARFUnit * {
437 if (DWARFUnit *U = Units.getUnitForOffset(
Offset))
442 return NumDebugInfoErrors;
445unsigned DWARFVerifier::verifyUnitSection(
const DWARFSection &S) {
446 const DWARFObject &DObj = DCtx.getDWARFObj();
447 DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);
448 unsigned NumDebugInfoErrors = 0;
449 uint64_t
Offset = 0, UnitIdx = 0;
451 bool isUnitDWARF64 =
false;
452 bool isHeaderChainValid =
true;
454 DWARFUnitVector TypeUnitVector;
455 DWARFUnitVector CompileUnitVector;
459 isHeaderChainValid =
false;
466 if (UnitIdx == 0 && !hasDIE) {
467 warn() <<
"Section is empty.\n";
468 isHeaderChainValid =
true;
470 if (!isHeaderChainValid)
471 ++NumDebugInfoErrors;
472 return NumDebugInfoErrors;
475unsigned DWARFVerifier::verifyIndex(StringRef Name,
477 StringRef IndexStr) {
478 if (IndexStr.
empty())
480 OS <<
"Verifying " <<
Name <<
"...\n";
481 DWARFUnitIndex
Index(InfoColumnKind);
482 DataExtractor
D(IndexStr, DCtx.isLittleEndian(), 0);
485 using MapType = IntervalMap<uint64_t, uint64_t>;
486 MapType::Allocator
Alloc;
487 std::vector<std::unique_ptr<MapType>> Sections(
Index.getColumnKinds().size());
488 for (
const DWARFUnitIndex::Entry &
E :
Index.getRows()) {
489 uint64_t Sig =
E.getSignature();
490 if (!
E.getContributions())
493 InfoColumnKind == DW_SECT_INFO
496 const DWARFUnitIndex::Entry::SectionContribution &SC =
E.value();
501 Sections[Col] = std::make_unique<MapType>(
Alloc);
502 auto &
M = *Sections[Col];
505 StringRef Category = InfoColumnKind == DWARFSectionKind::DW_SECT_INFO
506 ?
"Overlapping CU index entries"
507 :
"Overlapping TU index entries";
508 ErrorCategory.Report(Category, [&]() {
510 "overlapping index entries for entries {0:x16} "
511 "and {1:x16} for column {2}\n",
524 return verifyIndex(
".debug_cu_index", DWARFSectionKind::DW_SECT_INFO,
525 DCtx.getDWARFObj().getCUIndexSection()) == 0;
530 DCtx.getDWARFObj().getTUIndexSection()) == 0;
535 unsigned NumErrors = 0;
537 OS <<
"Verifying .debug_info Unit Header Chain...\n";
539 NumErrors += verifyUnitSection(S);
542 OS <<
"Verifying .debug_types Unit Header Chain...\n";
544 NumErrors += verifyUnitSection(S);
547 OS <<
"Verifying non-dwo Units...\n";
548 NumErrors += verifyUnits(DCtx.getNormalUnitsVector());
550 OS <<
"Verifying dwo Units...\n";
551 NumErrors += verifyUnits(DCtx.getDWOUnitsVector());
552 return NumErrors == 0;
555unsigned DWARFVerifier::verifyDieRanges(
const DWARFDie &Die,
556 DieRangeInfo &ParentRI) {
557 unsigned NumErrors = 0;
565 if (!RangesOrError) {
567 if (!Unit->isDWOUnit())
576 DieRangeInfo RI(Die);
597 if (!IsObjectFile || IsMachOObject || Die.
getTag() != DW_TAG_compile_unit) {
598 bool DumpDieAfterError =
false;
599 for (
const auto &
Range : Ranges) {
600 if (!
Range.valid()) {
602 ErrorCategory.
Report(
"Invalid address range", [&]() {
603 error() <<
"Invalid address range " <<
Range <<
"\n";
604 DumpDieAfterError =
true;
615 if (
auto PrevRange = RI.insert(
Range)) {
617 ErrorCategory.Report(
"DIE has overlapping DW_AT_ranges", [&]() {
618 error() <<
"DIE has overlapping ranges in DW_AT_ranges attribute: "
619 << *PrevRange <<
" and " <<
Range <<
'\n';
620 DumpDieAfterError =
true;
624 if (DumpDieAfterError)
625 dump(Die, 2) <<
'\n';
629 const auto IntersectingChild = ParentRI.insert(RI);
630 if (IntersectingChild != ParentRI.Children.end()) {
632 ErrorCategory.Report(
"DIEs have overlapping address ranges", [&]() {
633 error() <<
"DIEs have overlapping address ranges:";
635 dump(IntersectingChild->Die) <<
'\n';
640 bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() &&
641 !(Die.
getTag() == DW_TAG_subprogram &&
642 ParentRI.Die.getTag() == DW_TAG_subprogram);
643 if (ShouldBeContained && !ParentRI.contains(RI)) {
645 ErrorCategory.Report(
646 "DIE address ranges are not contained by parent ranges", [&]() {
648 <<
"DIE address ranges are not contained in its parent's ranges:";
650 dump(Die, 2) <<
'\n';
655 for (DWARFDie Child : Die)
656 NumErrors += verifyDieRanges(Child, RI);
661bool DWARFVerifier::verifyExpressionOp(
const DWARFExpression::Operation &
Op,
663 for (
unsigned Operand = 0; Operand <
Op.Desc.
Op.
size(); ++Operand) {
664 unsigned Size =
Op.Desc.
Op[Operand];
671 if (
Op.Opcode == DW_OP_convert &&
Op.Operands[Operand] == 0)
673 auto Die =
U->getDIEForOffset(
U->getOffset() +
Op.Operands[Operand]);
674 if (!Die || Die.
getTag() != dwarf::DW_TAG_base_type)
682bool DWARFVerifier::verifyExpression(
const DWARFExpression &
E, DWARFUnit *U) {
684 if (!verifyExpressionOp(
Op, U))
690unsigned DWARFVerifier::verifyDebugInfoAttribute(
const DWARFDie &Die,
691 DWARFAttribute &AttrValue) {
692 unsigned NumErrors = 0;
693 auto ReportError = [&](StringRef category,
const Twine &TitleMsg) {
695 ErrorCategory.Report(category, [&]() {
696 error() << TitleMsg <<
'\n';
701 const DWARFObject &DObj = DCtx.getDWARFObj();
703 const auto Attr = AttrValue.
Attr;
708 unsigned DwarfVersion =
U->getVersion();
709 const DWARFSection &RangeSection = DwarfVersion < 5
712 if (
U->isDWOUnit() && RangeSection.
Data.
empty())
714 if (*SectionOffset >= RangeSection.
Data.
size())
715 ReportError(
"DW_AT_ranges offset out of bounds",
716 "DW_AT_ranges offset is beyond " +
717 StringRef(DwarfVersion < 5 ?
".debug_ranges"
718 :
".debug_rnglists") +
722 ReportError(
"Invalid DW_AT_ranges encoding",
723 "DIE has invalid DW_AT_ranges encoding:");
725 case DW_AT_stmt_list:
728 if (*SectionOffset >=
U->getLineSection().Data.size())
729 ReportError(
"DW_AT_stmt_list offset out of bounds",
730 "DW_AT_stmt_list offset is beyond .debug_line bounds: " +
734 ReportError(
"Invalid DW_AT_stmt_list encoding",
735 "DIE has invalid DW_AT_stmt_list encoding:");
737 case DW_AT_location: {
748 if (Expected<std::vector<DWARFLocationExpression>> Loc =
750 for (
const auto &Entry : *Loc) {
752 DWARFExpression Expression(
Data,
U->getAddressByteSize(),
753 U->getFormParams().Format);
755 any_of(Expression, [](
const DWARFExpression::Operation &
Op) {
758 if (
Error || !verifyExpression(Expression, U))
759 ReportError(
"Invalid DWARF expressions",
760 "DIE contains invalid DWARF expression:");
763 Loc.takeError(), [&](std::unique_ptr<ResolverError>
E) {
764 return U->isDWOUnit() ? Error::success()
765 : Error(std::move(E));
767 ReportError(
"Invalid DW_AT_location",
toString(std::move(Err)));
770 case DW_AT_specification:
771 case DW_AT_abstract_origin: {
773 auto DieTag = Die.
getTag();
774 auto RefTag = ReferencedDie.getTag();
775 if (DieTag == RefTag)
777 if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
779 if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
782 if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)
784 ReportError(
"Incompatible DW_AT_abstract_origin tag reference",
785 "DIE with tag " +
TagString(DieTag) +
" has " +
787 " that points to DIE with "
788 "incompatible tag " +
796 ReportError(
"Incompatible DW_AT_type attribute tag",
802 case DW_AT_call_file:
803 case DW_AT_decl_file: {
805 if (
U->isDWOUnit() && !
U->isTypeUnit())
807 const auto *
LT =
U->getContext().getLineTableForUnit(U);
809 if (!
LT->hasFileAtIndex(*FileIdx)) {
810 bool IsZeroIndexed =
LT->Prologue.getVersion() >= 5;
811 if (std::optional<uint64_t> LastFileIdx =
812 LT->getLastValidFileIndex()) {
813 ReportError(
"Invalid file index in DW_AT_decl_file",
815 " with an invalid file index " +
817 " (valid values are [" +
818 (IsZeroIndexed ?
"0-" :
"1-") +
821 ReportError(
"Invalid file index in DW_AT_decl_file",
823 " with an invalid file index " +
825 " (the file table in the prologue is empty)");
830 "File index in DW_AT_decl_file reference CU with no line table",
832 " that references a file with index " +
834 " and the compile unit has no line table");
837 ReportError(
"Invalid encoding in DW_AT_decl_file",
839 " with invalid encoding");
843 case DW_AT_call_line:
844 case DW_AT_decl_line: {
847 Attr == DW_AT_call_line ?
"Invalid file index in DW_AT_decl_line"
848 :
"Invalid file index in DW_AT_call_line",
853 case DW_AT_LLVM_stmt_sequence: {
857 if (!SectionOffset) {
858 ReportError(
"Invalid DW_AT_LLVM_stmt_sequence encoding",
859 "DIE has invalid DW_AT_LLVM_stmt_sequence encoding");
862 if (*SectionOffset >=
U->getLineSection().Data.size()) {
864 "DW_AT_LLVM_stmt_sequence offset out of bounds",
865 "DW_AT_LLVM_stmt_sequence offset is beyond .debug_line bounds: " +
871 const auto *LineTable = DCtx.getLineTableForUnit(U);
873 ReportError(
"DW_AT_LLVM_stmt_sequence without line table",
874 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
880 DWARFDie CUDie =
U->getUnitDIE();
882 if (!StmtListOffset) {
883 ReportError(
"DW_AT_LLVM_stmt_sequence without DW_AT_stmt_list",
884 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "
889 const int8_t DwarfOffset =
890 LineTable->Prologue.getFormParams().getDwarfOffsetByteSize();
892 uint64_t LineTableStart = *StmtListOffset;
893 uint64_t PrologueLength = LineTable->Prologue.PrologueLength;
894 uint64_t TotalLength = LineTable->Prologue.TotalLength;
895 uint64_t LineTableEnd = LineTableStart + TotalLength + DwarfOffset;
900 uint64_t InitialLengthSize = DwarfOffset;
902 uint64_t VersionSize = 2;
903 uint64_t PrologueLengthSize = DwarfOffset;
904 uint64_t SequencesStart = LineTableStart + InitialLengthSize + VersionSize +
905 PrologueLengthSize + PrologueLength;
908 if (*SectionOffset < SequencesStart || *SectionOffset >= LineTableEnd) {
909 ReportError(
"DW_AT_LLVM_stmt_sequence offset out of line table bounds",
910 "DW_AT_LLVM_stmt_sequence offset " +
912 " is not within the line table bounds [" +
920 [SectionOffset](
const auto &Sequence) {
921 return Sequence.StmtSeqOffset == *SectionOffset;
924 if (It == LineTable->Sequences.end())
926 "Invalid DW_AT_LLVM_stmt_sequence offset",
927 "DW_AT_LLVM_stmt_sequence offset " +
929 " does not point to a valid sequence offset in the line table");
938unsigned DWARFVerifier::verifyDebugInfoForm(
const DWARFDie &Die,
939 DWARFAttribute &AttrValue,
940 ReferenceMap &LocalReferences,
941 ReferenceMap &CrossUnitReferences) {
943 unsigned NumErrors = 0;
950 case DW_FORM_ref_udata: {
955 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
957 if (CUOffset >= CUSize) {
959 ErrorCategory.Report(
"Invalid CU offset", [&]() {
961 <<
format(
"0x%08" PRIx64, CUOffset)
962 <<
" is invalid (must be less than CU size of "
963 <<
format(
"0x%08" PRIx64, CUSize) <<
"):\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", [&]() {
1008 error() << ErrMsg <<
":\n";
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", [&]() {
1035 error() <<
"invalid DIE reference " <<
format(
"0x%08" PRIx64, Pair.first)
1036 <<
". Offset is in between DIEs:\n";
1037 for (
auto Offset : Pair.second)
1045void DWARFVerifier::verifyDebugLineStmtOffsets() {
1046 std::map<uint64_t, DWARFDie> StmtListToDie;
1047 for (
const auto &CU : DCtx.compile_units()) {
1048 auto Die = CU->getUnitDIE();
1053 if (!StmtSectionOffset)
1055 const uint64_t LineTableOffset = *StmtSectionOffset;
1056 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1057 if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
1059 ++NumDebugLineErrors;
1060 ErrorCategory.Report(
"Unparsable .debug_line entry", [&]() {
1061 error() <<
".debug_line[" <<
format(
"0x%08" PRIx64, LineTableOffset)
1062 <<
"] was not able to be parsed for CU:\n";
1069 assert(LineTable ==
nullptr);
1074 auto [Iter,
Inserted] = StmtListToDie.try_emplace(LineTableOffset, Die);
1076 ++NumDebugLineErrors;
1077 const auto &OldDie = Iter->second;
1078 ErrorCategory.Report(
"Identical DW_AT_stmt_list section offset", [&]() {
1079 error() <<
"two compile unit DIEs, "
1080 <<
format(
"0x%08" PRIx64, OldDie.getOffset()) <<
" and "
1082 <<
", have the same DW_AT_stmt_list section offset:\n";
1091void DWARFVerifier::verifyDebugLineRows() {
1092 for (
const auto &CU : DCtx.compile_units()) {
1093 auto Die = CU->getUnitDIE();
1094 auto LineTable = DCtx.getLineTableForUnit(CU.get());
1101 bool isDWARF5 = LineTable->Prologue.getVersion() >= 5;
1102 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
1103 uint32_t MinFileIndex = isDWARF5 ? 0 : 1;
1104 uint32_t FileIndex = MinFileIndex;
1105 StringMap<uint16_t> FullPathMap;
1106 for (
const auto &FileName : LineTable->Prologue.FileNames) {
1108 if (FileName.DirIdx > MaxDirIndex) {
1109 ++NumDebugLineErrors;
1110 ErrorCategory.Report(
1111 "Invalid index in .debug_line->prologue.file_names->dir_idx",
1113 error() <<
".debug_line["
1114 <<
format(
"0x%08" PRIx64,
1116 <<
"].prologue.file_names[" << FileIndex
1117 <<
"].dir_idx contains an invalid index: "
1118 << FileName.DirIdx <<
"\n";
1123 std::string FullPath;
1124 const bool HasFullPath = LineTable->getFileNameByIndex(
1125 FileIndex, CU->getCompilationDir(),
1127 assert(HasFullPath &&
"Invalid index?");
1130 if (!Inserted && It->second != FileIndex && DumpOpts.Verbose) {
1131 warn() <<
".debug_line["
1132 <<
format(
"0x%08" PRIx64,
1134 <<
"].prologue.file_names[" << FileIndex
1135 <<
"] is a duplicate of file_names[" << It->second <<
"]\n";
1143 if (LineTable->Rows.size() == 1 && LineTable->Rows.front().EndSequence)
1147 uint64_t PrevAddress = 0;
1148 uint32_t RowIndex = 0;
1149 for (
const auto &Row : LineTable->Rows) {
1151 if (Row.Address.Address < PrevAddress) {
1152 ++NumDebugLineErrors;
1153 ErrorCategory.Report(
1154 "decreasing address between debug_line rows", [&]() {
1155 error() <<
".debug_line["
1156 <<
format(
"0x%08" PRIx64,
1158 <<
"] row[" << RowIndex
1159 <<
"] decreases in address from previous row:\n";
1163 LineTable->Rows[RowIndex - 1].dump(OS);
1169 if (!LineTable->hasFileAtIndex(Row.File)) {
1170 ++NumDebugLineErrors;
1171 ErrorCategory.Report(
"Invalid file index in debug_line", [&]() {
1172 error() <<
".debug_line["
1173 <<
format(
"0x%08" PRIx64,
1175 <<
"][" << RowIndex <<
"] has invalid file index " << Row.File
1176 <<
" (valid values are [" << MinFileIndex <<
','
1177 << LineTable->Prologue.FileNames.size()
1178 << (isDWARF5 ?
")" :
"]") <<
"):\n";
1184 if (Row.EndSequence)
1187 PrevAddress = Row.Address.Address;
1195 : OS(S), DCtx(
D), DumpOpts(
std::
move(DumpOpts)), IsObjectFile(
false),
1196 IsMachOObject(
false) {
1197 ErrorCategory.ShowDetail(this->DumpOpts.
Verbose ||
1198 !this->DumpOpts.ShowAggregateErrors);
1199 if (
const auto *
F = DCtx.getDWARFObj().getFile()) {
1200 IsObjectFile = F->isRelocatableObject();
1201 IsMachOObject = F->isMachO();
1206 NumDebugLineErrors = 0;
1207 OS <<
"Verifying .debug_line...\n";
1208 verifyDebugLineStmtOffsets();
1209 verifyDebugLineRows();
1210 return NumDebugLineErrors == 0;
1213void DWARFVerifier::verifyAppleAccelTable(
const DWARFSection *AccelSection,
1223 if (!AccelSectionData.isValidOffset(
AccelTable.getSizeHdr())) {
1224 ErrorCategory.
Report(
"Section is too small to fit a section header", [&]() {
1225 error() <<
"Section is too small to fit a section header.\n";
1231 if (
Error E = AccelTable.extract()) {
1232 std::string Msg =
toString(std::move(
E));
1233 ErrorCategory.Report(
"Section is too small to fit a section header",
1234 [&]() {
error() << Msg <<
'\n'; });
1239 uint32_t NumBuckets = AccelTable.getNumBuckets();
1240 uint32_t NumHashes = AccelTable.getNumHashes();
1242 uint64_t BucketsOffset =
1243 AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
1244 uint64_t HashesBase = BucketsOffset + NumBuckets * 4;
1245 uint64_t OffsetsBase = HashesBase + NumHashes * 4;
1246 for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
1247 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
1248 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
1249 ErrorCategory.Report(
"Invalid hash index", [&]() {
1250 error() <<
format(
"Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
1255 uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
1256 if (NumAtoms == 0) {
1257 ErrorCategory.Report(
"No atoms", [&]() {
1258 error() <<
"No atoms: failed to read HashData.\n";
1262 if (!AccelTable.validateForms()) {
1263 ErrorCategory.Report(
"Unsupported form", [&]() {
1264 error() <<
"Unsupported form: failed to read HashData.\n";
1269 for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
1270 uint64_t HashOffset = HashesBase + 4 * HashIdx;
1271 uint64_t DataOffset = OffsetsBase + 4 * HashIdx;
1272 uint32_t Hash = AccelSectionData.getU32(&HashOffset);
1273 uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
1274 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
1275 sizeof(uint64_t))) {
1276 ErrorCategory.Report(
"Invalid HashData offset", [&]() {
1277 error() <<
format(
"Hash[%d] has invalid HashData offset: "
1278 "0x%08" PRIx64
".\n",
1279 HashIdx, HashDataOffset);
1283 uint64_t StrpOffset;
1284 uint64_t StringOffset;
1285 uint32_t StringCount = 0;
1288 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
1289 const uint32_t NumHashDataObjects =
1290 AccelSectionData.getU32(&HashDataOffset);
1291 for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
1293 std::tie(
Offset,
Tag) = AccelTable.readAtoms(&HashDataOffset);
1294 auto Die = DCtx.getDIEForOffset(
Offset);
1296 const uint32_t BucketIdx =
1297 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
1298 StringOffset = StrpOffset;
1299 const char *
Name = StrData->
getCStr(&StringOffset);
1303 ErrorCategory.Report(
"Invalid DIE offset", [&]() {
1305 "%s Bucket[%d] Hash[%d] = 0x%08x "
1306 "Str[%u] = 0x%08" PRIx64
" DIE[%d] = 0x%08" PRIx64
" "
1307 "is not a valid DIE offset for \"%s\".\n",
1308 SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
1309 HashDataIdx,
Offset, Name);
1313 if ((
Tag != dwarf::DW_TAG_null) && (Die.
getTag() !=
Tag)) {
1314 ErrorCategory.Report(
"Mismatched Tag in accellerator table", [&]() {
1316 <<
" in accelerator table does not match Tag "
1318 << HashDataIdx <<
"].\n";
1329 DenseMap<uint64_t, uint64_t> CUMap;
1330 CUMap.
reserve(DCtx.getNumCompileUnits());
1332 DenseSet<uint64_t> CUOffsets;
1333 for (
const auto &CU : DCtx.compile_units())
1334 CUOffsets.
insert(CU->getOffset());
1336 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
1338 ErrorCategory.Report(
"Name Index doesn't index any CU", [&]() {
1339 error() <<
formatv(
"Name Index @ {0:x} does not index any CU\n",
1344 for (uint32_t CU = 0, End = NI.
getCUCount(); CU < End; ++CU) {
1347 ErrorCategory.Report(
"Name Index references non-existing CU", [&]() {
1349 "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
1354 uint64_t DuplicateCUOffset = 0;
1356 std::lock_guard<std::mutex> Lock(AccessMutex);
1358 if (Iter != CUMap.
end())
1359 DuplicateCUOffset = Iter->second;
1363 if (DuplicateCUOffset) {
1364 ErrorCategory.Report(
"Duplicate Name Index", [&]() {
1366 "Name Index @ {0:x} references a CU @ {1:x}, but "
1367 "this CU is already indexed by Name Index @ {2:x}\n",
1375 for (
const auto &CU : DCtx.compile_units()) {
1376 if (CUMap.
count(CU->getOffset()) == 0)
1377 warn() <<
formatv(
"CU @ {0:x} not covered by any Name Index\n",
1388 constexpr BucketInfo(uint32_t Bucket, uint32_t
Index)
1394 warn() <<
formatv(
"Name Index @ {0:x} does not contain a hash table.\n",
1401 std::vector<BucketInfo> BucketStarts;
1403 const uint64_t OrigNumberOfErrors = ErrorCategory.GetNumErrors();
1404 for (uint32_t Bucket = 0, End = NI.
getBucketCount(); Bucket < End; ++Bucket) {
1407 ErrorCategory.Report(
"Name Index Bucket contains invalid value", [&]() {
1408 error() <<
formatv(
"Bucket {0} of Name Index @ {1:x} contains invalid "
1409 "value {2}. Valid range is [0, {3}].\n",
1416 BucketStarts.emplace_back(Bucket,
Index);
1422 if (OrigNumberOfErrors != ErrorCategory.GetNumErrors())
1435 uint32_t NextUncovered = 1;
1436 for (
const BucketInfo &
B : BucketStarts) {
1443 if (
B.Index > NextUncovered) {
1444 ErrorCategory.Report(
"Name table entries uncovered by hash table", [&]() {
1445 error() <<
formatv(
"Name Index @ {0:x}: Name table entries [{1}, {2}] "
1446 "are not covered by the hash table.\n",
1450 uint32_t Idx =
B.Index;
1463 ErrorCategory.Report(
"Name Index point to mismatched hash value", [&]() {
1465 "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
1466 "mismatched hash value {2:x} (belonging to bucket {3}).\n",
1482 ErrorCategory.Report(
1483 "String hash doesn't match Name Index hash", [&]() {
1485 "Name Index @ {0:x}: String ({1}) at index {2} "
1486 "hashes to {3:x}, but "
1487 "the Name Index hash is {4:x}\n",
1493 NextUncovered = std::max(NextUncovered, Idx);
1497void DWARFVerifier::verifyNameIndexAttribute(
1501 if (FormName.
empty()) {
1502 ErrorCategory.Report(
"Unknown NameIndex Abbreviation", [&]() {
1503 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1504 "unknown form: {3}.\n",
1511 if (AttrEnc.
Index == DW_IDX_type_hash) {
1512 if (AttrEnc.
Form != dwarf::DW_FORM_data8) {
1513 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1515 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
1516 "uses an unexpected form {2} (should be {3}).\n",
1524 if (AttrEnc.
Index == dwarf::DW_IDX_parent) {
1525 constexpr static auto AllowedForms = {dwarf::Form::DW_FORM_flag_present,
1526 dwarf::Form::DW_FORM_ref4};
1528 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1530 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_parent "
1531 "uses an unexpected form {2} (should be "
1532 "DW_FORM_ref4 or DW_FORM_flag_present).\n",
1543 struct FormClassTable {
1546 StringLiteral ClassName;
1548 static constexpr FormClassTable Table[] = {
1556 return T.Index == AttrEnc.
Index;
1559 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} contains an "
1560 "unknown index attribute: {2}.\n",
1565 if (!DWARFFormValue(AttrEnc.
Form).isFormClass(Iter->Class)) {
1566 ErrorCategory.Report(
"Unexpected NameIndex Abbreviation", [&]() {
1567 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1568 "unexpected form {3} (expected form class {4}).\n",
1570 AttrEnc.
Form, Iter->ClassName);
1576void DWARFVerifier::verifyNameIndexAbbrevs(
1580 if (TagName.
empty()) {
1581 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} references an "
1582 "unknown tag: {2}.\n",
1586 for (
const auto &AttrEnc : Abbrev.Attributes) {
1588 ErrorCategory.Report(
1589 "NameIndex Abbreviateion contains multiple attributes", [&]() {
1591 "NameIndex @ {0:x}: Abbreviation {1:x} contains "
1592 "multiple {2} attributes.\n",
1597 verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
1601 !
Attributes.count(dwarf::DW_IDX_type_unit)) {
1602 ErrorCategory.Report(
"Abbreviation contains no attribute", [&]() {
1603 error() <<
formatv(
"NameIndex @ {0:x}: Indexing multiple compile units "
1604 "and abbreviation {1:x} has no DW_IDX_compile_unit "
1605 "or DW_IDX_type_unit attribute.\n",
1609 if (!
Attributes.count(dwarf::DW_IDX_die_offset)) {
1610 ErrorCategory.Report(
"Abbreviate in NameIndex missing attribute", [&]() {
1612 "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
1622 bool IncludeStrippedTemplateNames,
1623 bool IncludeObjCNames =
true,
1624 bool IncludeLinkageName =
true) {
1626 if (
const char *Str =
DIE.getShortName()) {
1628 Result.emplace_back(Name);
1629 if (IncludeStrippedTemplateNames) {
1630 if (std::optional<StringRef> StrippedName =
1634 Result.push_back(StrippedName->str());
1637 if (IncludeObjCNames) {
1638 if (std::optional<ObjCSelectorNames> ObjCNames =
1640 Result.emplace_back(ObjCNames->ClassName);
1641 Result.emplace_back(ObjCNames->Selector);
1642 if (ObjCNames->ClassNameNoCategory)
1643 Result.emplace_back(*ObjCNames->ClassNameNoCategory);
1644 if (ObjCNames->MethodNameNoCategory)
1645 Result.push_back(std::move(*ObjCNames->MethodNameNoCategory));
1648 }
else if (
DIE.
getTag() == dwarf::DW_TAG_namespace)
1649 Result.emplace_back(
"(anonymous namespace)");
1651 if (IncludeLinkageName) {
1652 if (
const char *Str =
DIE.getLinkageName())
1653 Result.emplace_back(Str);
1659void DWARFVerifier::verifyNameIndexEntries(
1665 ErrorCategory.Report(
"Unable to get string associated with name", [&]() {
1666 error() <<
formatv(
"Name Index @ {0:x}: Unable to get string associated "
1672 StringRef Str(CStr);
1675 uint64_t NextEntryID = EntryID;
1676 Expected<DWARFDebugNames::Entry> EntryOr = NI.
getEntry(&NextEntryID);
1677 for (; EntryOr; ++
NumEntries, EntryID = NextEntryID,
1678 EntryOr = NI.
getEntry(&NextEntryID)) {
1680 std::optional<uint64_t> CUIndex = EntryOr->getRelatedCUIndex();
1681 std::optional<uint64_t> TUIndex = EntryOr->getTUIndex();
1682 if (CUIndex && *CUIndex >= NI.
getCUCount()) {
1683 ErrorCategory.Report(
"Name Index entry contains invalid CU index", [&]() {
1684 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1685 "invalid CU index ({2}).\n",
1692 if (TUIndex && *TUIndex >= (NumLocalTUs + NumForeignTUs)) {
1693 ErrorCategory.Report(
"Name Index entry contains invalid TU index", [&]() {
1694 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1695 "invalid TU index ({2}).\n",
1700 std::optional<uint64_t> UnitOffset;
1703 if (*TUIndex >= NumLocalTUs) {
1716 ErrorCategory.Report(
1717 "Name Index entry contains foreign TU index with invalid CU "
1721 "Name Index @ {0:x}: Entry @ {1:x} contains an "
1722 "foreign TU index ({2}) with no CU index.\n",
1731 }
else if (CUIndex) {
1737 if (!UnitOffset || UnitOffset == UINT32_MAX)
1742 DWARFUnit *DU = DCtx.getUnitForOffset(*UnitOffset);
1743 if (DU ==
nullptr || DU->
getOffset() != *UnitOffset) {
1746 ErrorCategory.Report(
1747 "Name Index entry contains invalid CU or TU offset", [&]() {
1748 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1749 "invalid CU or TU offset {2:x}.\n",
1765 DWARFUnit *NonSkeletonUnit =
nullptr;
1768 NonSkeletonUnit = Iter->second;
1770 NonSkeletonUnit = DU;
1774 ErrorCategory.Report(
"Unable to get load .dwo file", [&]() {
1776 "Name Index @ {0:x}: Entry @ {1:x} unable to load "
1777 ".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
1785 if (TUIndex && *TUIndex >= NumLocalTUs) {
1793 const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs;
1795 llvm::DWARFContext &NonSkeletonDCtx = NonSkeletonUnit->
getContext();
1803 if (NonSkeletonDCtx.
isDWP()) {
1804 DWARFDie NonSkeletonUnitDie = NonSkeletonUnit->
getUnitDIE(
true);
1806 UnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1808 NonSkeletonUnitDie.
find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1809 if (DUDwoName != TUDwoName)
1813 uint64_t DIEOffset =
1814 NonSkeletonUnit->
getOffset() + *EntryOr->getDIEUnitOffset();
1818 if (DIEOffset >= NextUnitOffset) {
1819 ErrorCategory.Report(
"NameIndex relative DIE offset too large", [&]() {
1820 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1821 "DIE @ {2:x} when CU or TU ends at {3:x}.\n",
1829 ErrorCategory.Report(
"NameIndex references nonexistent DIE", [&]() {
1830 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1831 "non-existing DIE @ {2:x}.\n",
1842 ErrorCategory.Report(
"Name index contains mismatched CU of DIE", [&]() {
1844 "Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
1845 "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
1850 if (DIE.
getTag() != EntryOr->tag()) {
1851 ErrorCategory.Report(
"Name Index contains mismatched Tag of DIE", [&]() {
1853 "Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
1854 "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1862 auto IncludeStrippedTemplateNames =
1863 DIE.
getTag() == DW_TAG_subprogram ||
1864 DIE.
getTag() == DW_TAG_inlined_subroutine;
1865 auto EntryNames =
getNames(DIE, IncludeStrippedTemplateNames);
1867 ErrorCategory.Report(
"Name Index contains mismatched name of DIE", [&]() {
1868 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
1869 "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1871 make_range(EntryNames.begin(), EntryNames.end()));
1876 EntryOr.takeError(),
1877 [&](
const DWARFDebugNames::SentinelError &) {
1880 ErrorCategory.Report(
1881 "NameIndex Name is not associated with any entries", [&]() {
1882 error() << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
1883 "not associated with any entries.\n",
1884 NI.getUnitOffset(), NTE.getIndex(), Str);
1888 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
1889 error() <<
formatv(
"Name Index @ {0:x}: Name {1} ({2}): {3}\n",
1904 for (
const auto &Entry : *
Loc) {
1906 U->getAddressByteSize());
1908 U->getFormParams().Format);
1909 bool IsInteresting =
1911 return !
Op.isError() && (
Op.getCode() == DW_OP_addr ||
1912 Op.getCode() == DW_OP_form_tls_address ||
1913 Op.getCode() == DW_OP_GNU_push_tls_address);
1921void DWARFVerifier::verifyNameIndexCompleteness(
1930 if (Die.
find(DW_AT_declaration))
1940 auto IncludeLinkageName = Die.
getTag() == DW_TAG_subprogram ||
1941 Die.
getTag() == DW_TAG_inlined_subroutine;
1944 auto IncludeStrippedTemplateNames =
false;
1945 auto IncludeObjCNames =
false;
1946 auto EntryNames =
getNames(Die, IncludeStrippedTemplateNames,
1947 IncludeObjCNames, IncludeLinkageName);
1948 if (EntryNames.empty())
1958 case DW_TAG_compile_unit:
1964 case DW_TAG_formal_parameter:
1965 case DW_TAG_template_value_parameter:
1966 case DW_TAG_template_type_parameter:
1967 case DW_TAG_GNU_template_parameter_pack:
1968 case DW_TAG_GNU_template_template_param:
1978 case DW_TAG_enumerator:
1983 case DW_TAG_imported_declaration:
1989 case DW_TAG_subprogram:
1990 case DW_TAG_inlined_subroutine:
1993 {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
2002 case DW_TAG_variable:
2014 for (StringRef Name : EntryNames) {
2015 auto iter = NamesToDieOffsets.find(Name);
2016 if (iter == NamesToDieOffsets.end() || !iter->second.count(DieUnitOffset)) {
2017 ErrorCategory.Report(
2018 "Name Index DIE entry missing name",
2021 "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
2022 "name {3} missing.\n",
2023 NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name);
2035 CUTU->getBaseAddress();
2038 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2039 DCtx.getRecoverableErrorHandler()(std::move(E));
2045 if (!
CU->getDWOId())
2048 CU->getNonSkeletonUnitDIE().getDwarfUnit()->getContext();
2050 for (
auto &CUTU : NonSkeletonContext.
dwo_units()) {
2052 CUTU->getBaseAddress();
2055 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
2056 DCtx.getRecoverableErrorHandler()(std::move(E));
2059 if (NonSkeletonContext.
isDWP())
2064void DWARFVerifier::verifyDebugNames(
const DWARFSection &AccelSection,
2066 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,
2067 DCtx.isLittleEndian(), 0);
2068 DWARFDebugNames AccelTable(AccelSectionData, StrData);
2070 OS <<
"Verifying .debug_names...\n";
2075 std::string Msg =
toString(std::move(
E));
2076 ErrorCategory.Report(
"Accelerator Table Error",
2077 [&]() {
error() << Msg <<
'\n'; });
2080 const uint64_t OriginalNumErrors = ErrorCategory.GetNumErrors();
2081 verifyDebugNamesCULists(AccelTable);
2082 for (
const auto &NI : AccelTable)
2083 verifyNameIndexBuckets(NI, StrData);
2084 parallelForEach(AccelTable, [&](
const DWARFDebugNames::NameIndex &NI) {
2085 verifyNameIndexAbbrevs(NI);
2089 if (OriginalNumErrors != ErrorCategory.GetNumErrors())
2091 DenseMap<uint64_t, DWARFUnit *> CUOffsetsToDUMap;
2092 for (
const auto &CU : DCtx.compile_units()) {
2093 if (!(CU->getVersion() >= 5 && CU->getDWOId()))
2095 CUOffsetsToDUMap[CU->getOffset()] =
2096 CU->getNonSkeletonUnitDIE().getDwarfUnit();
2099 for (
const DWARFDebugNames::NameIndex &NI : AccelTable) {
2101 verifyNameIndexEntries(NI, NTE, CUOffsetsToDUMap);
2105 auto populateNameToOffset =
2106 [&](
const DWARFDebugNames::NameIndex &NI,
2107 StringMap<DenseSet<uint64_t>> &NamesToDieOffsets) {
2108 for (
const DWARFDebugNames::NameTableEntry &NTE : NI) {
2110 const std::string
Name = tName ? std::string(tName) :
"";
2112 Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&EntryID);
2113 auto Iter = NamesToDieOffsets.insert({
Name, DenseSet<uint64_t>(3)});
2114 for (; EntryOr; EntryOr = NI.getEntry(&EntryID)) {
2115 if (std::optional<uint64_t> DieOffset = EntryOr->getDIEUnitOffset())
2116 Iter.first->second.insert(*DieOffset);
2120 [&](
const DWARFDebugNames::SentinelError &) {
2121 if (!NamesToDieOffsets.empty())
2123 ErrorCategory.Report(
2124 "NameIndex Name is not associated with any entries", [&]() {
2126 << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
2127 "not associated with any entries.\n",
2128 NI.getUnitOffset(), NTE.getIndex(), Name);
2131 [&](
const ErrorInfoBase &
Info) {
2132 ErrorCategory.Report(
"Uncategorized NameIndex error", [&]() {
2134 "Name Index @ {0:x}: Name {1} ({2}): {3}\n",
2135 NI.getUnitOffset(), NTE.
getIndex(), Name,
Info.message());
2144 populateNameToOffset(NI, NamesToDieOffsets);
2145 for (uint32_t i = 0, iEnd = NI.getCUCount(); i < iEnd; ++i) {
2146 const uint64_t CUOffset = NI.getCUOffset(i);
2147 DWARFUnit *
U = DCtx.getUnitForOffset(CUOffset);
2154 if (CUDie != NonSkeletonUnitDie) {
2158 verifyNameIndexCompleteness(
2159 DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), NI,
2165 verifyNameIndexCompleteness(DWARFDie(CU, &Die), NI,
2176 DataExtractor StrData(
D.getStrSection(), DCtx.isLittleEndian(), 0);
2177 if (!
D.getAppleNamesSection().Data.empty())
2178 verifyAppleAccelTable(&
D.getAppleNamesSection(), &StrData,
".apple_names");
2179 if (!
D.getAppleTypesSection().Data.empty())
2180 verifyAppleAccelTable(&
D.getAppleTypesSection(), &StrData,
".apple_types");
2181 if (!
D.getAppleNamespacesSection().Data.empty())
2182 verifyAppleAccelTable(&
D.getAppleNamespacesSection(), &StrData,
2183 ".apple_namespaces");
2184 if (!
D.getAppleObjCSection().Data.empty())
2185 verifyAppleAccelTable(&
D.getAppleObjCSection(), &StrData,
".apple_objc");
2187 if (!
D.getNamesSection().Data.empty())
2188 verifyDebugNames(
D.getNamesSection(), StrData);
2189 return ErrorCategory.GetNumErrors() == 0;
2193 OS <<
"Verifying .debug_str_offsets...\n";
2202 std::optional<DwarfFormat> DwoLegacyDwarf4Format;
2204 if (DwoLegacyDwarf4Format)
2210 DwoLegacyDwarf4Format = InfoFormat;
2214 DwoLegacyDwarf4Format,
".debug_str_offsets.dwo",
2217 std::nullopt,
".debug_str_offsets",
2231 while (
C.seek(NextUnit),
C.tell() < DA.getData().size()) {
2237 Length = DA.getData().size();
2243 if (
C.tell() +
Length > DA.getData().size()) {
2244 ErrorCategory.Report(
2245 "Section contribution length exceeds available space", [&]() {
2247 "{0}: contribution {1:X}: length exceeds available space "
2249 "offset ({1:X}) + length field space ({2:X}) + length "
2251 "{4:X} > section size {5:X})\n",
2253 C.tell() +
Length, DA.getData().size());
2262 ErrorCategory.Report(
"Invalid Section version", [&]() {
2263 error() <<
formatv(
"{0}: contribution {1:X}: invalid version {2}\n",
2274 DA.setAddressSize(OffsetByteSize);
2276 if (Remainder != 0) {
2277 ErrorCategory.Report(
"Invalid section contribution length", [&]() {
2279 "{0}: contribution {1:X}: invalid length ((length ({2:X}) "
2280 "- header (0x4)) % offset size {3:X} == {4:X} != 0)\n",
2291 if (StrData.
size() <= StrOff) {
2292 ErrorCategory.Report(
2293 "String offset out of bounds of string section", [&]() {
2295 "{0}: contribution {1:X}: index {2:X}: invalid string "
2296 "offset *{3:X} == {4:X}, is beyond the bounds of the string "
2297 "section of length {5:X}\n",
2303 if (StrData[StrOff - 1] ==
'\0')
2305 ErrorCategory.Report(
2306 "Section contribution contains invalid string offset", [&]() {
2308 "{0}: contribution {1:X}: index {2:X}: invalid string "
2309 "offset *{3:X} == {4:X}, is neither zero nor "
2310 "immediately following a null character\n",
2317 if (
Error E =
C.takeError()) {
2318 std::string Msg =
toString(std::move(E));
2319 ErrorCategory.Report(
"String offset error", [&]() {
2328 StringRef s, std::function<
void(
void)> detailCallback) {
2329 this->
Report(s,
"", detailCallback);
2334 std::function<
void(
void)> detailCallback) {
2335 std::lock_guard<std::mutex> Lock(WriteMutex);
2337 std::string category_str = std::string(category);
2340 if (!sub_category.
empty()) {
2348 std::function<
void(
StringRef,
unsigned)> handleCounts) {
2349 for (
const auto &[
name, aggData] : Aggregation) {
2350 handleCounts(
name, aggData.OverallCount);
2355 const auto Agg = Aggregation.find(category);
2356 if (Agg != Aggregation.end()) {
2358 handleCounts(
name, aggData);
2364 if (DumpOpts.ShowAggregateErrors && ErrorCategory.GetNumCategories()) {
2365 error() <<
"Aggregated error counts:\n";
2366 ErrorCategory.EnumerateResults([&](
StringRef s,
unsigned count) {
2367 error() << s <<
" occurred " <<
count <<
" time(s).\n";
2370 if (!DumpOpts.JsonErrSummaryFile.empty()) {
2375 error() <<
"unable to open json summary file '"
2376 << DumpOpts.JsonErrSummaryFile
2377 <<
"' for writing: " << EC.message() <<
'\n';
2383 ErrorCategory.EnumerateResults([&](
StringRef Category,
unsigned Count) {
2387 ErrorCategory.EnumerateDetailedResultsFor(
2388 Category, [&](
StringRef SubCategory,
unsigned SubCount) {
2393 ErrorCount +=
Count;
2396 RootNode.
try_emplace(
"error-categories", std::move(Categories));
2410 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.