LLVM: lib/DebugInfo/DWARF/DWARFVerifier.cpp Source File (original) (raw)

1

2

3

4

5

6

7

39#include

40#include

41#include

42

43using namespace llvm;

44using namespace dwarf;

45using namespace object;

46

47namespace llvm {

49}

50

51std::optional

53 auto Begin = Ranges.begin();

54 auto End = Ranges.end();

55 auto Pos = std::lower_bound(Begin, End, R);

56

57

58 if (Pos != End && *Pos == R) {

59 return std::nullopt;

60 }

61

62 if (Pos != End) {

64 if (Pos->merge(R))

66 }

67 if (Pos != Begin) {

68 auto Iter = Pos - 1;

70 if (Iter->merge(R))

72 }

73

74 Ranges.insert(Pos, R);

75 return std::nullopt;

76}

77

80 if (RI.Ranges.empty())

82

85 while (Iter != End) {

86 if (Iter->intersects(RI))

87 return Iter;

88 ++Iter;

89 }

92}

93

96 auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();

97 if (I2 == E2)

98 return true;

99

101 while (I1 != E1) {

102 bool Covered = I1->LowPC <= R.LowPC;

103 if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) {

104 if (++I2 == E2)

105 return true;

106 R = *I2;

107 continue;

108 }

109 if (!Covered)

110 return false;

111 if (R.LowPC < I1->HighPC)

112 R.LowPC = I1->HighPC;

113 ++I1;

114 }

115 return false;

116}

117

120 auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();

121 while (I1 != E1 && I2 != E2) {

122 if (I1->intersects(*I2)) {

123

124 if (!(*I1 == *I2))

125 return true;

126 }

127 if (I1->LowPC < I2->LowPC)

128 ++I1;

129 else

130 ++I2;

131 }

132 return false;

133}

134

135bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,

142

143 bool ValidLength = false;

144 bool ValidVersion = false;

145 bool ValidAddrSize = false;

146 bool ValidType = true;

147 bool ValidAbbrevOffset = true;

148

154

160 } else {

164 }

165

168 if (!AbbrevSetOrErr) {

169 ValidAbbrevOffset = false;

170

171

172

174 }

175

179 if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||

180 !ValidType) {

182 bool HeaderShown = false;

183 auto ShowHeaderOnce = [&]() {

184 if (!HeaderShown) {

185 error() << format("Units[%d] - start offset: 0x%08" PRIx64 " \n",

186 UnitIndex, OffsetStart);

187 HeaderShown = true;

188 }

189 };

190 if (!ValidLength)

191 ErrorCategory.Report(

192 "Unit Header Length: Unit too large for .debug_info provided", [&]() {

193 ShowHeaderOnce();

194 note() << "The length for this unit is too "

195 "large for the .debug_info provided.\n";

196 });

197 if (!ValidVersion)

198 ErrorCategory.Report(

199 "Unit Header Length: 16 bit unit header version is not valid", [&]() {

200 ShowHeaderOnce();

201 note() << "The 16 bit unit header version is not valid.\n";

202 });

203 if (!ValidType)

204 ErrorCategory.Report(

205 "Unit Header Length: Unit type encoding is not valid", [&]() {

206 ShowHeaderOnce();

207 note() << "The unit type encoding is not valid.\n";

208 });

209 if (!ValidAbbrevOffset)

210 ErrorCategory.Report(

211 "Unit Header Length: Offset into the .debug_abbrev section is not "

212 "valid",

213 [&]() {

214 ShowHeaderOnce();

215 note() << "The offset into the .debug_abbrev section is "

216 "not valid.\n";

217 });

218 if (!ValidAddrSize)

219 ErrorCategory.Report("Unit Header Length: Address size is unsupported",

220 [&]() {

221 ShowHeaderOnce();

222 note() << "The address size is unsupported.\n";

223 });

224 }

225 *Offset = OffsetStart + Length + (isUnitDWARF64 ? 12 : 4);

227}

228

229bool DWARFVerifier::verifyName(const DWARFDie &Die) {

230

231

232

233 std::string ReconstructedName;

234 raw_string_ostream OS(ReconstructedName);

235 std::string OriginalFullName;

237 OS.flush();

238 if (OriginalFullName.empty() || OriginalFullName == ReconstructedName)

239 return false;

240

241 ErrorCategory.Report(

242 "Simplified template DW_AT_name could not be reconstituted", [&]() {

244 << "Simplified template DW_AT_name could not be reconstituted:\n"

245 << formatv(" original: {0}\n"

246 " reconstituted: {1}\n",

247 OriginalFullName, ReconstructedName);

248 dump(Die) << '\n';

250 });

251 return true;

252}

253

254unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit,

255 ReferenceMap &UnitLocalReferences,

256 ReferenceMap &CrossUnitReferences) {

257 unsigned NumUnitErrors = 0;

258 unsigned NumDies = Unit.getNumDIEs();

259 for (unsigned I = 0; I < NumDies; ++I) {

260 auto Die = Unit.getDIEAtIndex(I);

261

262 if (Die.getTag() == DW_TAG_null)

263 continue;

264

265 for (auto AttrValue : Die.attributes()) {

266 NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);

267 NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences,

268 CrossUnitReferences);

269 }

270

271 NumUnitErrors += verifyName(Die);

272

277 << " has DW_CHILDREN_yes but DIE has no children: ";

278 Die.dump(OS);

279 }

280 }

281

282 NumUnitErrors += verifyDebugInfoCallSite(Die);

283 }

284

285 DWARFDie Die = Unit.getUnitDIE( false);

286 if (!Die) {

287 ErrorCategory.Report("Compilation unit missing DIE", [&]() {

288 error() << "Compilation unit without DIE.\n";

289 });

290 NumUnitErrors++;

291 return NumUnitErrors;

292 }

293

295 ErrorCategory.Report("Compilation unit root DIE is not a unit DIE", [&]() {

296 error() << "Compilation unit root DIE is not a unit DIE: "

298 });

299 NumUnitErrors++;

300 }

301

304 ErrorCategory.Report("Mismatched unit type", [&]() {

307 << ") do not match.\n";

308 });

309 NumUnitErrors++;

310 }

311

312

313

314

315 if (Die.getTag() == dwarf::DW_TAG_skeleton_unit && Die.hasChildren()) {

316 ErrorCategory.Report("Skeleton CU has children", [&]() {

317 error() << "Skeleton compilation unit has children.\n";

318 });

319 NumUnitErrors++;

320 }

321

323 NumUnitErrors += verifyDieRanges(Die, RI);

324

325 return NumUnitErrors;

326}

327

328unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) {

329 if (Die.getTag() != DW_TAG_call_site && Die.getTag() != DW_TAG_GNU_call_site)

330 return 0;

331

334 if (Curr.getTag() == DW_TAG_inlined_subroutine) {

335 ErrorCategory.Report(

336 "Call site nested entry within inlined subroutine", [&]() {

337 error() << "Call site entry nested within inlined subroutine:";

338 Curr.dump(OS);

339 });

340 return 1;

341 }

342 }

343

345 ErrorCategory.Report(

346 "Call site entry not nested within valid subprogram", [&]() {

347 error() << "Call site entry not nested within a valid subprogram:";

348 Die.dump(OS);

349 });

350 return 1;

351 }

352

353 std::optional CallAttr = Curr.find(

354 {DW_AT_call_all_calls, DW_AT_call_all_source_calls,

355 DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,

356 DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites});

357 if (!CallAttr) {

358 ErrorCategory.Report(

359 "Subprogram with call site entry has no DW_AT_call attribute", [&]() {

361 << "Subprogram with call site entry has no DW_AT_call attribute:";

362 Curr.dump(OS);

363 Die.dump(OS, 1);

364 });

365 return 1;

366 }

367

368 return 0;

369}

370

371unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {

372 if (!Abbrev)

373 return 0;

374

375 Expected<const DWARFAbbreviationDeclarationSet *> AbbrDeclsOrErr =

377 if (!AbbrDeclsOrErr) {

379 ErrorCategory.Report("Abbreviation Declaration error",

380 [&]() { error() << ErrMsg << "\n"; });

381 return 1;

382 }

383

384 const auto *AbbrDecls = *AbbrDeclsOrErr;

385 unsigned NumErrors = 0;

386 for (auto AbbrDecl : *AbbrDecls) {

387 SmallDenseSet<uint16_t> AttributeSet;

388 for (auto Attribute : AbbrDecl.attributes()) {

390 if (Result.second) {

391 ErrorCategory.Report(

392 "Abbreviation declartion contains multiple attributes", [&]() {

393 error() << "Abbreviation declaration contains multiple "

395 AbbrDecl.dump(OS);

396 });

397 ++NumErrors;

398 }

399 }

400 }

401 return NumErrors;

402}

