40using namespace object;
46std::optional<DWARFAddressRange>
48 auto Begin =
Ranges.begin();
50 auto Pos = std::lower_bound(Begin, End, R);
71 return Children.end();
73 auto End = Children.end();
74 auto Iter = Children.begin();
76 if (Iter->intersects(RI))
81 return Children.end();
85 auto I1 = Ranges.begin(), E1 = Ranges.end();
86 auto I2 =
RHS.Ranges.begin(), E2 =
RHS.Ranges.end();
92 bool Covered = I1->LowPC <= R.LowPC;
93 if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) {
101 if (R.LowPC < I1->HighPC)
102 R.LowPC = I1->HighPC;
109 auto I1 = Ranges.begin(), E1 = Ranges.end();
110 auto I2 =
RHS.Ranges.begin(), E2 =
RHS.Ranges.end();
111 while (I1 != E1 && I2 != E2) {
112 if (I1->intersects(*I2))
114 if (I1->LowPC < I2->LowPC)
124 uint8_t &
UnitType,
bool &isUnitDWARF64) {
126 uint8_t AddrSize = 0;
130 bool ValidLength =
false;
131 bool ValidVersion =
false;
132 bool ValidAddrSize =
false;
133 bool ValidType =
true;
134 bool ValidAbbrevOffset =
true;
154 ValidAbbrevOffset =
false;
159 if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
162 error() <<
format(
"Units[%d] - start offset: 0x%08" PRIx64
" \n", UnitIndex,
165 note() <<
"The length for this unit is too "
166 "large for the .debug_info provided.\n";
168 note() <<
"The 16 bit unit header version is not valid.\n";
170 note() <<
"The unit type encoding is not valid.\n";
171 if (!ValidAbbrevOffset)
172 note() <<
"The offset into the .debug_abbrev section is "
175 note() <<
"The address size is unsupported.\n";
177 *
Offset = OffsetStart +
Length + (isUnitDWARF64 ? 12 : 4);
181bool DWARFVerifier::verifyName(
const DWARFDie &Die) {
185 std::string ReconstructedName;
187 std::string OriginalFullName;
190 if (OriginalFullName.empty() || OriginalFullName == ReconstructedName)
193 error() <<
"Simplified template DW_AT_name could not be reconstituted:\n"
195 " reconstituted: {1}\n",
196 OriginalFullName, ReconstructedName);
202unsigned DWARFVerifier::verifyUnitContents(
DWARFUnit &Unit,
203 ReferenceMap &UnitLocalReferences,
204 ReferenceMap &CrossUnitReferences) {
205 unsigned NumUnitErrors = 0;
206 unsigned NumDies = Unit.getNumDIEs();
207 for (
unsigned I = 0;
I < NumDies; ++
I) {
208 auto Die = Unit.getDIEAtIndex(
I);
210 if (Die.
getTag() == DW_TAG_null)
214 NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
215 NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences,
216 CrossUnitReferences);
219 NumUnitErrors += verifyName(Die);
225 <<
" has DW_CHILDREN_yes but DIE has no children: ";
230 NumUnitErrors += verifyDebugInfoCallSite(Die);
233 DWARFDie Die = Unit.getUnitDIE(
false);
235 error() <<
"Compilation unit without DIE.\n";
237 return NumUnitErrors;
241 error() <<
"Compilation unit root DIE is not a unit DIE: "
246 uint8_t
UnitType = Unit.getUnitType();
250 <<
") do not match.\n";
258 error() <<
"Skeleton compilation unit has children.\n";
263 NumUnitErrors += verifyDieRanges(Die, RI);
265 return NumUnitErrors;
268unsigned DWARFVerifier::verifyDebugInfoCallSite(
const DWARFDie &Die) {
269 if (Die.
getTag() != DW_TAG_call_site && Die.
getTag() != DW_TAG_GNU_call_site)
274 if (Curr.
getTag() == DW_TAG_inlined_subroutine) {
275 error() <<
"Call site entry nested within inlined subroutine:";
282 error() <<
"Call site entry not nested within a valid subprogram:";
287 std::optional<DWARFFormValue> CallAttr = Curr.
find(
288 {DW_AT_call_all_calls, DW_AT_call_all_source_calls,
289 DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,
290 DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites});
292 error() <<
"Subprogram with call site entry has no DW_AT_call attribute:";
301unsigned DWARFVerifier::verifyAbbrevSection(
const DWARFDebugAbbrev *Abbrev) {
302 unsigned NumErrors = 0;
306 for (
auto AbbrDecl : *AbbrDecls) {
308 for (
auto Attribute : AbbrDecl.attributes()) {
311 error() <<
"Abbreviation declaration contains multiple "
323 OS <<
"Verifying .debug_abbrev...\n";
326 unsigned NumErrors = 0;
332 return NumErrors == 0;
336 unsigned NumDebugInfoErrors = 0;
337 ReferenceMap CrossUnitReferences;
340 for (
const auto &Unit : Units) {
341 OS <<
"Verifying unit: " <<
Index <<
" / " << Units.getNumUnits();
342 if (
const char*
Name = Unit->getUnitDIE(
true).getShortName())
343 OS <<
", \"" <<
Name <<
'\"';
346 ReferenceMap UnitLocalReferences;
347 NumDebugInfoErrors +=
348 verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences);
349 NumDebugInfoErrors += verifyDebugInfoReferences(
350 UnitLocalReferences, [&](
uint64_t Offset) {
return Unit.get(); });
354 NumDebugInfoErrors += verifyDebugInfoReferences(
361 return NumDebugInfoErrors;
364unsigned DWARFVerifier::verifyUnitSection(
const DWARFSection &S) {
367 unsigned NumDebugInfoErrors = 0;
370 bool isUnitDWARF64 =
false;
371 bool isHeaderChainValid =
true;
378 ReferenceMap CrossUnitReferences;
382 isHeaderChainValid =
false;
389 if (UnitIdx == 0 && !hasDIE) {
390 warn() <<
"Section is empty.\n";
391 isHeaderChainValid =
true;
393 if (!isHeaderChainValid)
394 ++NumDebugInfoErrors;
395 return NumDebugInfoErrors;
401 if (IndexStr.
empty())
403 OS <<
"Verifying " <<
Name <<
"...\n";
409 MapType::Allocator
Alloc;
410 std::vector<std::unique_ptr<MapType>> Sections(
Index.getColumnKinds().size());
413 if (!
E.getContributions())
416 InfoColumnKind == DW_SECT_INFO
421 if (
SC.getLength() == 0)
424 Sections[Col] = std::make_unique<MapType>(
Alloc);
425 auto &
M = *Sections[Col];
426 auto I =
M.find(
SC.getOffset());
427 if (
I !=
M.end() &&
I.start() < (
SC.getOffset() +
SC.getLength())) {
429 "overlapping index entries for entries {0:x16} "
430 "and {1:x16} for column {2}\n",
434 M.insert(
SC.getOffset(),
SC.getOffset() +
SC.getLength() - 1, Sig);
442 return verifyIndex(
".debug_cu_index", DWARFSectionKind::DW_SECT_INFO,
453 unsigned NumErrors = 0;
455 OS <<
"Verifying .debug_info Unit Header Chain...\n";
457 NumErrors += verifyUnitSection(S);
460 OS <<
"Verifying .debug_types Unit Header Chain...\n";
462 NumErrors += verifyUnitSection(S);
465 OS <<
"Verifying non-dwo Units...\n";
468 OS <<
"Verifying dwo Units...\n";
470 return NumErrors == 0;
473unsigned DWARFVerifier::verifyDieRanges(
const DWARFDie &Die,
474 DieRangeInfo &ParentRI) {
475 unsigned NumErrors = 0;
483 if (!RangesOrError) {
485 if (!Unit->isDWOUnit())
494 DieRangeInfo RI(Die);
515 if (!IsObjectFile || IsMachOObject || Die.
getTag() != DW_TAG_compile_unit) {
516 bool DumpDieAfterError =
false;
517 for (
const auto &Range : Ranges) {
518 if (!Range.valid()) {
520 error() <<
"Invalid address range " << Range <<
"\n";
521 DumpDieAfterError =
true;
531 if (
auto PrevRange = RI.insert(Range)) {
533 error() <<
"DIE has overlapping ranges in DW_AT_ranges attribute: "
534 << *PrevRange <<
" and " <<
Range <<
'\n';
535 DumpDieAfterError =
true;
538 if (DumpDieAfterError)
539 dump(Die, 2) <<
'\n';
543 const auto IntersectingChild = ParentRI.insert(RI);
544 if (IntersectingChild != ParentRI.Children.end()) {
546 error() <<
"DIEs have overlapping address ranges:";
548 dump(IntersectingChild->Die) <<
'\n';
552 bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() &&
553 !(Die.
getTag() == DW_TAG_subprogram &&
554 ParentRI.Die.getTag() == DW_TAG_subprogram);
555 if (ShouldBeContained && !ParentRI.contains(RI)) {
557 error() <<
"DIE address ranges are not contained in its parent's ranges:";
559 dump(Die, 2) <<
'\n';
564 NumErrors += verifyDieRanges(Child, RI);
569unsigned DWARFVerifier::verifyDebugInfoAttribute(
const DWARFDie &Die,
571 unsigned NumErrors = 0;
572 auto ReportError = [&](
const Twine &TitleMsg) {
574 error() << TitleMsg <<
'\n';
580 const auto Attr = AttrValue.
Attr;
585 unsigned DwarfVersion =
U->getVersion();
589 if (
U->isDWOUnit() && RangeSection.
Data.
empty())
591 if (*SectionOffset >= RangeSection.
Data.
size())
593 "DW_AT_ranges offset is beyond " +
594 StringRef(DwarfVersion < 5 ?
".debug_ranges" :
".debug_rnglists") +
598 ReportError(
"DIE has invalid DW_AT_ranges encoding:");
600 case DW_AT_stmt_list:
603 if (*SectionOffset >=
U->getLineSection().Data.size())
604 ReportError(
"DW_AT_stmt_list offset is beyond .debug_line bounds: " +
608 ReportError(
"DIE has invalid DW_AT_stmt_list encoding:");
610 case DW_AT_location: {
621 if (
Expected<std::vector<DWARFLocationExpression>> Loc =
623 for (
const auto &Entry : *Loc) {
626 U->getFormParams().Format);
632 ReportError(
"DIE contains invalid DWARF expression:");
635 Loc.takeError(), [&](std::unique_ptr<ResolverError>
E) {
636 return U->isDWOUnit() ? Error::success()
637 : Error(std::move(E));
639 ReportError(
toString(std::move(Err)));
642 case DW_AT_specification:
643 case DW_AT_abstract_origin: {
645 auto DieTag = Die.
getTag();
646 auto RefTag = ReferencedDie.getTag();
647 if (DieTag == RefTag)
649 if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
651 if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
654 if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)
656 ReportError(
"DIE with tag " +
TagString(DieTag) +
" has " +
658 " that points to DIE with "
659 "incompatible tag " +
672 case DW_AT_call_file:
673 case DW_AT_decl_file: {
675 if (
U->isDWOUnit() && !
U->isTypeUnit())
677 const auto *
LT =
U->getContext().getLineTableForUnit(U);
679 if (!
LT->hasFileAtIndex(*FileIdx)) {
680 bool IsZeroIndexed =
LT->Prologue.getVersion() >= 5;
681 if (std::optional<uint64_t> LastFileIdx =
682 LT->getLastValidFileIndex()) {
684 " with an invalid file index " +
686 " (valid values are [" + (IsZeroIndexed ?
"0-" :
"1-") +
690 " with an invalid file index " +
692 " (the file table in the prologue is empty)");
697 " that references a file with index " +
699 " and the compile unit has no line table");
703 " with invalid encoding");
707 case DW_AT_call_line:
708 case DW_AT_decl_line: {
711 " with invalid encoding");
721unsigned DWARFVerifier::verifyDebugInfoForm(
const DWARFDie &Die,
723 ReferenceMap &LocalReferences,
724 ReferenceMap &CrossUnitReferences) {
726 unsigned NumErrors = 0;
733 case DW_FORM_ref_udata: {
738 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
740 if (CUOffset >= CUSize) {
743 <<
format(
"0x%08" PRIx64, CUOffset)
744 <<
" is invalid (must be less than CU size of "
745 <<
format(
"0x%08" PRIx64, CUSize) <<
"):\n";
746 Die.
dump(
OS, 0, DumpOpts);
751 LocalReferences[*RefVal].insert(Die.
getOffset());
756 case DW_FORM_ref_addr: {
762 if (*RefVal >= DieCU->getInfoSection().Data.size()) {
764 error() <<
"DW_FORM_ref_addr offset beyond .debug_info "
770 CrossUnitReferences[*RefVal].insert(Die.
getOffset());
781 case DW_FORM_line_strp: {
795unsigned DWARFVerifier::verifyDebugInfoReferences(
796 const ReferenceMap &References,
800 return U->getDIEForOffset(
Offset);
803 unsigned NumErrors = 0;
804 for (
const std::pair<
const uint64_t, std::set<uint64_t>> &Pair :
806 if (GetDIEForOffset(Pair.first))
809 error() <<
"invalid DIE reference " <<
format(
"0x%08" PRIx64, Pair.first)
810 <<
". Offset is in between DIEs:\n";
811 for (
auto Offset : Pair.second)
818void DWARFVerifier::verifyDebugLineStmtOffsets() {
819 std::map<uint64_t, DWARFDie> StmtListToDie;
821 auto Die =
CU->getUnitDIE();
826 if (!StmtSectionOffset)
828 const uint64_t LineTableOffset = *StmtSectionOffset;
832 ++NumDebugLineErrors;
833 error() <<
".debug_line[" <<
format(
"0x%08" PRIx64, LineTableOffset)
834 <<
"] was not able to be parsed for CU:\n";
840 assert(LineTable ==
nullptr);
845 auto Iter = StmtListToDie.find(LineTableOffset);
846 if (Iter != StmtListToDie.end()) {
847 ++NumDebugLineErrors;
848 error() <<
"two compile unit DIEs, "
849 <<
format(
"0x%08" PRIx64, Iter->second.getOffset()) <<
" and "
851 <<
", have the same DW_AT_stmt_list section offset:\n";
857 StmtListToDie[LineTableOffset] = Die;
861void DWARFVerifier::verifyDebugLineRows() {
863 auto Die =
CU->getUnitDIE();
872 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
873 uint32_t MinFileIndex = isDWARF5 ? 0 : 1;
876 for (
const auto &FileName : LineTable->Prologue.FileNames) {
878 if (FileName.DirIdx > MaxDirIndex) {
879 ++NumDebugLineErrors;
880 error() <<
".debug_line["
883 <<
"].prologue.file_names[" << FileIndex
884 <<
"].dir_idx contains an invalid index: " << FileName.DirIdx
889 std::string FullPath;
890 const bool HasFullPath = LineTable->getFileNameByIndex(
891 FileIndex,
CU->getCompilationDir(),
892 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath);
893 assert(HasFullPath &&
"Invalid index?");
895 auto It = FullPathMap.
find(FullPath);
896 if (It == FullPathMap.
end())
897 FullPathMap[FullPath] = FileIndex;
898 else if (It->second != FileIndex) {
899 warn() <<
".debug_line["
902 <<
"].prologue.file_names[" << FileIndex
903 <<
"] is a duplicate of file_names[" << It->second <<
"]\n";
912 for (
const auto &Row : LineTable->Rows) {
914 if (Row.Address.Address < PrevAddress) {
915 ++NumDebugLineErrors;
916 error() <<
".debug_line["
919 <<
"] row[" << RowIndex
920 <<
"] decreases in address from previous row:\n";
924 LineTable->Rows[RowIndex - 1].dump(
OS);
930 if (!LineTable->hasFileAtIndex(Row.File)) {
931 ++NumDebugLineErrors;
932 error() <<
".debug_line["
935 <<
"][" << RowIndex <<
"] has invalid file index " << Row.File
936 <<
" (valid values are [" << MinFileIndex <<
','
937 << LineTable->Prologue.FileNames.size()
938 << (isDWARF5 ?
")" :
"]") <<
"):\n";
946 PrevAddress = Row.Address.Address;
955 IsMachOObject(
false) {
957 IsObjectFile =
F->isRelocatableObject();
958 IsMachOObject =
F->isMachO();
963 NumDebugLineErrors = 0;
964 OS <<
"Verifying .debug_line...\n";
965 verifyDebugLineStmtOffsets();
966 verifyDebugLineRows();
967 return NumDebugLineErrors == 0;
970unsigned DWARFVerifier::verifyAppleAccelTable(
const DWARFSection *AccelSection,
973 unsigned NumErrors = 0;
981 if (!AccelSectionData.isValidOffset(
AccelTable.getSizeHdr())) {
982 error() <<
"Section is too small to fit a section header.\n";
998 uint64_t HashesBase = BucketsOffset + NumBuckets * 4;
999 uint64_t OffsetsBase = HashesBase + NumHashes * 4;
1000 for (
uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
1001 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
1002 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
1003 error() <<
format(
"Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
1009 if (NumAtoms == 0) {
1010 error() <<
"No atoms: failed to read HashData.\n";
1014 error() <<
"Unsupported form: failed to read HashData.\n";
1018 for (
uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
1019 uint64_t HashOffset = HashesBase + 4 * HashIdx;
1020 uint64_t DataOffset = OffsetsBase + 4 * HashIdx;
1021 uint32_t Hash = AccelSectionData.getU32(&HashOffset);
1022 uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
1023 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
1025 error() <<
format(
"Hash[%d] has invalid HashData offset: "
1026 "0x%08" PRIx64
".\n",
1027 HashIdx, HashDataOffset);
1036 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
1037 const uint32_t NumHashDataObjects =
1038 AccelSectionData.getU32(&HashDataOffset);
1039 for (
uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
1045 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
1046 StringOffset = StrpOffset;
1047 const char *
Name = StrData->
getCStr(&StringOffset);
1052 "%s Bucket[%d] Hash[%d] = 0x%08x "
1053 "Str[%u] = 0x%08" PRIx64
" DIE[%d] = 0x%08" PRIx64
" "
1054 "is not a valid DIE offset for \"%s\".\n",
1055 SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
1061 if ((
Tag != dwarf::DW_TAG_null) && (Die.
getTag() !=
Tag)) {
1063 <<
" in accelerator table does not match Tag "
1080 const uint64_t NotIndexed = std::numeric_limits<uint64_t>::max();
1084 CUMap[
CU->getOffset()] = NotIndexed;
1086 unsigned NumErrors = 0;
1088 if (NI.getCUCount() == 0) {
1089 error() <<
formatv(
"Name Index @ {0:x} does not index any CU\n",
1090 NI.getUnitOffset());
1098 if (Iter == CUMap.
end()) {
1100 "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
1101 NI.getUnitOffset(),
Offset);
1106 if (Iter->second != NotIndexed) {
1107 error() <<
formatv(
"Name Index @ {0:x} references a CU @ {1:x}, but "
1108 "this CU is already indexed by Name Index @ {2:x}\n",
1109 NI.getUnitOffset(),
Offset, Iter->second);
1112 Iter->second = NI.getUnitOffset();
1116 for (
const auto &KV : CUMap) {
1117 if (KV.second == NotIndexed)
1118 warn() <<
formatv(
"CU @ {0:x} not covered by any Name Index\n", KV.first);
1138 warn() <<
formatv(
"Name Index @ {0:x} does not contain a hash table.\n",
1145 std::vector<BucketInfo> BucketStarts;
1150 error() <<
formatv(
"Bucket {0} of Name Index @ {1:x} contains invalid "
1151 "value {2}. Valid range is [0, {3}].\n",
1157 BucketStarts.emplace_back(Bucket,
Index);
1177 for (
const BucketInfo &
B : BucketStarts) {
1184 if (
B.Index > NextUncovered) {
1185 error() <<
formatv(
"Name Index @ {0:x}: Name table entries [{1}, {2}] "
1186 "are not covered by the hash table.\n",
1204 "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
1205 "mismatched hash value {2:x} (belonging to bucket {3}).\n",
1221 error() <<
formatv(
"Name Index @ {0:x}: String ({1}) at index {2} "
1222 "hashes to {3:x}, but "
1223 "the Name Index hash is {4:x}\n",
1231 NextUncovered = std::max(NextUncovered,
Idx);
1236unsigned DWARFVerifier::verifyNameIndexAttribute(
1240 if (FormName.
empty()) {
1241 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1242 "unknown form: {3}.\n",
1248 if (AttrEnc.
Index == DW_IDX_type_hash) {
1249 if (AttrEnc.
Form != dwarf::DW_FORM_data8) {
1251 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
1252 "uses an unexpected form {2} (should be {3}).\n",
1261 struct FormClassTable {
1266 static constexpr FormClassTable Table[] = {
1275 return T.Index == AttrEnc.
Index;
1278 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} contains an "
1279 "unknown index attribute: {2}.\n",
1285 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1286 "unexpected form {3} (expected form class {4}).\n",
1288 AttrEnc.
Form, Iter->ClassName);
1297 warn() <<
formatv(
"Name Index @ {0:x}: Verifying indexes of type units is "
1298 "not currently supported.\n",
1303 unsigned NumErrors = 0;
1306 if (TagName.
empty()) {
1307 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} references an "
1308 "unknown tag: {2}.\n",
1312 for (
const auto &AttrEnc : Abbrev.Attributes) {
1314 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} contains "
1315 "multiple {2} attributes.\n",
1320 NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
1324 error() <<
formatv(
"NameIndex @ {0:x}: Indexing multiple compile units "
1325 "and abbreviation {1:x} has no {2} attribute.\n",
1327 dwarf::DW_IDX_compile_unit);
1330 if (!
Attributes.count(dwarf::DW_IDX_die_offset)) {
1332 "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
1341 bool IncludeLinkageName =
true) {
1343 if (
const char *Str =
DIE.getShortName())
1344 Result.emplace_back(Str);
1345 else if (
DIE.
getTag() == dwarf::DW_TAG_namespace)
1346 Result.emplace_back(
"(anonymous namespace)");
1348 if (IncludeLinkageName) {
1349 if (
const char *Str =
DIE.getLinkageName())
1350 Result.emplace_back(Str);
1356unsigned DWARFVerifier::verifyNameIndexEntries(
1366 "Name Index @ {0:x}: Unable to get string associated with name {1}.\n",
1372 unsigned NumErrors = 0;
1377 for (; EntryOr; ++
NumEntries, EntryID = NextEntryID,
1378 EntryOr = NI.
getEntry(&NextEntryID)) {
1379 uint32_t CUIndex = *EntryOr->getCUIndex();
1381 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1382 "invalid CU index ({2}).\n",
1388 uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset();
1391 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1392 "non-existing DIE @ {2:x}.\n",
1398 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
1399 "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
1405 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
1406 "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1414 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
1415 "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1417 make_range(EntryNames.begin(), EntryNames.end()));
1425 error() << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
1426 "not associated with any entries.\n",
1427 NI.getUnitOffset(), NTE.getIndex(), Str);
1432 << formatv(
"Name Index @ {0:x}: Name {1} ({2}): {3}\n",
1433 NI.getUnitOffset(), NTE.getIndex(), Str,
1448 for (
const auto &Entry : *Loc) {
1450 U->getAddressByteSize());
1452 U->getFormParams().Format);
1453 bool IsInteresting =
1455 return !Op.isError() && (Op.getCode() == DW_OP_addr ||
1456 Op.getCode() == DW_OP_form_tls_address ||
1457 Op.getCode() == DW_OP_GNU_push_tls_address);
1465unsigned DWARFVerifier::verifyNameIndexCompleteness(
1473 if (Die.
find(DW_AT_declaration))
1483 auto IncludeLinkageName = Die.
getTag() == DW_TAG_subprogram ||
1484 Die.
getTag() == DW_TAG_inlined_subroutine;
1485 auto EntryNames =
getNames(Die, IncludeLinkageName);
1486 if (EntryNames.empty())
1496 case DW_TAG_compile_unit:
1502 case DW_TAG_formal_parameter:
1503 case DW_TAG_template_value_parameter:
1504 case DW_TAG_template_type_parameter:
1505 case DW_TAG_GNU_template_parameter_pack:
1506 case DW_TAG_GNU_template_template_param:
1516 case DW_TAG_enumerator:
1521 case DW_TAG_imported_declaration:
1527 case DW_TAG_subprogram:
1528 case DW_TAG_inlined_subroutine:
1531 {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
1540 case DW_TAG_variable:
1551 unsigned NumErrors = 0;
1555 return E.getDIEUnitOffset() == DieUnitOffset;
1557 error() <<
formatv(
"Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
1558 "name {3} missing.\n",
1567unsigned DWARFVerifier::verifyDebugNames(
const DWARFSection &AccelSection,
1569 unsigned NumErrors = 0;
1574 OS <<
"Verifying .debug_names...\n";
1579 error() <<
toString(std::move(
E)) <<
'\n';
1583 NumErrors += verifyDebugNamesCULists(
AccelTable);
1585 NumErrors += verifyNameIndexBuckets(NI, StrData);
1587 NumErrors += verifyNameIndexAbbrevs(NI);
1594 NumErrors += verifyNameIndexEntries(NI, NTE);
1599 for (
const std::unique_ptr<DWARFUnit> &U : DCtx.
compile_units()) {
1602 auto *
CU = cast<DWARFCompileUnit>(
U.get());
1604 NumErrors += verifyNameIndexCompleteness(
DWARFDie(
CU, &Die), *NI);
1613 unsigned NumErrors = 0;
1614 if (!
D.getAppleNamesSection().Data.empty())
1615 NumErrors += verifyAppleAccelTable(&
D.getAppleNamesSection(), &StrData,
1617 if (!
D.getAppleTypesSection().Data.empty())
1618 NumErrors += verifyAppleAccelTable(&
D.getAppleTypesSection(), &StrData,
1620 if (!
D.getAppleNamespacesSection().Data.empty())
1621 NumErrors += verifyAppleAccelTable(&
D.getAppleNamespacesSection(), &StrData,
1622 ".apple_namespaces");
1623 if (!
D.getAppleObjCSection().Data.empty())
1624 NumErrors += verifyAppleAccelTable(&
D.getAppleObjCSection(), &StrData,
1627 if (!
D.getNamesSection().Data.empty())
1628 NumErrors += verifyDebugNames(
D.getNamesSection(), StrData);
1629 return NumErrors == 0;
1639 Die.
dump(OS, indent, DumpOpts);
ArrayRef< TableEntry > TableRef
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static SmallVector< StringRef, 2 > getNames(const DWARFDie &DIE, bool IncludeLinkageName=true)
static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file contains constants used for implementing Dwarf debug support.
This file implements a coalescing interval map for small objects.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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...
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
A structured debug information entry.
unsigned getOffset() const
Get the compile/type unit relative offset of this DIE.
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)
unsigned getNumCompileUnits()
Get the number of compile units in this context.
DWARFDie getDIEForOffset(uint64_t Offset)
Get a DIE given an exact offset.
const DWARFDebugAbbrev * getDebugAbbrevDWO()
Get a pointer to the parsed dwo abbreviations object.
compile_unit_range compile_units()
Get compile units in this context.
const DWARFDebugAbbrev * getDebugAbbrev()
Get a pointer to the parsed DebugAbbrev object.
bool isLittleEndian() const
const DWARFDebugLine::LineTable * getLineTableForUnit(DWARFUnit *U)
Get a pointer to a parsed line table corresponding to a compile unit.
const DWARFUnitVector & getNormalUnitsVector()
static bool isAddressSizeSupported(unsigned AddressSize)
const DWARFUnitVector & getDWOUnitsVector()
const DWARFObject & getDWARFObj() const
const DWARFAbbreviationDeclarationSet * getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const
DWARFDebugInfoEntry - A DIE with only the minimum required data.
DWARF v5-specific implementation of an Accelerator Entry.
Represents a single accelerator table within the DWARF v5 .debug_names section.
uint32_t getHashArrayEntry(uint32_t Index) const
Reads an entry in the Hash Array for the given Index.
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
iterator_range< ValueIterator > equal_range(StringRef Key) const
Look up all entries in this Name Index matching Key.
uint64_t getCUOffset(uint32_t CU) const
Reads offset of compilation unit CU. CU is 0-based.
Expected< Entry > getEntry(uint64_t *Offset) const
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
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.
Error returned by NameIndex::getEntry to report it has reached the end of the entry list.
.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.
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.
Expected< DWARFAddressRangesVector > getAddressRanges() const
Get the address ranges for this DIE.
DWARFDie getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE as the referenced DIE.
DWARFDie getParent() const
Get the parent of this DIE object.
std::optional< DWARFFormValue > find(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE.
DWARFUnit * getDwarfUnit() const
bool isSubprogramDIE() const
Returns true if DIE represents a subprogram (not inlined).
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...
DWARFDie getFirstChild() const
Get the first child of this DIE object.
dwarf::Tag getTag() const
Expected< DWARFLocationExpressionsVector > getLocations(dwarf::Attribute Attr) const
iterator_range< attribute_iterator > attributes() const
Get an iterator range to all attributes in the current DIE only.
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 getAbbrevDWOSection() const
virtual StringRef getAbbrevSection() const
virtual void forEachInfoSections(function_ref< void(const DWARFSection &)> F) const
virtual const DWARFSection & getRangesSection() const
virtual StringRef getTUIndexSection() const
virtual void forEachTypesSections(function_ref< void(const DWARFSection &)> F) const
virtual const DWARFSection & getLineSection() const
virtual const DWARFSection & getRnglistsSection() const
virtual StringRef getCUIndexSection() const
virtual const object::ObjectFile * getFile() const
Describe a collection of units.
DWARFDie getUnitDIE(bool ExtractUnitDIEOnly=true)
static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag)
uint64_t getOffset() const
bool handleAccelTables()
Verify the information in accelerator tables, if they exist.
bool handleDebugTUIndex()
Verify the information in the .debug_tu_index section.
bool handleDebugCUIndex()
Verify the information in the .debug_cu_index section.
DWARFVerifier(raw_ostream &S, DWARFContext &D, DIDumpOptions DumpOpts=DIDumpOptions::getForSingleDIE())
bool handleDebugInfo()
Verify the information in the .debug_info and .debug_types sections.
bool handleDebugLine()
Verify the information in the .debug_line section.
bool handleDebugAbbrev()
Verify the information in any of the following sections, if available: .debug_abbrev,...
iterator find(const_arg_type_t< KeyT > Val)
void reserve(size_type NumEntries)
Grow the densemap so that it can contain at least NumEntries items before resizing again.
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.
Implements a dense probed hash-table based set with some number of buckets stored inline.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
iterator find(StringRef Key)
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.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
static raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
static raw_ostream & error()
Convenience method for printing "error: " to stderr.
static raw_ostream & note()
Convenience method for printing "note: " to stderr.
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
StringRef AttributeString(unsigned Attribute)
StringRef FormEncodingString(unsigned Encoding)
StringRef UnitTypeString(unsigned)
StringRef TagString(unsigned Tag)
@ SC
CHAIN = SC CHAIN, Imm128 - System call.
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.
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 formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are are tuples (A,...
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.
std::vector< DWARFAddressRange > DWARFAddressRangesVector
DWARFAddressRangesVector - represents a set of absolute address 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.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
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...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
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 consumeError(Error Err)
Consume a Error without doing anything.
Container for dump options that control which debug information will be dumped.
Encapsulates a DWARF attribute value and all of the data required to describe the attribute value.
DWARFFormValue Value
The form and value for this attribute.
dwarf::Attribute Attr
The attribute enumeration of this attribute.
uint16_t getVersion() const
static void dumpTableHeader(raw_ostream &OS, unsigned Indent)
Abbreviation describing the encoding of Name Index entries.
uint32_t Code
Abbreviation code.
Index attribute and its encoding.
A class that keeps the address range information for a single DIE.
std::vector< DWARFAddressRange > Ranges
Sorted DWARFAddressRanges.
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
bool intersects(const DieRangeInfo &RHS) const
Return true if any range in this object intersects with any range in RHS.
std::optional< DWARFAddressRange > insert(const DWARFAddressRange &R)
Inserts the address range.