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;
155 if (!AbbrevSetOrErr) {
156 ValidAbbrevOffset =
false;
166 if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
169 error() <<
format(
"Units[%d] - start offset: 0x%08" PRIx64
" \n", UnitIndex,
172 note() <<
"The length for this unit is too "
173 "large for the .debug_info provided.\n";
175 note() <<
"The 16 bit unit header version is not valid.\n";
177 note() <<
"The unit type encoding is not valid.\n";
178 if (!ValidAbbrevOffset)
179 note() <<
"The offset into the .debug_abbrev section is "
182 note() <<
"The address size is unsupported.\n";
184 *
Offset = OffsetStart +
Length + (isUnitDWARF64 ? 12 : 4);
188bool DWARFVerifier::verifyName(
const DWARFDie &Die) {
192 std::string ReconstructedName;
194 std::string OriginalFullName;
197 if (OriginalFullName.empty() || OriginalFullName == ReconstructedName)
200 error() <<
"Simplified template DW_AT_name could not be reconstituted:\n"
202 " reconstituted: {1}\n",
203 OriginalFullName, ReconstructedName);
209unsigned DWARFVerifier::verifyUnitContents(
DWARFUnit &Unit,
210 ReferenceMap &UnitLocalReferences,
211 ReferenceMap &CrossUnitReferences) {
212 unsigned NumUnitErrors = 0;
213 unsigned NumDies = Unit.getNumDIEs();
214 for (
unsigned I = 0;
I < NumDies; ++
I) {
215 auto Die = Unit.getDIEAtIndex(
I);
217 if (Die.
getTag() == DW_TAG_null)
221 NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
222 NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences,
223 CrossUnitReferences);
226 NumUnitErrors += verifyName(Die);
232 <<
" has DW_CHILDREN_yes but DIE has no children: ";
237 NumUnitErrors += verifyDebugInfoCallSite(Die);
240 DWARFDie Die = Unit.getUnitDIE(
false);
242 error() <<
"Compilation unit without DIE.\n";
244 return NumUnitErrors;
248 error() <<
"Compilation unit root DIE is not a unit DIE: "
253 uint8_t
UnitType = Unit.getUnitType();
257 <<
") do not match.\n";
265 error() <<
"Skeleton compilation unit has children.\n";
270 NumUnitErrors += verifyDieRanges(Die, RI);
272 return NumUnitErrors;
275unsigned DWARFVerifier::verifyDebugInfoCallSite(
const DWARFDie &Die) {
276 if (Die.
getTag() != DW_TAG_call_site && Die.
getTag() != DW_TAG_GNU_call_site)
281 if (Curr.
getTag() == DW_TAG_inlined_subroutine) {
282 error() <<
"Call site entry nested within inlined subroutine:";
289 error() <<
"Call site entry not nested within a valid subprogram:";
294 std::optional<DWARFFormValue> CallAttr = Curr.
find(
295 {DW_AT_call_all_calls, DW_AT_call_all_source_calls,
296 DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,
297 DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites});
299 error() <<
"Subprogram with call site entry has no DW_AT_call attribute:";
308unsigned DWARFVerifier::verifyAbbrevSection(
const DWARFDebugAbbrev *Abbrev) {
314 if (!AbbrDeclsOrErr) {
319 const auto *AbbrDecls = *AbbrDeclsOrErr;
320 unsigned NumErrors = 0;
321 for (
auto AbbrDecl : *AbbrDecls) {
323 for (
auto Attribute : AbbrDecl.attributes()) {
326 error() <<
"Abbreviation declaration contains multiple "
337 OS <<
"Verifying .debug_abbrev...\n";
340 unsigned NumErrors = 0;
346 return NumErrors == 0;
350 unsigned NumDebugInfoErrors = 0;
351 ReferenceMap CrossUnitReferences;
354 for (
const auto &Unit : Units) {
355 OS <<
"Verifying unit: " <<
Index <<
" / " << Units.getNumUnits();
356 if (
const char*
Name = Unit->getUnitDIE(
true).getShortName())
357 OS <<
", \"" <<
Name <<
'\"';
360 ReferenceMap UnitLocalReferences;
361 NumDebugInfoErrors +=
362 verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences);
363 NumDebugInfoErrors += verifyDebugInfoReferences(
364 UnitLocalReferences, [&](
uint64_t Offset) {
return Unit.get(); });
368 NumDebugInfoErrors += verifyDebugInfoReferences(
375 return NumDebugInfoErrors;
378unsigned DWARFVerifier::verifyUnitSection(
const DWARFSection &S) {
381 unsigned NumDebugInfoErrors = 0;
384 bool isUnitDWARF64 =
false;
385 bool isHeaderChainValid =
true;
392 ReferenceMap CrossUnitReferences;
396 isHeaderChainValid =
false;
403 if (UnitIdx == 0 && !hasDIE) {
404 warn() <<
"Section is empty.\n";
405 isHeaderChainValid =
true;
407 if (!isHeaderChainValid)
408 ++NumDebugInfoErrors;
409 return NumDebugInfoErrors;
415 if (IndexStr.
empty())
417 OS <<
"Verifying " <<
Name <<
"...\n";
423 MapType::Allocator
Alloc;
424 std::vector<std::unique_ptr<MapType>> Sections(
Index.getColumnKinds().size());
427 if (!
E.getContributions())
430 InfoColumnKind == DW_SECT_INFO
435 if (
SC.getLength() == 0)
438 Sections[Col] = std::make_unique<MapType>(
Alloc);
439 auto &
M = *Sections[Col];
440 auto I =
M.find(
SC.getOffset());
441 if (
I !=
M.end() &&
I.start() < (
SC.getOffset() +
SC.getLength())) {
443 "overlapping index entries for entries {0:x16} "
444 "and {1:x16} for column {2}\n",
448 M.insert(
SC.getOffset(),
SC.getOffset() +
SC.getLength() - 1, Sig);
456 return verifyIndex(
".debug_cu_index", DWARFSectionKind::DW_SECT_INFO,
467 unsigned NumErrors = 0;
469 OS <<
"Verifying .debug_info Unit Header Chain...\n";
471 NumErrors += verifyUnitSection(S);
474 OS <<
"Verifying .debug_types Unit Header Chain...\n";
476 NumErrors += verifyUnitSection(S);
479 OS <<
"Verifying non-dwo Units...\n";
482 OS <<
"Verifying dwo Units...\n";
484 return NumErrors == 0;
487unsigned DWARFVerifier::verifyDieRanges(
const DWARFDie &Die,
488 DieRangeInfo &ParentRI) {
489 unsigned NumErrors = 0;
497 if (!RangesOrError) {
499 if (!Unit->isDWOUnit())
508 DieRangeInfo RI(Die);
529 if (!IsObjectFile || IsMachOObject || Die.
getTag() != DW_TAG_compile_unit) {
530 bool DumpDieAfterError =
false;
531 for (
const auto &Range : Ranges) {
532 if (!Range.valid()) {
534 error() <<
"Invalid address range " << Range <<
"\n";
535 DumpDieAfterError =
true;
545 if (
auto PrevRange = RI.insert(Range)) {
547 error() <<
"DIE has overlapping ranges in DW_AT_ranges attribute: "
548 << *PrevRange <<
" and " <<
Range <<
'\n';
549 DumpDieAfterError =
true;
552 if (DumpDieAfterError)
553 dump(Die, 2) <<
'\n';
557 const auto IntersectingChild = ParentRI.insert(RI);
558 if (IntersectingChild != ParentRI.Children.end()) {
560 error() <<
"DIEs have overlapping address ranges:";
562 dump(IntersectingChild->Die) <<
'\n';
566 bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() &&
567 !(Die.
getTag() == DW_TAG_subprogram &&
568 ParentRI.Die.getTag() == DW_TAG_subprogram);
569 if (ShouldBeContained && !ParentRI.contains(RI)) {
571 error() <<
"DIE address ranges are not contained in its parent's ranges:";
573 dump(Die, 2) <<
'\n';
578 NumErrors += verifyDieRanges(Child, RI);
583unsigned DWARFVerifier::verifyDebugInfoAttribute(
const DWARFDie &Die,
585 unsigned NumErrors = 0;
586 auto ReportError = [&](
const Twine &TitleMsg) {
588 error() << TitleMsg <<
'\n';
594 const auto Attr = AttrValue.
Attr;
599 unsigned DwarfVersion =
U->getVersion();
603 if (
U->isDWOUnit() && RangeSection.
Data.
empty())
605 if (*SectionOffset >= RangeSection.
Data.
size())
607 "DW_AT_ranges offset is beyond " +
608 StringRef(DwarfVersion < 5 ?
".debug_ranges" :
".debug_rnglists") +
612 ReportError(
"DIE has invalid DW_AT_ranges encoding:");
614 case DW_AT_stmt_list:
617 if (*SectionOffset >=
U->getLineSection().Data.size())
618 ReportError(
"DW_AT_stmt_list offset is beyond .debug_line bounds: " +
622 ReportError(
"DIE has invalid DW_AT_stmt_list encoding:");
624 case DW_AT_location: {
635 if (
Expected<std::vector<DWARFLocationExpression>> Loc =
637 for (
const auto &Entry : *Loc) {
640 U->getFormParams().Format);
646 ReportError(
"DIE contains invalid DWARF expression:");
649 Loc.takeError(), [&](std::unique_ptr<ResolverError>
E) {
650 return U->isDWOUnit() ? Error::success()
651 : Error(std::move(E));
653 ReportError(
toString(std::move(Err)));
656 case DW_AT_specification:
657 case DW_AT_abstract_origin: {
659 auto DieTag = Die.
getTag();
660 auto RefTag = ReferencedDie.getTag();
661 if (DieTag == RefTag)
663 if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
665 if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
668 if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)
670 ReportError(
"DIE with tag " +
TagString(DieTag) +
" has " +
672 " that points to DIE with "
673 "incompatible tag " +
686 case DW_AT_call_file:
687 case DW_AT_decl_file: {
689 if (
U->isDWOUnit() && !
U->isTypeUnit())
691 const auto *
LT =
U->getContext().getLineTableForUnit(U);
693 if (!
LT->hasFileAtIndex(*FileIdx)) {
694 bool IsZeroIndexed =
LT->Prologue.getVersion() >= 5;
695 if (std::optional<uint64_t> LastFileIdx =
696 LT->getLastValidFileIndex()) {
698 " with an invalid file index " +
700 " (valid values are [" + (IsZeroIndexed ?
"0-" :
"1-") +
704 " with an invalid file index " +
706 " (the file table in the prologue is empty)");
711 " that references a file with index " +
713 " and the compile unit has no line table");
717 " with invalid encoding");
721 case DW_AT_call_line:
722 case DW_AT_decl_line: {
725 " with invalid encoding");
735unsigned DWARFVerifier::verifyDebugInfoForm(
const DWARFDie &Die,
737 ReferenceMap &LocalReferences,
738 ReferenceMap &CrossUnitReferences) {
740 unsigned NumErrors = 0;
747 case DW_FORM_ref_udata: {
752 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
754 if (CUOffset >= CUSize) {
757 <<
format(
"0x%08" PRIx64, CUOffset)
758 <<
" is invalid (must be less than CU size of "
759 <<
format(
"0x%08" PRIx64, CUSize) <<
"):\n";
760 Die.
dump(
OS, 0, DumpOpts);
765 LocalReferences[*RefVal].insert(Die.
getOffset());
770 case DW_FORM_ref_addr: {
776 if (*RefVal >= DieCU->getInfoSection().Data.size()) {
778 error() <<
"DW_FORM_ref_addr offset beyond .debug_info "
784 CrossUnitReferences[*RefVal].insert(Die.
getOffset());
795 case DW_FORM_line_strp: {
809unsigned DWARFVerifier::verifyDebugInfoReferences(
810 const ReferenceMap &References,
814 return U->getDIEForOffset(
Offset);
817 unsigned NumErrors = 0;
818 for (
const std::pair<
const uint64_t, std::set<uint64_t>> &Pair :
820 if (GetDIEForOffset(Pair.first))
823 error() <<
"invalid DIE reference " <<
format(
"0x%08" PRIx64, Pair.first)
824 <<
". Offset is in between DIEs:\n";
825 for (
auto Offset : Pair.second)
832void DWARFVerifier::verifyDebugLineStmtOffsets() {
833 std::map<uint64_t, DWARFDie> StmtListToDie;
835 auto Die =
CU->getUnitDIE();
840 if (!StmtSectionOffset)
842 const uint64_t LineTableOffset = *StmtSectionOffset;
846 ++NumDebugLineErrors;
847 error() <<
".debug_line[" <<
format(
"0x%08" PRIx64, LineTableOffset)
848 <<
"] was not able to be parsed for CU:\n";
854 assert(LineTable ==
nullptr);
859 auto Iter = StmtListToDie.find(LineTableOffset);
860 if (Iter != StmtListToDie.end()) {
861 ++NumDebugLineErrors;
862 error() <<
"two compile unit DIEs, "
863 <<
format(
"0x%08" PRIx64, Iter->second.getOffset()) <<
" and "
865 <<
", have the same DW_AT_stmt_list section offset:\n";
871 StmtListToDie[LineTableOffset] = Die;
875void DWARFVerifier::verifyDebugLineRows() {
877 auto Die =
CU->getUnitDIE();
886 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
887 uint32_t MinFileIndex = isDWARF5 ? 0 : 1;
890 for (
const auto &FileName : LineTable->Prologue.FileNames) {
892 if (FileName.DirIdx > MaxDirIndex) {
893 ++NumDebugLineErrors;
894 error() <<
".debug_line["
897 <<
"].prologue.file_names[" << FileIndex
898 <<
"].dir_idx contains an invalid index: " << FileName.DirIdx
903 std::string FullPath;
904 const bool HasFullPath = LineTable->getFileNameByIndex(
905 FileIndex,
CU->getCompilationDir(),
906 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath);
907 assert(HasFullPath &&
"Invalid index?");
909 auto It = FullPathMap.
find(FullPath);
910 if (It == FullPathMap.
end())
911 FullPathMap[FullPath] = FileIndex;
912 else if (It->second != FileIndex) {
913 warn() <<
".debug_line["
916 <<
"].prologue.file_names[" << FileIndex
917 <<
"] is a duplicate of file_names[" << It->second <<
"]\n";
926 for (
const auto &Row : LineTable->Rows) {
928 if (Row.Address.Address < PrevAddress) {
929 ++NumDebugLineErrors;
930 error() <<
".debug_line["
933 <<
"] row[" << RowIndex
934 <<
"] decreases in address from previous row:\n";
938 LineTable->Rows[RowIndex - 1].dump(
OS);
944 if (!LineTable->hasFileAtIndex(Row.File)) {
945 ++NumDebugLineErrors;
946 error() <<
".debug_line["
949 <<
"][" << RowIndex <<
"] has invalid file index " << Row.File
950 <<
" (valid values are [" << MinFileIndex <<
','
951 << LineTable->Prologue.FileNames.size()
952 << (isDWARF5 ?
")" :
"]") <<
"):\n";
960 PrevAddress = Row.Address.Address;
969 IsMachOObject(
false) {
971 IsObjectFile =
F->isRelocatableObject();
972 IsMachOObject =
F->isMachO();
977 NumDebugLineErrors = 0;
978 OS <<
"Verifying .debug_line...\n";
979 verifyDebugLineStmtOffsets();
980 verifyDebugLineRows();
981 return NumDebugLineErrors == 0;
984unsigned DWARFVerifier::verifyAppleAccelTable(
const DWARFSection *AccelSection,
987 unsigned NumErrors = 0;
995 if (!AccelSectionData.isValidOffset(
AccelTable.getSizeHdr())) {
996 error() <<
"Section is too small to fit a section header.\n";
1012 uint64_t HashesBase = BucketsOffset + NumBuckets * 4;
1013 uint64_t OffsetsBase = HashesBase + NumHashes * 4;
1014 for (
uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
1015 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
1016 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
1017 error() <<
format(
"Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
1023 if (NumAtoms == 0) {
1024 error() <<
"No atoms: failed to read HashData.\n";
1028 error() <<
"Unsupported form: failed to read HashData.\n";
1032 for (
uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
1033 uint64_t HashOffset = HashesBase + 4 * HashIdx;
1034 uint64_t DataOffset = OffsetsBase + 4 * HashIdx;
1035 uint32_t Hash = AccelSectionData.getU32(&HashOffset);
1036 uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
1037 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
1039 error() <<
format(
"Hash[%d] has invalid HashData offset: "
1040 "0x%08" PRIx64
".\n",
1041 HashIdx, HashDataOffset);
1050 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
1051 const uint32_t NumHashDataObjects =
1052 AccelSectionData.getU32(&HashDataOffset);
1053 for (
uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
1059 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
1060 StringOffset = StrpOffset;
1061 const char *
Name = StrData->
getCStr(&StringOffset);
1066 "%s Bucket[%d] Hash[%d] = 0x%08x "
1067 "Str[%u] = 0x%08" PRIx64
" DIE[%d] = 0x%08" PRIx64
" "
1068 "is not a valid DIE offset for \"%s\".\n",
1069 SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
1075 if ((
Tag != dwarf::DW_TAG_null) && (Die.
getTag() !=
Tag)) {
1077 <<
" in accelerator table does not match Tag "
1094 const uint64_t NotIndexed = std::numeric_limits<uint64_t>::max();
1098 CUMap[
CU->getOffset()] = NotIndexed;
1100 unsigned NumErrors = 0;
1102 if (NI.getCUCount() == 0) {
1103 error() <<
formatv(
"Name Index @ {0:x} does not index any CU\n",
1104 NI.getUnitOffset());
1112 if (Iter == CUMap.
end()) {
1114 "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
1115 NI.getUnitOffset(),
Offset);
1120 if (Iter->second != NotIndexed) {
1121 error() <<
formatv(
"Name Index @ {0:x} references a CU @ {1:x}, but "
1122 "this CU is already indexed by Name Index @ {2:x}\n",
1123 NI.getUnitOffset(),
Offset, Iter->second);
1126 Iter->second = NI.getUnitOffset();
1130 for (
const auto &KV : CUMap) {
1131 if (KV.second == NotIndexed)
1132 warn() <<
formatv(
"CU @ {0:x} not covered by any Name Index\n", KV.first);
1152 warn() <<
formatv(
"Name Index @ {0:x} does not contain a hash table.\n",
1159 std::vector<BucketInfo> BucketStarts;
1164 error() <<
formatv(
"Bucket {0} of Name Index @ {1:x} contains invalid "
1165 "value {2}. Valid range is [0, {3}].\n",
1171 BucketStarts.emplace_back(Bucket,
Index);
1191 for (
const BucketInfo &
B : BucketStarts) {
1198 if (
B.Index > NextUncovered) {
1199 error() <<
formatv(
"Name Index @ {0:x}: Name table entries [{1}, {2}] "
1200 "are not covered by the hash table.\n",
1218 "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
1219 "mismatched hash value {2:x} (belonging to bucket {3}).\n",
1235 error() <<
formatv(
"Name Index @ {0:x}: String ({1}) at index {2} "
1236 "hashes to {3:x}, but "
1237 "the Name Index hash is {4:x}\n",
1245 NextUncovered = std::max(NextUncovered,
Idx);
1250unsigned DWARFVerifier::verifyNameIndexAttribute(
1254 if (FormName.
empty()) {
1255 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1256 "unknown form: {3}.\n",
1262 if (AttrEnc.
Index == DW_IDX_type_hash) {
1263 if (AttrEnc.
Form != dwarf::DW_FORM_data8) {
1265 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
1266 "uses an unexpected form {2} (should be {3}).\n",
1275 struct FormClassTable {
1280 static constexpr FormClassTable Table[] = {
1289 return T.Index == AttrEnc.
Index;
1292 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} contains an "
1293 "unknown index attribute: {2}.\n",
1299 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
1300 "unexpected form {3} (expected form class {4}).\n",
1302 AttrEnc.
Form, Iter->ClassName);
1311 warn() <<
formatv(
"Name Index @ {0:x}: Verifying indexes of type units is "
1312 "not currently supported.\n",
1317 unsigned NumErrors = 0;
1320 if (TagName.
empty()) {
1321 warn() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} references an "
1322 "unknown tag: {2}.\n",
1326 for (
const auto &AttrEnc : Abbrev.Attributes) {
1328 error() <<
formatv(
"NameIndex @ {0:x}: Abbreviation {1:x} contains "
1329 "multiple {2} attributes.\n",
1334 NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
1338 error() <<
formatv(
"NameIndex @ {0:x}: Indexing multiple compile units "
1339 "and abbreviation {1:x} has no {2} attribute.\n",
1341 dwarf::DW_IDX_compile_unit);
1344 if (!
Attributes.count(dwarf::DW_IDX_die_offset)) {
1346 "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
1355 bool IncludeStrippedTemplateNames,
1356 bool IncludeObjCNames =
true,
1357 bool IncludeLinkageName =
true) {
1359 if (
const char *Str =
DIE.getShortName()) {
1361 Result.emplace_back(
Name);
1362 if (IncludeStrippedTemplateNames) {
1363 if (std::optional<StringRef> StrippedName =
1367 Result.push_back(StrippedName->str());
1370 if (IncludeObjCNames) {
1371 if (std::optional<ObjCSelectorNames> ObjCNames =
1373 Result.emplace_back(ObjCNames->ClassName);
1374 Result.emplace_back(ObjCNames->Selector);
1375 if (ObjCNames->ClassNameNoCategory)
1376 Result.emplace_back(*ObjCNames->ClassNameNoCategory);
1377 if (ObjCNames->MethodNameNoCategory)
1378 Result.push_back(std::move(*ObjCNames->MethodNameNoCategory));
1381 }
else if (
DIE.
getTag() == dwarf::DW_TAG_namespace)
1382 Result.emplace_back(
"(anonymous namespace)");
1384 if (IncludeLinkageName) {
1385 if (
const char *Str =
DIE.getLinkageName())
1386 Result.emplace_back(Str);
1392unsigned DWARFVerifier::verifyNameIndexEntries(
1402 "Name Index @ {0:x}: Unable to get string associated with name {1}.\n",
1408 unsigned NumErrors = 0;
1413 for (; EntryOr; ++
NumEntries, EntryID = NextEntryID,
1414 EntryOr = NI.
getEntry(&NextEntryID)) {
1415 uint32_t CUIndex = *EntryOr->getCUIndex();
1417 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1418 "invalid CU index ({2}).\n",
1424 uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset();
1427 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x} references a "
1428 "non-existing DIE @ {2:x}.\n",
1434 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
1435 "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
1441 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
1442 "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1450 auto IncludeStrippedTemplateNames =
1452 DIE.
getTag() == DW_TAG_inlined_subroutine;
1453 auto EntryNames =
getNames(
DIE, IncludeStrippedTemplateNames);
1455 error() <<
formatv(
"Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
1456 "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
1458 make_range(EntryNames.begin(), EntryNames.end()));
1466 error() << formatv(
"Name Index @ {0:x}: Name {1} ({2}) is "
1467 "not associated with any entries.\n",
1468 NI.getUnitOffset(), NTE.getIndex(), Str);
1473 << formatv(
"Name Index @ {0:x}: Name {1} ({2}): {3}\n",
1474 NI.getUnitOffset(), NTE.getIndex(), Str,
1489 for (
const auto &Entry : *Loc) {
1491 U->getAddressByteSize());
1493 U->getFormParams().Format);
1494 bool IsInteresting =
1497 Op.
getCode() == DW_OP_form_tls_address ||
1498 Op.
getCode() == DW_OP_GNU_push_tls_address);
1506unsigned DWARFVerifier::verifyNameIndexCompleteness(
1514 if (Die.
find(DW_AT_declaration))
1524 auto IncludeLinkageName = Die.
getTag() == DW_TAG_subprogram ||
1525 Die.
getTag() == DW_TAG_inlined_subroutine;
1528 auto IncludeStrippedTemplateNames =
false;
1529 auto IncludeObjCNames =
false;
1530 auto EntryNames =
getNames(Die, IncludeStrippedTemplateNames,
1531 IncludeObjCNames, IncludeLinkageName);
1532 if (EntryNames.empty())
1542 case DW_TAG_compile_unit:
1548 case DW_TAG_formal_parameter:
1549 case DW_TAG_template_value_parameter:
1550 case DW_TAG_template_type_parameter:
1551 case DW_TAG_GNU_template_parameter_pack:
1552 case DW_TAG_GNU_template_template_param:
1562 case DW_TAG_enumerator:
1567 case DW_TAG_imported_declaration:
1573 case DW_TAG_subprogram:
1574 case DW_TAG_inlined_subroutine:
1577 {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
1586 case DW_TAG_variable:
1597 unsigned NumErrors = 0;
1601 return E.getDIEUnitOffset() == DieUnitOffset;
1603 error() <<
formatv(
"Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
1604 "name {3} missing.\n",
1613unsigned DWARFVerifier::verifyDebugNames(
const DWARFSection &AccelSection,
1615 unsigned NumErrors = 0;
1620 OS <<
"Verifying .debug_names...\n";
1625 error() <<
toString(std::move(
E)) <<
'\n';
1629 NumErrors += verifyDebugNamesCULists(
AccelTable);
1631 NumErrors += verifyNameIndexBuckets(NI, StrData);
1633 NumErrors += verifyNameIndexAbbrevs(NI);
1640 NumErrors += verifyNameIndexEntries(NI, NTE);
1645 for (
const std::unique_ptr<DWARFUnit> &U : DCtx.
compile_units()) {
1648 auto *
CU = cast<DWARFCompileUnit>(
U.get());
1650 NumErrors += verifyNameIndexCompleteness(
DWARFDie(
CU, &Die), *NI);
1659 unsigned NumErrors = 0;
1660 if (!
D.getAppleNamesSection().Data.empty())
1661 NumErrors += verifyAppleAccelTable(&
D.getAppleNamesSection(), &StrData,
1663 if (!
D.getAppleTypesSection().Data.empty())
1664 NumErrors += verifyAppleAccelTable(&
D.getAppleTypesSection(), &StrData,
1666 if (!
D.getAppleNamespacesSection().Data.empty())
1667 NumErrors += verifyAppleAccelTable(&
D.getAppleNamespacesSection(), &StrData,
1668 ".apple_namespaces");
1669 if (!
D.getAppleObjCSection().Data.empty())
1670 NumErrors += verifyAppleAccelTable(&
D.getAppleObjCSection(), &StrData,
1673 if (!
D.getNamesSection().Data.empty())
1674 NumErrors += verifyDebugNames(
D.getNamesSection(), StrData);
1675 return NumErrors == 0;
1679 OS <<
"Verifying .debug_str_offsets...\n";
1712 while (
C.seek(NextUnit),
C.tell() < DA.getData().size()) {
1716 if (InfoVersion == 4) {
1718 Length = DA.getData().size();
1724 if (
C.tell() +
Length > DA.getData().size()) {
1726 "{0}: contribution {1:X}: length exceeds available space "
1728 "offset ({1:X}) + length field space ({2:X}) + length ({3:X}) == "
1729 "{4:X} > section size {5:X})\n",
1731 C.tell() +
Length, DA.getData().size());
1737 uint8_t Version = DA.getU16(
C);
1738 if (
C && Version != 5) {
1739 error() <<
formatv(
"{0}: contribution {1:X}: invalid version {2}\n",
1749 DA.setAddressSize(OffsetByteSize);
1751 if (Remainder != 0) {
1753 "{0}: contribution {1:X}: invalid length ((length ({2:X}) "
1754 "- header (0x4)) % offset size {3:X} == {4:X} != 0)\n",
1764 if (StrData.
size() <= StrOff) {
1766 "{0}: contribution {1:X}: index {2:X}: invalid string "
1767 "offset *{3:X} == {4:X}, is beyond the bounds of the string section of length {5:X}\n",
1771 if (StrData[StrOff - 1] ==
'\0')
1773 error() <<
formatv(
"{0}: contribution {1:X}: index {2:X}: invalid string "
1774 "offset *{3:X} == {4:X}, is neither zero nor "
1775 "immediately following a null character\n",
1781 if (
Error E =
C.takeError()) {
1795 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 bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx)
static SmallVector< std::string, 3 > getNames(const DWARFDie &DIE, bool IncludeStrippedTemplateNames, bool IncludeObjCNames=true, bool IncludeLinkageName=true)
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
Expected< 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 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 StringRef getTUIndexSection() const
virtual void forEachTypesSections(function_ref< void(const DWARFSection &)> F) const
virtual const DWARFSection & getStrOffsetsSection() const
virtual const DWARFSection & getLineSection() const
virtual const DWARFSection & getRnglistsSection() const
virtual StringRef getCUIndexSection() const
virtual StringRef getStrSection() 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 verifyDebugStrOffsets(StringRef SectionName, const DWARFSection &Section, StringRef StrData, void(DWARFObject::*)(function_ref< void(const DWARFSection &)>) const)
bool handleDebugTUIndex()
Verify the information in the .debug_tu_index section.
bool handleDebugStrOffsets()
Verify the information in the .debug_str_offsets[.dwo].
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)
@ C
The default llvm calling convention, compatible with C.
@ 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.
uint8_t getDwarfOffsetByteSize(DwarfFormat Format)
The size of a reference determined by the DWARF 32/64-bit format.
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.
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.
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.
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 consumeError(Error Err)
Consume a Error without doing anything.
Implement std::hash so that hash_code can be used in STL containers.
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.