403

405 OS << "Verifying .debug_abbrev...\n";

406

407 const DWARFObject &DObj = DCtx.getDWARFObj();

408 unsigned NumErrors = 0;

410 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());

412 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());

413

414 return NumErrors == 0;

415}

416

417unsigned DWARFVerifier::verifyUnits(const DWARFUnitVector &Units) {

418 unsigned NumDebugInfoErrors = 0;

419 ReferenceMap CrossUnitReferences;

420

421 unsigned Index = 1;

422 for (const auto &Unit : Units) {

423 OS << "Verifying unit: " << Index << " / " << Units.getNumUnits();

424 if (const char* Name = Unit->getUnitDIE(true).getShortName())

425 OS << ", \"" << Name << '\"';

426 OS << '\n';

428 ReferenceMap UnitLocalReferences;

429 NumDebugInfoErrors +=

430 verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences);

431 NumDebugInfoErrors += verifyDebugInfoReferences(

432 UnitLocalReferences, [&](uint64_t Offset) { return Unit.get(); });

434 }

435

436 NumDebugInfoErrors += verifyDebugInfoReferences(

437 CrossUnitReferences, [&](uint64_t Offset) -> DWARFUnit * {

438 if (DWARFUnit *U = Units.getUnitForOffset(Offset))

439 return U;

440 return nullptr;

441 });

442

443 return NumDebugInfoErrors;

444}

445

446unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S) {

447 const DWARFObject &DObj = DCtx.getDWARFObj();

448 DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);

449 unsigned NumDebugInfoErrors = 0;

450 uint64_t Offset = 0, UnitIdx = 0;

452 bool isUnitDWARF64 = false;

453 bool isHeaderChainValid = true;

455 DWARFUnitVector TypeUnitVector;

456 DWARFUnitVector CompileUnitVector;

457 while (hasDIE) {

458 if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType,

459 isUnitDWARF64)) {

460 isHeaderChainValid = false;

461 if (isUnitDWARF64)

462 break;

463 }

465 ++UnitIdx;

466 }

467 if (UnitIdx == 0 && !hasDIE) {

468 warn() << "Section is empty.\n";

469 isHeaderChainValid = true;

470 }

471 if (!isHeaderChainValid)

472 ++NumDebugInfoErrors;

473 return NumDebugInfoErrors;

474}

475

476unsigned DWARFVerifier::verifyIndex(StringRef Name,

478 StringRef IndexStr) {

479 if (IndexStr.empty())

480 return 0;

481 OS << "Verifying " << Name << "...\n";

482 DWARFUnitIndex Index(InfoColumnKind);

483 DataExtractor D(IndexStr, DCtx.isLittleEndian(), 0);

485 return 1;

486 using MapType = IntervalMap<uint64_t, uint64_t>;

487 MapType::Allocator Alloc;

488 std::vector<std::unique_ptr> Sections(Index.getColumnKinds().size());

489 for (const DWARFUnitIndex::Entry &E : Index.getRows()) {

490 uint64_t Sig = E.getSignature();

491 if (E.getContributions())

492 continue;

494 InfoColumnKind == DW_SECT_INFO

495 ? ArrayRef(E.getContributions(), Index.getColumnKinds().size())

496 : ArrayRef(E.getContribution(), 1))) {

497 const DWARFUnitIndex::Entry::SectionContribution &SC = E.value();

498 int Col = E.index();

500 continue;

501 if (!Sections[Col])

502 Sections[Col] = std::make_unique(Alloc);

503 auto &M = *Sections[Col];

506 StringRef Category = InfoColumnKind == DWARFSectionKind::DW_SECT_INFO

507 ? "Overlapping CU index entries"

508 : "Overlapping TU index entries";

509 ErrorCategory.Report(Category, [&]() {

511 "overlapping index entries for entries {0:x16} "

512 "and {1:x16} for column {2}\n",

514 });

515 return 1;

516 }

518 }

519 }

520

521 return 0;

522}

523

525 return verifyIndex(".debug_cu_index", DWARFSectionKind::DW_SECT_INFO,

526 DCtx.getDWARFObj().getCUIndexSection()) == 0;

527}

528

531 DCtx.getDWARFObj().getTUIndexSection()) == 0;

532}

533

535 const DWARFObject &DObj = DCtx.getDWARFObj();

536 unsigned NumErrors = 0;

537

538 OS << "Verifying .debug_info Unit Header Chain...\n";

540 NumErrors += verifyUnitSection(S);

541 });

542

543 OS << "Verifying .debug_types Unit Header Chain...\n";

545 NumErrors += verifyUnitSection(S);

546 });

547

548 OS << "Verifying non-dwo Units...\n";

549 NumErrors += verifyUnits(DCtx.getNormalUnitsVector());

550

551 OS << "Verifying dwo Units...\n";

552 NumErrors += verifyUnits(DCtx.getDWOUnitsVector());

553 return NumErrors == 0;

554}

555

556unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,

557 DieRangeInfo &ParentRI) {

558 unsigned NumErrors = 0;

559

561 return NumErrors;

562

564

566 if (!RangesOrError) {

567

568 if (!Unit->isDWOUnit())

569 ++NumErrors;

571 return NumErrors;

572 }

573

575

576

577 DieRangeInfo RI(Die);

578

579

580

581

582

583

584

585

586

587

588

589

590

591

592

593

594

595

596

597

598 if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) {

599 bool DumpDieAfterError = false;

600 for (const auto &Range : Ranges) {

601 if (Range.valid()) {

602 ++NumErrors;

603 ErrorCategory.Report("Invalid address range", [&]() {

604 error() << "Invalid address range " << Range << "\n";

605 DumpDieAfterError = true;

606 });

607 continue;

608 }

609

610

611

612

613

614

615

616 if (auto PrevRange = RI.insert(Range)) {

617 ++NumErrors;

618 ErrorCategory.Report("DIE has overlapping DW_AT_ranges", [&]() {

619 error() << "DIE has overlapping ranges in DW_AT_ranges attribute: "

620 << *PrevRange << " and " << Range << '\n';

621 DumpDieAfterError = true;

622 });

623 }

624 }

625 if (DumpDieAfterError)

626 dump(Die, 2) << '\n';

627 }

628

629

630 const auto IntersectingChild = ParentRI.insert(RI);

631 if (IntersectingChild != ParentRI.Children.end()) {

632 ++NumErrors;

633 ErrorCategory.Report("DIEs have overlapping address ranges", [&]() {

634 error() << "DIEs have overlapping address ranges:";

636 dump(IntersectingChild->Die) << '\n';

637 });

638 }

639

640

641 bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() &&

642 !(Die.getTag() == DW_TAG_subprogram &&

643 ParentRI.Die.getTag() == DW_TAG_subprogram);

644 if (ShouldBeContained && !ParentRI.contains(RI)) {

645 ++NumErrors;

646 ErrorCategory.Report(

647 "DIE address ranges are not contained by parent ranges", [&]() {

649 << "DIE address ranges are not contained in its parent's ranges:";

650 dump(ParentRI.Die);

651 dump(Die, 2) << '\n';

652 });

653 }

654

655

656 for (DWARFDie Child : Die)

657 NumErrors += verifyDieRanges(Child, RI);

658

659 return NumErrors;

660}

661

662bool DWARFVerifier::verifyExpressionOp(const DWARFExpression::Operation &Op,

663 DWARFUnit *U) {

664 for (unsigned Operand = 0; Operand < Op.Desc.Op.size(); ++Operand) {

665 unsigned Size = Op.Desc.Op[Operand];

666

668

669

670

671

672 if (Op.Opcode == DW_OP_convert && Op.Operands[Operand] == 0)

673 continue;

674 auto Die = U->getDIEForOffset(U->getOffset() + Op.Operands[Operand]);

675 if (!Die || Die.getTag() != dwarf::DW_TAG_base_type)

676 return false;

677 }

678 }

679

680 return true;

681}

682

683bool DWARFVerifier::verifyExpression(const DWARFExpression &E, DWARFUnit *U) {

684 for (auto &Op : E)

685 if (!verifyExpressionOp(Op, U))

686 return false;

687

688 return true;

689}

690

691unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,

692 DWARFAttribute &AttrValue) {

693 unsigned NumErrors = 0;

694 auto ReportError = [&](StringRef category, const Twine &TitleMsg) {

695 ++NumErrors;

696 ErrorCategory.Report(category, [&]() {

697 error() << TitleMsg << '\n';

698 dump(Die) << '\n';

699 });

700 };

701

702 const DWARFObject &DObj = DCtx.getDWARFObj();

704 const auto Attr = AttrValue.Attr;

705 switch (Attr) {

706 case DW_AT_ranges:

707

709 unsigned DwarfVersion = U->getVersion();

710 const DWARFSection &RangeSection = DwarfVersion < 5

713 if (U->isDWOUnit() && RangeSection.Data.empty())

714 break;

715 if (*SectionOffset >= RangeSection.Data.size())

716 ReportError("DW_AT_ranges offset out of bounds",

717 "DW_AT_ranges offset is beyond " +

718 StringRef(DwarfVersion < 5 ? ".debug_ranges"

719 : ".debug_rnglists") +

720 " bounds: " + llvm::formatv("{0:x8}", *SectionOffset));

721 break;

722 }

723 ReportError("Invalid DW_AT_ranges encoding",

724 "DIE has invalid DW_AT_ranges encoding:");

725 break;

726 case DW_AT_stmt_list:

727

729 if (*SectionOffset >= U->getLineSection().Data.size())

730 ReportError("DW_AT_stmt_list offset out of bounds",

731 "DW_AT_stmt_list offset is beyond .debug_line bounds: " +

733 break;

734 }

735 ReportError("Invalid DW_AT_stmt_list encoding",

736 "DIE has invalid DW_AT_stmt_list encoding:");

737 break;

738 case DW_AT_location: {

739

740

741

742

743

744

745

746

747

748

749 if (Expected<std::vector> Loc =

751 for (const auto &Entry : *Loc) {

753 DWARFExpression Expression(Data, U->getAddressByteSize(),

754 U->getFormParams().Format);

756 any_of(Expression, [](const DWARFExpression::Operation &Op) {

758 });

759 if (Error || !verifyExpression(Expression, U))

760 ReportError("Invalid DWARF expressions",

761 "DIE contains invalid DWARF expression:");

762 }

764 Loc.takeError(), [&](std::unique_ptr E) {

765 return U->isDWOUnit() ? Error::success()

766 : Error(std::move(E));

767 }))

768 ReportError("Invalid DW_AT_location", toString(std::move(Err)));

769 break;

770 }

771 case DW_AT_specification:

772 case DW_AT_abstract_origin: {

774 auto DieTag = Die.getTag();

775 auto RefTag = ReferencedDie.getTag();

776 if (DieTag == RefTag)

777 break;

778 if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)

779 break;

780 if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)

781 break;

782

783 if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)

784 break;

785 ReportError("Incompatible DW_AT_abstract_origin tag reference",

786 "DIE with tag " + TagString(DieTag) + " has " +

788 " that points to DIE with "

789 "incompatible tag " +

791 }

792 break;

793 }

794 case DW_AT_type: {

797 ReportError("Incompatible DW_AT_type attribute tag",

799 " with incompatible tag " + TagString(TypeDie.getTag()));

800 }

801 break;

802 }

803 case DW_AT_call_file:

804 case DW_AT_decl_file: {

806 if (U->isDWOUnit() && U->isTypeUnit())

807 break;

808 const auto *LT = U->getContext().getLineTableForUnit(U);

809 if (LT) {

810 if (LT->hasFileAtIndex(*FileIdx)) {

811 bool IsZeroIndexed = LT->Prologue.getVersion() >= 5;

812 if (std::optional<uint64_t> LastFileIdx =

813 LT->getLastValidFileIndex()) {

814 ReportError("Invalid file index in DW_AT_decl_file",

816 " with an invalid file index " +

818 " (valid values are [" +

819 (IsZeroIndexed ? "0-" : "1-") +

821 } else {

822 ReportError("Invalid file index in DW_AT_decl_file",

824 " with an invalid file index " +

826 " (the file table in the prologue is empty)");

827 }

828 }

829 } else {

830 ReportError(

831 "File index in DW_AT_decl_file reference CU with no line table",

833 " that references a file with index " +

835 " and the compile unit has no line table");

836 }

837 } else {

838 ReportError("Invalid encoding in DW_AT_decl_file",

840 " with invalid encoding");

841 }

842 break;

843 }

844 case DW_AT_call_line:

845 case DW_AT_decl_line: {

847 ReportError(

848 Attr == DW_AT_call_line ? "Invalid file index in DW_AT_decl_line"

849 : "Invalid file index in DW_AT_call_line",

850 "DIE has " + AttributeString(Attr) + " with invalid encoding");

851 }

852 break;

853 }

854 case DW_AT_LLVM_stmt_sequence: {

855

856

858 if (!SectionOffset) {

859 ReportError("Invalid DW_AT_LLVM_stmt_sequence encoding",

860 "DIE has invalid DW_AT_LLVM_stmt_sequence encoding");

861 break;

862 }

863 if (*SectionOffset >= U->getLineSection().Data.size()) {

864 ReportError(

865 "DW_AT_LLVM_stmt_sequence offset out of bounds",

866 "DW_AT_LLVM_stmt_sequence offset is beyond .debug_line bounds: " +

868 break;

869 }

870

871

872 const auto *LineTable = DCtx.getLineTableForUnit(U);

873 if (!LineTable) {

874 ReportError("DW_AT_LLVM_stmt_sequence without line table",

875 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "

876 "line table");

877 break;

878 }

879

880

881 DWARFDie CUDie = U->getUnitDIE();

883 if (!StmtListOffset) {

884 ReportError("DW_AT_LLVM_stmt_sequence without DW_AT_stmt_list",

885 "DIE has DW_AT_LLVM_stmt_sequence but compile unit has no "

886 "DW_AT_stmt_list");

887 break;

888 }

889

890 const int8_t DwarfOffset =

891 LineTable->Prologue.getFormParams().getDwarfOffsetByteSize();

892

893 uint64_t LineTableStart = *StmtListOffset;

894 uint64_t PrologueLength = LineTable->Prologue.PrologueLength;

895 uint64_t TotalLength = LineTable->Prologue.TotalLength;

896 uint64_t LineTableEnd = LineTableStart + TotalLength + DwarfOffset;

897

898

899

900

901 uint64_t InitialLengthSize = DwarfOffset;

902

903 uint64_t VersionSize = 2;

904 uint64_t PrologueLengthSize = DwarfOffset;

905 uint64_t SequencesStart = LineTableStart + InitialLengthSize + VersionSize +

906 PrologueLengthSize + PrologueLength;

907

908

909 if (*SectionOffset < SequencesStart || *SectionOffset >= LineTableEnd) {

910 ReportError("DW_AT_LLVM_stmt_sequence offset out of line table bounds",

911 "DW_AT_LLVM_stmt_sequence offset " +

913 " is not within the line table bounds [" +

916 break;

917 }

918

919

921 [SectionOffset](const auto &Sequence) {

922 return Sequence.StmtSeqOffset == *SectionOffset;

923 });

924

925 if (It == LineTable->Sequences.end())

926 ReportError(

927 "Invalid DW_AT_LLVM_stmt_sequence offset",

928 "DW_AT_LLVM_stmt_sequence offset " +

930 " does not point to a valid sequence offset in the line table");

931 break;

932 }

933 default:

934 break;

935 }

936 return NumErrors;

937}

938

939unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,

940 DWARFAttribute &AttrValue,

941 ReferenceMap &LocalReferences,

942 ReferenceMap &CrossUnitReferences) {

944 unsigned NumErrors = 0;

946 switch (Form) {

947 case DW_FORM_ref1:

948 case DW_FORM_ref2:

949 case DW_FORM_ref4:

950 case DW_FORM_ref8:

951 case DW_FORM_ref_udata: {

952

955 if (RefVal) {

956 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();

958 if (CUOffset >= CUSize) {

959 ++NumErrors;

960 ErrorCategory.Report("Invalid CU offset", [&]() {

962 << format("0x%08" PRIx64, CUOffset)

963 << " is invalid (must be less than CU size of "

964 << format("0x%08" PRIx64, CUSize) << "):\n";

965 Die.dump(OS, 0, DumpOpts);

966 dump(Die) << '\n';

967 });

968 } else {

969

970

973 }

974 }

975 break;

976 }

977 case DW_FORM_ref_addr: {

978

979

982 if (RefVal) {

983 if (*RefVal >= DieCU->getInfoSection().Data.size()) {

984 ++NumErrors;

985 ErrorCategory.Report("DW_FORM_ref_addr offset out of bounds", [&]() {

986 error() << "DW_FORM_ref_addr offset beyond .debug_info "

987 "bounds:\n";

988 dump(Die) << '\n';

989 });

990 } else {

991

992

993 CrossUnitReferences[*RefVal].insert(Die.getOffset());

994 }

995 }

996 break;

997 }

998 case DW_FORM_strp:

999 case DW_FORM_strx:

1000 case DW_FORM_strx1:

1001 case DW_FORM_strx2:

1002 case DW_FORM_strx3:

1003 case DW_FORM_strx4:

1004 case DW_FORM_line_strp: {

1006 ++NumErrors;

1007 std::string ErrMsg = toString(std::move(E));

1008 ErrorCategory.Report("Invalid DW_FORM attribute", [&]() {

1009 error() << ErrMsg << ":\n";

1010 dump(Die) << '\n';

1011 });

1012 }

1013 break;

1014 }

1015 default:

1016 break;

1017 }

1018 return NumErrors;

1019}

1020

1021unsigned DWARFVerifier::verifyDebugInfoReferences(

1022 const ReferenceMap &References,

1023 llvm::function_ref<DWARFUnit *(uint64_t)> GetUnitForOffset) {

1024 auto GetDIEForOffset = [&](uint64_t Offset) {

1025 if (DWARFUnit *U = GetUnitForOffset(Offset))

1026 return U->getDIEForOffset(Offset);

1027 return DWARFDie();

1028 };

1029 unsigned NumErrors = 0;

1030 for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair :

1031 References) {

1032 if (GetDIEForOffset(Pair.first))

1033 continue;

1034 ++NumErrors;

1035 ErrorCategory.Report("Invalid DIE reference", [&]() {

1036 error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first)

1037 << ". Offset is in between DIEs:\n";

1038 for (auto Offset : Pair.second)

1039 dump(GetDIEForOffset(Offset)) << '\n';

1040 OS << "\n";

1041 });

1042 }

1043 return NumErrors;

1044}

1045

1046void DWARFVerifier::verifyDebugLineStmtOffsets() {

1047 std::map<uint64_t, DWARFDie> StmtListToDie;

1048 for (const auto &CU : DCtx.compile_units()) {

1049 auto Die = CU->getUnitDIE();

1050

1051

1052

1054 if (!StmtSectionOffset)

1055 continue;

1056 const uint64_t LineTableOffset = *StmtSectionOffset;

1057 auto LineTable = DCtx.getLineTableForUnit(CU.get());

1058 if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {

1059 if (!LineTable) {

1060 ++NumDebugLineErrors;

1061 ErrorCategory.Report("Unparsable .debug_line entry", [&]() {

1062 error() << ".debug_line[" << format("0x%08" PRIx64, LineTableOffset)

1063 << "] was not able to be parsed for CU:\n";

1064 dump(Die) << '\n';

1065 });

1066 continue;

1067 }

1068 } else {

1069

1070 assert(LineTable == nullptr);

1071

1072

1073 continue;

1074 }

1075 auto [Iter, Inserted] = StmtListToDie.try_emplace(LineTableOffset, Die);

1076 if (!Inserted) {

1077 ++NumDebugLineErrors;

1078 const auto &OldDie = Iter->second;

1079 ErrorCategory.Report("Identical DW_AT_stmt_list section offset", [&]() {

1080 error() << "two compile unit DIEs, "

1081 << format("0x%08" PRIx64, OldDie.getOffset()) << " and "

1083 << ", have the same DW_AT_stmt_list section offset:\n";

1084 dump(OldDie);

1085 dump(Die) << '\n';

1086 });

1087

1088 }

1089 }

1090}

1091

1092void DWARFVerifier::verifyDebugLineRows() {

1093 for (const auto &CU : DCtx.compile_units()) {

1094 auto Die = CU->getUnitDIE();

1095 auto LineTable = DCtx.getLineTableForUnit(CU.get());

1096

1097

1098 if (!LineTable)

1099 continue;

1100

1101

1102 bool isDWARF5 = LineTable->Prologue.getVersion() >= 5;

1103 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();

1104 uint32_t MinFileIndex = isDWARF5 ? 0 : 1;

1105 uint32_t FileIndex = MinFileIndex;

1106 StringMap<uint16_t> FullPathMap;

1107 for (const auto &FileName : LineTable->Prologue.FileNames) {

1108

1109 if (FileName.DirIdx > MaxDirIndex) {

1110 ++NumDebugLineErrors;

1111 ErrorCategory.Report(

1112 "Invalid index in .debug_line->prologue.file_names->dir_idx",

1113 [&]() {

1114 error() << ".debug_line["

1115 << format("0x%08" PRIx64,

1117 << "].prologue.file_names[" << FileIndex

1118 << "].dir_idx contains an invalid index: "

1119 << FileName.DirIdx << "\n";

1120 });

1121 }

1122

1123

1124 std::string FullPath;

1125 const bool HasFullPath = LineTable->getFileNameByIndex(

1126 FileIndex, CU->getCompilationDir(),

1128 assert(HasFullPath && "Invalid index?");

1129 (void)HasFullPath;

1131 if (!Inserted && It->second != FileIndex && DumpOpts.Verbose) {

1132 warn() << ".debug_line["

1133 << format("0x%08" PRIx64,

1135 << "].prologue.file_names[" << FileIndex

1136 << "] is a duplicate of file_names[" << It->second << "]\n";

1137 }

1138

1139 FileIndex++;

1140 }

1141

1142

1143

1144 if (LineTable->Rows.size() == 1 && LineTable->Rows.front().EndSequence)

1145 continue;

1146

1147

1148 uint64_t PrevAddress = 0;

1149 uint32_t RowIndex = 0;

1150 for (const auto &Row : LineTable->Rows) {

1151

1152 if (Row.Address.Address < PrevAddress) {

1153 ++NumDebugLineErrors;

1154 ErrorCategory.Report(

1155 "decreasing address between debug_line rows", [&]() {

1156 error() << ".debug_line["

1157 << format("0x%08" PRIx64,

1159 << "] row[" << RowIndex

1160 << "] decreases in address from previous row:\n";

1161

1163 if (RowIndex > 0)

1164 LineTable->Rows[RowIndex - 1].dump(OS);

1165 Row.dump(OS);

1166 OS << '\n';

1167 });

1168 }

1169

1170 if (!LineTable->hasFileAtIndex(Row.File)) {

1171 ++NumDebugLineErrors;

1172 ErrorCategory.Report("Invalid file index in debug_line", [&]() {

1173 error() << ".debug_line["

1174 << format("0x%08" PRIx64,

1176 << "][" << RowIndex << "] has invalid file index " << Row.File

1177 << " (valid values are [" << MinFileIndex << ','

1178 << LineTable->Prologue.FileNames.size()

1179 << (isDWARF5 ? ")" : "]") << "):\n";

1181 Row.dump(OS);

1182 OS << '\n';

1183 });

1184 }

1185 if (Row.EndSequence)

1186 PrevAddress = 0;

1187 else

1188 PrevAddress = Row.Address.Address;

1189 ++RowIndex;

1190 }

1191 }

1192}

1193

1196 : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)), IsObjectFile(false),

1197 IsMachOObject(false) {

1198 ErrorCategory.ShowDetail(this->DumpOpts.Verbose ||

1199 !this->DumpOpts.ShowAggregateErrors);

1200 if (const auto *F = DCtx.getDWARFObj().getFile()) {

1201 IsObjectFile = F->isRelocatableObject();

1202 IsMachOObject = F->isMachO();

1203 }

1204}

1205

1207 NumDebugLineErrors = 0;

1208 OS << "Verifying .debug_line...\n";

1209 verifyDebugLineStmtOffsets();

1210 verifyDebugLineRows();

1211 return NumDebugLineErrors == 0;

1212}

1213

1214void DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,

1220

1221 OS << "Verifying " << SectionName << "...\n";

1222

1223

1224 if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {

1225 ErrorCategory.Report("Section is too small to fit a section header", [&]() {

1226 error() << "Section is too small to fit a section header.\n";

1227 });

1228 return;

1229 }

1230

1231

1232 if (Error E = AccelTable.extract()) {

1233 std::string Msg = toString(std::move(E));

1234 ErrorCategory.Report("Section is too small to fit a section header",

1235 [&]() { error() << Msg << '\n'; });

1236 return;

1237 }

1238

1239

1240 uint32_t NumBuckets = AccelTable.getNumBuckets();

1241 uint32_t NumHashes = AccelTable.getNumHashes();

1242

1243 uint64_t BucketsOffset =

1244 AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();

1245 uint64_t HashesBase = BucketsOffset + NumBuckets * 4;

1246 uint64_t OffsetsBase = HashesBase + NumHashes * 4;

1247 for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {

1248 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);

1249 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {

1250 ErrorCategory.Report("Invalid hash index", [&]() {

1251 error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx,

1252 HashIdx);

1253 });

1254 }

1255 }

1256 uint32_t NumAtoms = AccelTable.getAtomsDesc().size();

1257 if (NumAtoms == 0) {

1258 ErrorCategory.Report("No atoms", [&]() {

1259 error() << "No atoms: failed to read HashData.\n";

1260 });

1261 return;

1262 }

1263 if (!AccelTable.validateForms()) {

1264 ErrorCategory.Report("Unsupported form", [&]() {

1265 error() << "Unsupported form: failed to read HashData.\n";

1266 });

1267 return;

1268 }

1269

1270 for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {

1271 uint64_t HashOffset = HashesBase + 4 * HashIdx;

1272 uint64_t DataOffset = OffsetsBase + 4 * HashIdx;

1273 uint32_t Hash = AccelSectionData.getU32(&HashOffset);

1274 uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);

1275 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,

1276 sizeof(uint64_t))) {

1277 ErrorCategory.Report("Invalid HashData offset", [&]() {

1278 error() << format("Hash[%d] has invalid HashData offset: "

1279 "0x%08" PRIx64 ".\n",

1280 HashIdx, HashDataOffset);

1281 });

1282 }

1283

1284 uint64_t StrpOffset;

1285 uint64_t StringOffset;

1286 uint32_t StringCount = 0;

1288 unsigned Tag;

1289 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {

1290 const uint32_t NumHashDataObjects =

1291 AccelSectionData.getU32(&HashDataOffset);

1292 for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;

1293 ++HashDataIdx) {

1294 std::tie(Offset, Tag) = AccelTable.readAtoms(&HashDataOffset);

1295 auto Die = DCtx.getDIEForOffset(Offset);

1296 if (!Die) {

1297 const uint32_t BucketIdx =

1298 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;

1299 StringOffset = StrpOffset;

1300 const char *Name = StrData->getCStr(&StringOffset);

1301 if (!Name)

1302 Name = "";

1303

1304 ErrorCategory.Report("Invalid DIE offset", [&]() {

1306 "%s Bucket[%d] Hash[%d] = 0x%08x "

1307 "Str[%u] = 0x%08" PRIx64 " DIE[%d] = 0x%08" PRIx64 " "

1308 "is not a valid DIE offset for \"%s\".\n",

1309 SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,

1310 HashDataIdx, Offset, Name);

1311 });

1312 continue;

1313 }

1314 if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {

1315 ErrorCategory.Report("Mismatched Tag in accellerator table", [&]() {

1317 << " in accelerator table does not match Tag "

1319 << HashDataIdx << "].\n";

1320 });

1321 }

1322 }

1323 }

1324 }

1325}

1326

1328

1329

1330 DenseMap<uint64_t, uint64_t> CUMap;

1331 CUMap.reserve(DCtx.getNumCompileUnits());

1332

1333 DenseSet<uint64_t> CUOffsets;

1334 for (const auto &CU : DCtx.compile_units())

1335 CUOffsets.insert(CU->getOffset());

1336

1337 parallelForEach(AccelTable, [&](const DWARFDebugNames::NameIndex &NI) {

1339 ErrorCategory.Report("Name Index doesn't index any CU", [&]() {

1340 error() << formatv("Name Index @ {0:x} does not index any CU\n",

1342 });

1343 return;

1344 }

1345 for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) {

1348 ErrorCategory.Report("Name Index references non-existing CU", [&]() {

1350 "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",

1352 });

1353 continue;

1354 }

1355 uint64_t DuplicateCUOffset = 0;

1356 {

1357 std::lock_guardstd::mutex Lock(AccessMutex);

1359 if (Iter != CUMap.end())

1360 DuplicateCUOffset = Iter->second;

1361 else

1363 }

1364 if (DuplicateCUOffset) {

1365 ErrorCategory.Report("Duplicate Name Index", [&]() {

1367 "Name Index @ {0:x} references a CU @ {1:x}, but "

1368 "this CU is already indexed by Name Index @ {2:x}\n",

1370 });

1371 continue;

1372 }

1373 }

1374 });

1375

1376 for (const auto &CU : DCtx.compile_units()) {

1377 if (CUMap.count(CU->getOffset()) == 0)

1378 warn() << formatv("CU @ {0:x} not covered by any Name Index\n",

1379 CU->getOffset());

1380 }

1381}

1382

1385 struct BucketInfo {

1386 uint32_t Bucket;

1388

1389 constexpr BucketInfo(uint32_t Bucket, uint32_t Index)

1392 };

1393

1395 warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n",

1397 return;

1398 }

1399

1400

1401

1402 std::vector BucketStarts;

1404 const uint64_t OrigNumberOfErrors = ErrorCategory.GetNumErrors();

1405 for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) {

1408 ErrorCategory.Report("Name Index Bucket contains invalid value", [&]() {

1409 error() << formatv("Bucket {0} of Name Index @ {1:x} contains invalid "

1410 "value {2}. Valid range is [0, {3}].\n",

1413 });

1414 continue;

1415 }

1417 BucketStarts.emplace_back(Bucket, Index);

1418 }

1419

1420

1421

1422

1423 if (OrigNumberOfErrors != ErrorCategory.GetNumErrors())

1424 return;

1425

1426

1427 array_pod_sort(BucketStarts.begin(), BucketStarts.end());

1428

1429

1430

1432

1433

1434

1435

1436 uint32_t NextUncovered = 1;

1437 for (const BucketInfo &B : BucketStarts) {

1438

1439

1440

1441

1442

1443

1444 if (B.Index > NextUncovered) {

1445 ErrorCategory.Report("Name table entries uncovered by hash table", [&]() {

1446 error() << formatv("Name Index @ {0:x}: Name table entries [{1}, {2}] "

1447 "are not covered by the hash table.\n",

1449 });

1450 }

1451 uint32_t Idx = B.Index;

1452

1453

1455 break;

1456

1457

1458

1459

1460

1461

1464 ErrorCategory.Report("Name Index point to mismatched hash value", [&]() {

1466 "Name Index @ {0:x}: Bucket {1} is not empty but points to a "

1467 "mismatched hash value {2:x} (belonging to bucket {3}).\n",

1470 });

1471 }

1472

1473

1474

1475

1479 break;

1480

1483 ErrorCategory.Report(

1484 "String hash doesn't match Name Index hash", [&]() {

1486 "Name Index @ {0:x}: String ({1}) at index {2} "

1487 "hashes to {3:x}, but "

1488 "the Name Index hash is {4:x}\n",

1490 });

1491 }

1492 ++Idx;

1493 }

1494 NextUncovered = std::max(NextUncovered, Idx);

1495 }

1496}

1497

1498void DWARFVerifier::verifyNameIndexAttribute(

1502 if (FormName.empty()) {

1503 ErrorCategory.Report("Unknown NameIndex Abbreviation", [&]() {

1504 error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "

1505 "unknown form: {3}.\n",

1507 AttrEnc.Form);

1508 });

1509 return;

1510 }

1511

1512 if (AttrEnc.Index == DW_IDX_type_hash) {

1513 if (AttrEnc.Form != dwarf::DW_FORM_data8) {

1514 ErrorCategory.Report("Unexpected NameIndex Abbreviation", [&]() {

1516 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "

1517 "uses an unexpected form {2} (should be {3}).\n",

1519 });

1520 return;

1521 }

1522 return;

1523 }

1524

1525 if (AttrEnc.Index == dwarf::DW_IDX_parent) {

1526 constexpr static auto AllowedForms = {dwarf::Form::DW_FORM_flag_present,

1527 dwarf::Form::DW_FORM_ref4};

1529 ErrorCategory.Report("Unexpected NameIndex Abbreviation", [&]() {

1531 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_parent "

1532 "uses an unexpected form {2} (should be "

1533 "DW_FORM_ref4 or DW_FORM_flag_present).\n",

1535 });

1536 return;

1537 }

1538 return;

1539 }

1540

1541

1542

1543

1544 struct FormClassTable {

1547 StringLiteral ClassName;

1548 };

1549 static constexpr FormClassTable Table[] = {

1553 };

1554

1556 auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) {

1557 return T.Index == AttrEnc.Index;

1558 });

1560 warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an "

1561 "unknown index attribute: {2}.\n",

1563 return;

1564 }

1565

1566 if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) {

1567 ErrorCategory.Report("Unexpected NameIndex Abbreviation", [&]() {

1568 error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "

1569 "unexpected form {3} (expected form class {4}).\n",

1571 AttrEnc.Form, Iter->ClassName);

1572 });

1573 return;

1574 }

1575}

1576

1577void DWARFVerifier::verifyNameIndexAbbrevs(

1579 for (const auto &Abbrev : NI.getAbbrevs()) {

1581 if (TagName.empty()) {

1582 warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an "

1583 "unknown tag: {2}.\n",

1585 }

1587 for (const auto &AttrEnc : Abbrev.Attributes) {

1589 ErrorCategory.Report(

1590 "NameIndex Abbreviateion contains multiple attributes", [&]() {

1592 "NameIndex @ {0:x}: Abbreviation {1:x} contains "

1593 "multiple {2} attributes.\n",

1595 });

1596 continue;

1597 }

1598 verifyNameIndexAttribute(NI, Abbrev, AttrEnc);

1599 }

1600

1602 Attributes.count(dwarf::DW_IDX_type_unit)) {

1603 ErrorCategory.Report("Abbreviation contains no attribute", [&]() {

1604 error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units "

1605 "and abbreviation {1:x} has no DW_IDX_compile_unit "

1606 "or DW_IDX_type_unit attribute.\n",

1608 });

1609 }

1610 if (Attributes.count(dwarf::DW_IDX_die_offset)) {

1611 ErrorCategory.Report("Abbreviate in NameIndex missing attribute", [&]() {

1613 "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",

1614 NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset);

1615 });

1616 }

1617 }

1618}

1619

1620

1621

1623 bool IncludeStrippedTemplateNames,

1624 bool IncludeObjCNames = true,

1625 bool IncludeLinkageName = true) {

1627 if (const char *Str = DIE.getShortName()) {

1629 Result.emplace_back(Name);

1630 if (IncludeStrippedTemplateNames) {

1631 if (std::optional StrippedName =

1633

1634

1635 Result.push_back(StrippedName->str());

1636 }

1637

1638 if (IncludeObjCNames) {

1639 if (std::optional ObjCNames =

1641 Result.emplace_back(ObjCNames->ClassName);

1642 Result.emplace_back(ObjCNames->Selector);

1643 if (ObjCNames->ClassNameNoCategory)

1644 Result.emplace_back(*ObjCNames->ClassNameNoCategory);

1645 if (ObjCNames->MethodNameNoCategory)

1646 Result.push_back(std::move(*ObjCNames->MethodNameNoCategory));

1647 }

1648 }

1649 } else if (DIE.getTag() == dwarf::DW_TAG_namespace)

1650 Result.emplace_back("(anonymous namespace)");

1651

1652 if (IncludeLinkageName) {

1653 if (const char *Str = DIE.getLinkageName())

1654 Result.emplace_back(Str);

1655 }

1656

1657 return Result;

1658}

1659

1660void DWARFVerifier::verifyNameIndexEntries(

1664 const char *CStr = NTE.getString();

1665 if (!CStr) {

1666 ErrorCategory.Report("Unable to get string associated with name", [&]() {

1667 error() << formatv("Name Index @ {0:x}: Unable to get string associated "

1668 "with name {1}.\n",

1670 });

1671 return;

1672 }

1673 StringRef Str(CStr);

1676 uint64_t NextEntryID = EntryID;

1677 ExpectedDWARFDebugNames::Entry EntryOr = NI.getEntry(&NextEntryID);

1678 for (; EntryOr; ++NumEntries, EntryID = NextEntryID,

1679 EntryOr = NI.getEntry(&NextEntryID)) {

1680

1681 std::optional<uint64_t> CUIndex = EntryOr->getRelatedCUIndex();

1682 std::optional<uint64_t> TUIndex = EntryOr->getTUIndex();

1683 if (CUIndex && *CUIndex >= NI.getCUCount()) {

1684 ErrorCategory.Report("Name Index entry contains invalid CU index", [&]() {

1685 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "

1686 "invalid CU index ({2}).\n",

1688 });

1689 continue;

1690 }

1693 if (TUIndex && *TUIndex >= (NumLocalTUs + NumForeignTUs)) {

1694 ErrorCategory.Report("Name Index entry contains invalid TU index", [&]() {

1695 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "

1696 "invalid TU index ({2}).\n",

1698 });

1699 continue;

1700 }

1701 std::optional<uint64_t> UnitOffset;

1702 if (TUIndex) {

1703

1704 if (*TUIndex >= NumLocalTUs) {

1705

1706

1707

1708

1709

1710

1711

1712

1713 if (CUIndex) {

1714

1716 } else {

1717 ErrorCategory.Report(

1718 "Name Index entry contains foreign TU index with invalid CU "

1719 "index",

1720 [&]() {

1722 "Name Index @ {0:x}: Entry @ {1:x} contains an "

1723 "foreign TU index ({2}) with no CU index.\n",

1725 });

1726 continue;

1727 }

1728 } else {

1729

1731 }

1732 } else if (CUIndex) {

1733

1735 }

1736

1737

1738 if (!UnitOffset || UnitOffset == UINT32_MAX)

1739 continue;

1740

1741

1742

1743 DWARFUnit *DU = DCtx.getUnitForOffset(*UnitOffset);

1744 if (DU == nullptr || DU->getOffset() != *UnitOffset) {

1745

1746

1747 ErrorCategory.Report(

1748 "Name Index entry contains invalid CU or TU offset", [&]() {

1749 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "

1750 "invalid CU or TU offset {2:x}.\n",

1752 });

1753 continue;

1754 }

1755

1756

1757

1758

1759

1760

1761

1762

1763

1764

1765

1766 DWARFUnit *NonSkeletonUnit = nullptr;

1768 auto Iter = CUOffsetsToDUMap.find(DU->getOffset());

1769 NonSkeletonUnit = Iter->second;

1770 } else {

1771 NonSkeletonUnit = DU;

1772 }

1773 DWARFDie UnitDie = DU->getUnitDIE();

1775 ErrorCategory.Report("Unable to get load .dwo file", [&]() {

1777 "Name Index @ {0:x}: Entry @ {1:x} unable to load "

1778 ".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",

1781 *UnitOffset);

1782 });

1783 continue;

1784 }

1785

1786 if (TUIndex && *TUIndex >= NumLocalTUs) {

1787

1788

1789

1790

1791

1792

1793

1794 const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs;

1796 llvm::DWARFContext &NonSkeletonDCtx = NonSkeletonUnit->getContext();

1797

1798

1799 NonSkeletonUnit =

1801

1802

1803

1804 if (NonSkeletonDCtx.isDWP()) {

1805 DWARFDie NonSkeletonUnitDie = NonSkeletonUnit->getUnitDIE(true);

1807 UnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));

1809 NonSkeletonUnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));

1810 if (DUDwoName != TUDwoName)

1811 continue;

1812 }

1813 }

1814 uint64_t DIEOffset =

1815 NonSkeletonUnit->getOffset() + *EntryOr->getDIEUnitOffset();

1816 const uint64_t NextUnitOffset = NonSkeletonUnit->getNextUnitOffset();

1817

1818

1819 if (DIEOffset >= NextUnitOffset) {

1820 ErrorCategory.Report("NameIndex relative DIE offset too large", [&]() {

1821 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "

1822 "DIE @ {2:x} when CU or TU ends at {3:x}.\n",

1824 NextUnitOffset);

1825 });

1826 continue;

1827 }

1828 DWARFDie DIE = NonSkeletonUnit->getDIEForOffset(DIEOffset);

1829 if (!DIE) {

1830 ErrorCategory.Report("NameIndex references nonexistent DIE", [&]() {

1831 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "

1832 "non-existing DIE @ {2:x}.\n",

1834 });

1835 continue;

1836 }

1837

1838

1839

1840

1843 ErrorCategory.Report("Name index contains mismatched CU of DIE", [&]() {

1845 "Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "

1846 "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",

1847 NI.getUnitOffset(), EntryID, DIEOffset, *UnitOffset,

1849 });

1850 }

1851 if (DIE.getTag() != EntryOr->tag()) {

1852 ErrorCategory.Report("Name Index contains mismatched Tag of DIE", [&]() {

1854 "Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "

1855 "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",

1856 NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(),

1858 });

1859 }

1860

1861

1862

1863 auto IncludeStrippedTemplateNames =

1864 DIE.getTag() == DW_TAG_subprogram ||

1865 DIE.getTag() == DW_TAG_inlined_subroutine;

1866 auto EntryNames = getNames(DIE, IncludeStrippedTemplateNames);

1868 ErrorCategory.Report("Name Index contains mismatched name of DIE", [&]() {

1869 error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "

1870 "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",

1872 make_range(EntryNames.begin(), EntryNames.end()));

1873 });

1874 }

1875 }

1877 EntryOr.takeError(),

1878 [&](const DWARFDebugNames::SentinelError &) {

1879 if (NumEntries > 0)

1880 return;

1881 ErrorCategory.Report(

1882 "NameIndex Name is not associated with any entries", [&]() {

1883 error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is "

1884 "not associated with any entries.\n",

1885 NI.getUnitOffset(), NTE.getIndex(), Str);

1886 });

1887 },

1889 ErrorCategory.Report("Uncategorized NameIndex error", [&]() {

1890 error() << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n",

1892 Info.message());

1893 });

1894 });

1895}

1896

1900 if (Loc) {

1902 return false;

1903 }

1905 for (const auto &Entry : *Loc) {

1907 U->getAddressByteSize());

1909 U->getFormParams().Format);

1910 bool IsInteresting =

1912 return Op.isError() && (Op.getCode() == DW_OP_addr ||

1913 Op.getCode() == DW_OP_form_tls_address ||

1914 Op.getCode() == DW_OP_GNU_push_tls_address);

1915 });

1916 if (IsInteresting)

1917 return true;

1918 }

1919 return false;

1920}

1921

1922void DWARFVerifier::verifyNameIndexCompleteness(

1925

1926

1927

1928

1929

1930

1931 if (Die.find(DW_AT_declaration))

1932 return;

1933

1934

1935

1936

1937

1938

1939

1940

1941 auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram ||

1942 Die.getTag() == DW_TAG_inlined_subroutine;

1943

1944

1945 auto IncludeStrippedTemplateNames = false;

1946 auto IncludeObjCNames = false;

1947 auto EntryNames = getNames(Die, IncludeStrippedTemplateNames,

1948 IncludeObjCNames, IncludeLinkageName);

1949 if (EntryNames.empty())

1950 return;

1951

1952

1953

1954

1955

1956

1957 switch (Die.getTag()) {

1958

1959 case DW_TAG_compile_unit:

1960 case DW_TAG_module:

1961 return;

1962

1963

1964

1965 case DW_TAG_formal_parameter:

1966 case DW_TAG_template_value_parameter:

1967 case DW_TAG_template_type_parameter:

1968 case DW_TAG_GNU_template_parameter_pack:

1969 case DW_TAG_GNU_template_template_param:

1970 return;

1971

1972

1973 case DW_TAG_member:

1974 return;

1975

1976

1977

1978

1979 case DW_TAG_enumerator:

1980 return;

1981

1982

1983

1984 case DW_TAG_imported_declaration:

1985 return;

1986

1987

1988

1989

1990 case DW_TAG_subprogram:

1991 case DW_TAG_inlined_subroutine:

1992 case DW_TAG_label:

1994 {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))

1995 break;

1996 return;

1997

1998

1999

2000

2001

2002

2003 case DW_TAG_variable:

2005 break;

2006 return;

2007

2008 default:

2009 break;

2010 }

2011

2012

2013

2015 for (StringRef Name : EntryNames) {

2016 auto iter = NamesToDieOffsets.find(Name);

2017 if (iter == NamesToDieOffsets.end() || !iter->second.count(DieUnitOffset)) {

2018 ErrorCategory.Report(

2019 "Name Index DIE entry missing name",

2021 error() << formatv(

2022 "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "

2023 "name {3} missing.\n",

2024 NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name);

2025 });

2026 }

2027 }

2028}

2029

2030

2031

2033

2035 CUTU->getUnitDIE();

2036 CUTU->getBaseAddress();

2037 }

2039 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))

2040 DCtx.getRecoverableErrorHandler()(std::move(E));

2041 });

2042

2043

2044

2046 if (CU->getDWOId())

2047 continue;

2049 CU->getNonSkeletonUnitDIE().getDwarfUnit()->getContext();

2050

2051 for (auto &CUTU : NonSkeletonContext.dwo_units()) {

2052 CUTU->getUnitDIE();

2053 CUTU->getBaseAddress();

2054 }

2056 if (Error E = CUTU->tryExtractDIEsIfNeeded(false))

2057 DCtx.getRecoverableErrorHandler()(std::move(E));

2058 });

2059

2060 if (NonSkeletonContext.isDWP())

2061 break;

2062 }

2063}

2064

2065void DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,

2067 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,

2068 DCtx.isLittleEndian(), 0);

2069 DWARFDebugNames AccelTable(AccelSectionData, StrData);

2070

2071 OS << "Verifying .debug_names...\n";

2072

2073

2074

2076 std::string Msg = toString(std::move(E));

2077 ErrorCategory.Report("Accelerator Table Error",

2078 [&]() { error() << Msg << '\n'; });

2079 return;

2080 }

2081 const uint64_t OriginalNumErrors = ErrorCategory.GetNumErrors();

2082 verifyDebugNamesCULists(AccelTable);

2083 for (const auto &NI : AccelTable)

2084 verifyNameIndexBuckets(NI, StrData);

2085 parallelForEach(AccelTable, [&](const DWARFDebugNames::NameIndex &NI) {

2086 verifyNameIndexAbbrevs(NI);

2087 });

2088

2089

2090 if (OriginalNumErrors != ErrorCategory.GetNumErrors())

2091 return;

2092 DenseMap<uint64_t, DWARFUnit *> CUOffsetsToDUMap;

2093 for (const auto &CU : DCtx.compile_units()) {

2094 if (!(CU->getVersion() >= 5 && CU->getDWOId()))

2095 continue;

2096 CUOffsetsToDUMap[CU->getOffset()] =

2097 CU->getNonSkeletonUnitDIE().getDwarfUnit();

2098 }

2100 for (const DWARFDebugNames::NameIndex &NI : AccelTable) {

2101 parallelForEach(NI, [&](DWARFDebugNames::NameTableEntry NTE) {

2102 verifyNameIndexEntries(NI, NTE, CUOffsetsToDUMap);

2103 });

2104 }

2105

2106 auto populateNameToOffset =

2107 [&](const DWARFDebugNames::NameIndex &NI,

2108 StringMap<DenseSet<uint64_t>> &NamesToDieOffsets) {

2109 for (const DWARFDebugNames::NameTableEntry &NTE : NI) {

2110 const char *tName = NTE.getString();

2111 const std::string Name = tName ? std::string(tName) : "";

2113 ExpectedDWARFDebugNames::Entry EntryOr = NI.getEntry(&EntryID);

2114 auto Iter = NamesToDieOffsets.insert({Name, DenseSet<uint64_t>(3)});

2115 for (; EntryOr; EntryOr = NI.getEntry(&EntryID)) {

2116 if (std::optional<uint64_t> DieOffset = EntryOr->getDIEUnitOffset())

2117 Iter.first->second.insert(*DieOffset);

2118 }

2121 [&](const DWARFDebugNames::SentinelError &) {

2122 if (!NamesToDieOffsets.empty())

2123 return;

2124 ErrorCategory.Report(

2125 "NameIndex Name is not associated with any entries", [&]() {

2126 error()

2127 << formatv("Name Index @ {0:x}: Name {1} ({2}) is "

2128 "not associated with any entries.\n",

2129 NI.getUnitOffset(), NTE.getIndex(), Name);

2130 });

2131 },

2132 [&](const ErrorInfoBase &Info) {

2133 ErrorCategory.Report("Uncategorized NameIndex error", [&]() {

2135 "Name Index @ {0:x}: Name {1} ({2}): {3}\n",

2136 NI.getUnitOffset(), NTE.getIndex(), Name, Info.message());

2137 });

2138 });

2139 }

2140 };

2141

2142

2145 populateNameToOffset(NI, NamesToDieOffsets);

2146 for (uint32_t i = 0, iEnd = NI.getCUCount(); i < iEnd; ++i) {

2147 const uint64_t CUOffset = NI.getCUOffset(i);

2148 DWARFUnit *U = DCtx.getUnitForOffset(CUOffset);

2150 if (CU) {

2153 DWARFDie NonSkeletonUnitDie =

2155 if (CUDie != NonSkeletonUnitDie) {

2159 verifyNameIndexCompleteness(

2160 DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), NI,

2161 NamesToDieOffsets);

2162 });

2163 }

2164 } else {

2166 verifyNameIndexCompleteness(DWARFDie(CU, &Die), NI,

2167 NamesToDieOffsets);

2168 });

2169 }

2170 }

2171 }

2172 }

2173}

2174

2177 DataExtractor StrData(D.getStrSection(), DCtx.isLittleEndian(), 0);

2178 if (D.getAppleNamesSection().Data.empty())

2179 verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names");

2180 if (D.getAppleTypesSection().Data.empty())

2181 verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types");

2182 if (D.getAppleNamespacesSection().Data.empty())

2183 verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData,

2184 ".apple_namespaces");

2185 if (D.getAppleObjCSection().Data.empty())

2186 verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc");

2187

2188 if (D.getNamesSection().Data.empty())

2189 verifyDebugNames(D.getNamesSection(), StrData);

2190 return ErrorCategory.GetNumErrors() == 0;

2191}

2192

2194 OS << "Verifying .debug_str_offsets...\n";

2195 const DWARFObject &DObj = DCtx.getDWARFObj();

2197

2198

2199

2200

2201

2202

2203 std::optional DwoLegacyDwarf4Format;

2205 if (DwoLegacyDwarf4Format)

2206 return;

2207 DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);

2211 DwoLegacyDwarf4Format = InfoFormat;

2212 });

2213

2215 DwoLegacyDwarf4Format, ".debug_str_offsets.dwo",

2218 std::nullopt, ".debug_str_offsets",

2221}

2222

2226 const DWARFObject &DObj = DCtx.getDWARFObj();

2227

2232 while (C.seek(NextUnit), C.tell() < DA.getData().size()) {

2235 uint64_t StartOffset = C.tell();

2236 if (LegacyFormat) {

2237 Format = *LegacyFormat;

2238 Length = DA.getData().size();

2239 NextUnit = C.tell() + Length;

2240 } else {

2241 std::tie(Length, Format) = DA.getInitialLength(C);

2242 if (C)

2243 break;

2244 if (C.tell() + Length > DA.getData().size()) {

2245 ErrorCategory.Report(

2246 "Section contribution length exceeds available space", [&]() {

2248 "{0}: contribution {1:X}: length exceeds available space "

2249 "(contribution "

2250 "offset ({1:X}) + length field space ({2:X}) + length "

2251 "({3:X}) == "

2252 "{4:X} > section size {5:X})\n",

2254 C.tell() + Length, DA.getData().size());

2255 });

2257

2258 break;

2259 }

2260 NextUnit = C.tell() + Length;

2263 ErrorCategory.Report("Invalid Section version", [&]() {

2264 error() << formatv("{0}: contribution {1:X}: invalid version {2}\n",

2266 });

2268

2269

2270 continue;

2271 }

2272 (void)DA.getU16(C);

2273 }

2275 DA.setAddressSize(OffsetByteSize);

2277 if (Remainder != 0) {

2278 ErrorCategory.Report("Invalid section contribution length", [&]() {

2280 "{0}: contribution {1:X}: invalid length ((length ({2:X}) "

2281 "- header (0x4)) % offset size {3:X} == {4:X} != 0)\n",

2283 });

2285 }

2286 for (uint64_t Index = 0; C && C.tell() + OffsetByteSize <= NextUnit; ++Index) {

2288 uint64_t StrOff = DA.getAddress(C);

2289

2290 if (StrOff == 0)

2291 continue;

2292 if (StrData.size() <= StrOff) {

2293 ErrorCategory.Report(

2294 "String offset out of bounds of string section", [&]() {

2296 "{0}: contribution {1:X}: index {2:X}: invalid string "

2297 "offset *{3:X} == {4:X}, is beyond the bounds of the string "

2298 "section of length {5:X}\n",

2300 StrData.size());

2301 });

2302 continue;

2303 }

2304 if (StrData[StrOff - 1] == '\0')

2305 continue;

2306 ErrorCategory.Report(

2307 "Section contribution contains invalid string offset", [&]() {

2309 "{0}: contribution {1:X}: index {2:X}: invalid string "

2310 "offset *{3:X} == {4:X}, is neither zero nor "

2311 "immediately following a null character\n",

2313 });

2315 }

2316 }

2317

2318 if (Error E = C.takeError()) {

2319 std::string Msg = toString(std::move(E));

2320 ErrorCategory.Report("String offset error", [&]() {

2322 return false;

2323 });

2324 }

2326}

2327

2329 StringRef s, std::function<void(void)> detailCallback) {

2330 this->Report(s, "", detailCallback);

2331}

2332

2335 std::function<void(void)> detailCallback) {

2336 std::lock_guardstd::mutex Lock(WriteMutex);

2337 ++NumErrors;

2338 std::string category_str = std::string(category);

2341 if (!sub_category.empty()) {

2343 }

2344 if (IncludeDetail)

2345 detailCallback();

2346}

2347

2349 std::function<void(StringRef, unsigned)> handleCounts) {

2350 for (const auto &[name, aggData] : Aggregation) {

2351 handleCounts(name, aggData.OverallCount);

2352 }

2353}

2355 StringRef category, std::function<void(StringRef, unsigned)> handleCounts) {

2356 const auto Agg = Aggregation.find(category);

2357 if (Agg != Aggregation.end()) {

2359 handleCounts(name, aggData);

2360 }

2361 }

2362}

2363

2365 if (DumpOpts.ShowAggregateErrors && ErrorCategory.GetNumCategories()) {

2366 error() << "Aggregated error counts:\n";

2367 ErrorCategory.EnumerateResults([&](StringRef s, unsigned count) {

2368 error() << s << " occurred " << count << " time(s).\n";

2369 });

2370 }

2371 if (!DumpOpts.JsonErrSummaryFile.empty()) {

2372 std::error_code EC;

2373 raw_fd_ostream JsonStream(DumpOpts.JsonErrSummaryFile, EC,

2375 if (EC) {

2376 error() << "unable to open json summary file '"

2377 << DumpOpts.JsonErrSummaryFile

2378 << "' for writing: " << EC.message() << '\n';

2379 return;

2380 }

2381

2384 ErrorCategory.EnumerateResults([&](StringRef Category, unsigned Count) {

2388 ErrorCategory.EnumerateDetailedResultsFor(

2389 Category, [&](StringRef SubCategory, unsigned SubCount) {

2390 Details.try_emplace(SubCategory, SubCount);

2391 });

2392 Val.try_emplace("details", std::move(Details));

2393 Categories.try_emplace(Category, std::move(Val));

2394 ErrorCount += Count;

2395 });

2397 RootNode.try_emplace("error-categories", std::move(Categories));

2398 RootNode.try_emplace("error-count", ErrorCount);

2399

2401 }

2402}

2403

2405

2407

2409

2411 Die.dump(OS, indent, DumpOpts);

2412 return OS;

2413}

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.

Definition DWARFVerifier.cpp:2032

static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx)

Definition DWARFVerifier.cpp:1897

static SmallVector< std::string, 3 > getNames(const DWARFDie &DIE, bool IncludeStrippedTemplateNames, bool IncludeObjCNames=true, bool IncludeLinkageName=true)

Constructs a full name for a DIE.

Definition DWARFVerifier.cpp:1622

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.

LLVM_ABI std::optional< uint64_t > getAsSectionOffset() const

LLVM_ABI std::optional< uint64_t > getAsRelativeReference() const

getAsFoo functions below return the extracted value as Foo if only DWARFFormValue has form class is s...

LLVM_ABI std::optional< uint64_t > getAsDebugInfoReference() const

LLVM_ABI std::optional< uint64_t > getAsUnsignedConstant() const

LLVM_ABI Expected< const char * > getAsCString() const

const DWARFUnit * getUnit() const

dwarf::Form getForm() const

uint64_t getRawUValue() const

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.

Definition DWARFVerifier.cpp:2175

LLVM_ABI bool verifyDebugStrOffsets(std::optional< dwarf::DwarfFormat > LegacyFormat, StringRef SectionName, const DWARFSection &Section, StringRef StrData)

Definition DWARFVerifier.cpp:2223

LLVM_ABI bool handleDebugTUIndex()

Verify the information in the .debug_tu_index section.

Definition DWARFVerifier.cpp:529

LLVM_ABI bool handleDebugStrOffsets()

Verify the information in the .debug_str_offsets[.dwo].

Definition DWARFVerifier.cpp:2193

LLVM_ABI bool handleDebugCUIndex()

Verify the information in the .debug_cu_index section.

Definition DWARFVerifier.cpp:524

LLVM_ABI DWARFVerifier(raw_ostream &S, DWARFContext &D, DIDumpOptions DumpOpts=DIDumpOptions::getForSingleDIE())

Definition DWARFVerifier.cpp:1194

LLVM_ABI bool handleDebugInfo()

Verify the information in the .debug_info and .debug_types sections.

Definition DWARFVerifier.cpp:534

LLVM_ABI bool handleDebugLine()

Verify the information in the .debug_line section.

Definition DWARFVerifier.cpp:1206

LLVM_ABI void summarize()

Emits any aggregate information collected, depending on the dump options.

Definition DWARFVerifier.cpp:2364

LLVM_ABI bool handleDebugAbbrev()

Verify the information in any of the following sections, if available: .debug_abbrev,...

Definition DWARFVerifier.cpp:404

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)

Definition DWARFVerifier.cpp:2348

LLVM_ABI void EnumerateDetailedResultsFor(StringRef category, std::function< void(StringRef, unsigned)> handleCounts)

Definition DWARFVerifier.cpp:2354

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 - 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.

Definition DWARFVerifier.cpp:94

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.

Definition DWARFVerifier.cpp:118

std::set< DieRangeInfo > Children

Sorted DWARFAddressRangeInfo.

LLVM_ABI std::optional< DWARFAddressRange > insert(const DWARFAddressRange &R)

Inserts the address range.

Definition DWARFVerifier.cpp:52