43using namespace dwarf_linker;
44using namespace dwarf_linker::classic;
55 for (
auto &Unit :
Dwarf.compile_units()) {
56 Size += Unit->getLength();
66 return LHS <
RHS->getOrigUnit().getNextUnitOffset();
68 return CU != Units.end() ?
CU->get() :
nullptr;
74DWARFDie DWARFLinker::resolveDIEReference(
const DWARFFile &File,
76 const DWARFFormValue &RefValue,
78 CompileUnit *&RefCU) {
81 if (std::optional<uint64_t> Off = RefValue.getAsRelativeReference()) {
82 RefOffset = RefValue.getUnit()->getOffset() + *Off;
83 }
else if (Off = RefValue.getAsDebugInfoReference(); Off) {
86 reportWarning(
"Unsupported reference type", File, &DIE);
90 if (
const auto RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) {
97 reportWarning(
"could not find referenced DIE", File, &DIE);
107 case dwarf::DW_AT_type:
108 case dwarf::DW_AT_containing_type:
109 case dwarf::DW_AT_specification:
110 case dwarf::DW_AT_abstract_origin:
111 case dwarf::DW_AT_import:
119 case dwarf::DW_TAG_array_type:
120 case dwarf::DW_TAG_class_type:
121 case dwarf::DW_TAG_enumeration_type:
122 case dwarf::DW_TAG_pointer_type:
123 case dwarf::DW_TAG_reference_type:
124 case dwarf::DW_TAG_string_type:
125 case dwarf::DW_TAG_structure_type:
126 case dwarf::DW_TAG_subroutine_type:
127 case dwarf::DW_TAG_template_alias:
128 case dwarf::DW_TAG_typedef:
129 case dwarf::DW_TAG_union_type:
130 case dwarf::DW_TAG_ptr_to_member_type:
131 case dwarf::DW_TAG_set_type:
132 case dwarf::DW_TAG_subrange_type:
133 case dwarf::DW_TAG_base_type:
134 case dwarf::DW_TAG_const_type:
135 case dwarf::DW_TAG_constant:
136 case dwarf::DW_TAG_file_type:
137 case dwarf::DW_TAG_namelist:
138 case dwarf::DW_TAG_packed_type:
139 case dwarf::DW_TAG_volatile_type:
140 case dwarf::DW_TAG_restrict_type:
141 case dwarf::DW_TAG_atomic_type:
142 case dwarf::DW_TAG_interface_type:
143 case dwarf::DW_TAG_unspecified_type:
144 case dwarf::DW_TAG_shared_type:
145 case dwarf::DW_TAG_immutable_type:
153bool DWARFLinker::DIECloner::getDIENames(
const DWARFDie &Die,
154 AttributesInfo &
Info,
156 bool StripTemplate) {
160 if (Die.getTag() == dwarf::DW_TAG_lexical_block)
163 if (!
Info.MangledName)
164 if (
const char *MangledName = Die.getLinkageName())
165 Info.MangledName = StringPool.getEntry(MangledName);
168 if (
const char *
Name = Die.getShortName())
169 Info.Name = StringPool.getEntry(
Name);
171 if (!
Info.MangledName)
174 if (StripTemplate &&
Info.Name &&
Info.MangledName !=
Info.Name) {
175 StringRef
Name =
Info.Name.getString();
177 Info.NameWithoutTemplate = StringPool.getEntry(*StrippedName);
180 return Info.Name ||
Info.MangledName;
194 std::function<
void(
const Twine &,
const DWARFDie &)> ReportWarning) {
195 if (
CU.getLanguage() != dwarf::DW_LANG_Swift)
198 if (!ParseableSwiftInterfaces)
202 if (!Path.ends_with(
".swiftinterface"))
207 SysRoot =
CU.getSysRoot();
208 if (!SysRoot.
empty() && Path.starts_with(SysRoot))
213 if (!DeveloperDir.
empty() && Path.starts_with(DeveloperDir))
217 std::optional<const char *>
Name =
221 auto &Entry = (*ParseableSwiftInterfaces)[*
Name];
223 DWARFDie CUDie =
CU.getOrigUnit().getUnitDIE();
228 if (!Entry.empty() && Entry != ResolvedPath)
229 ReportWarning(
Twine(
"Conflicting parseable interfaces for Swift Module ") +
230 *
Name +
": " + Entry +
" and " + Path,
232 Entry = std::string(ResolvedPath);
258 : Die(Die), ParentIdx(0), OtherInfo(OtherInfo),
Type(
T),
259 InImportedModule(
false) {}
262 bool InImportedModule)
263 : Die(Die), ParentIdx(ParentIdx), Context(Context),
265 InImportedModule(InImportedModule) {}
275 Info.Prune &= (Die.
getTag() == dwarf::DW_TAG_module) ||
281 if (ModulesEndOffset == 0)
282 Info.Prune &=
Info.Ctxt &&
Info.Ctxt->getCanonicalDIEOffset();
284 Info.Prune &=
Info.Ctxt &&
Info.Ctxt->getCanonicalDIEOffset() > 0 &&
285 Info.Ctxt->getCanonicalDIEOffset() <= ModulesEndOffset;
309 std::function<
void(
const Twine &,
const DWARFDie &)> ReportWarning) {
311 std::vector<ContextWorklistItem> Worklist;
312 Worklist.emplace_back(
DIE, CurrentDeclContext, ParentIdx,
false);
314 while (!Worklist.empty()) {
318 switch (Current.
Type) {
329 unsigned Idx =
CU.getOrigUnit().getDIEIndex(Current.
Die);
344 if (Current.
Die.
getTag() == dwarf::DW_TAG_module &&
347 CU.getClangModuleName()) {
355 if (
CU.hasODR() ||
Info.InModuleScope) {
359 Current.
Context = PtrInvalidPair.getPointer();
361 PtrInvalidPair.getInt() ? nullptr : PtrInvalidPair.getPointer();
363 Info.Ctxt->setDefinedInClangModule(
Info.InModuleScope);
374 Worklist.emplace_back(
376 Worklist.emplace_back(Child, Current.
Context,
Idx,
386 case dwarf::DW_TAG_class_type:
387 case dwarf::DW_TAG_common_block:
388 case dwarf::DW_TAG_lexical_block:
389 case dwarf::DW_TAG_structure_type:
390 case dwarf::DW_TAG_subprogram:
391 case dwarf::DW_TAG_subroutine_type:
392 case dwarf::DW_TAG_union_type:
398void DWARFLinker::cleanupAuxiliarryData(LinkContext &Context) {
401 for (DIEBlock *
I : DIEBlocks)
403 for (DIELoc *
I : DIELocs)
412 return DW_OP_Code == dwarf::DW_OP_form_tls_address ||
413 DW_OP_Code == dwarf::DW_OP_GNU_push_tls_address;
416std::pair<bool, std::optional<int64_t>>
417DWARFLinker::getVariableRelocAdjustment(AddressesMap &RelocMgr,
418 const DWARFDie &DIE) {
419 assert((DIE.getTag() == dwarf::DW_TAG_variable ||
420 DIE.getTag() == dwarf::DW_TAG_constant) &&
421 "Wrong type of input die");
423 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
426 DWARFUnit *U = DIE.getDwarfUnit();
427 std::optional<uint32_t> LocationIdx =
428 Abbrev->findAttributeIndex(dwarf::DW_AT_location);
430 return std::make_pair(
false, std::nullopt);
434 Abbrev->getAttributeOffsetFromIndex(*LocationIdx, DIE.getOffset(), *U);
437 std::optional<DWARFFormValue> LocationValue =
438 Abbrev->getAttributeValueFromOffset(*LocationIdx, AttrOffset, *U);
440 return std::make_pair(
false, std::nullopt);
445 std::optional<ArrayRef<uint8_t>> Expr = LocationValue->getAsBlock();
447 return std::make_pair(
false, std::nullopt);
450 DataExtractor
Data(
toStringRef(*Expr), U->getContext().isLittleEndian(),
451 U->getAddressByteSize());
452 DWARFExpression Expression(
Data, U->getAddressByteSize(),
453 U->getFormParams().Format);
455 bool HasLocationAddress =
false;
457 for (DWARFExpression::iterator It = Expression.begin();
458 It != Expression.end(); ++It) {
459 DWARFExpression::iterator NextIt = It;
462 const DWARFExpression::Operation &
Op = *It;
464 case dwarf::DW_OP_const2u:
465 case dwarf::DW_OP_const4u:
466 case dwarf::DW_OP_const8u:
467 case dwarf::DW_OP_const2s:
468 case dwarf::DW_OP_const4s:
469 case dwarf::DW_OP_const8s:
473 case dwarf::DW_OP_addr: {
474 HasLocationAddress =
true;
476 if (std::optional<int64_t> RelocAdjustment =
477 RelocMgr.getExprOpAddressRelocAdjustment(
478 *U,
Op, AttrOffset + CurExprOffset,
480 return std::make_pair(HasLocationAddress, *RelocAdjustment);
482 case dwarf::DW_OP_constx:
483 case dwarf::DW_OP_addrx: {
484 HasLocationAddress =
true;
485 if (std::optional<uint64_t> AddressOffset =
486 DIE.getDwarfUnit()->getIndexedAddressOffset(
489 if (std::optional<int64_t> RelocAdjustment =
490 RelocMgr.getExprOpAddressRelocAdjustment(
491 *U,
Op, *AddressOffset,
492 *AddressOffset + DIE.getDwarfUnit()->getAddressByteSize(),
494 return std::make_pair(HasLocationAddress, *RelocAdjustment);
504 return std::make_pair(HasLocationAddress, std::nullopt);
509unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr,
511 CompileUnit::DIEInfo &MyInfo,
513 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
516 if (!(Flags & TF_InFunctionScope) &&
517 Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
518 MyInfo.InDebugMap =
true;
519 return Flags | TF_Keep;
527 std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
528 getVariableRelocAdjustment(RelocMgr, DIE);
530 if (LocExprAddrAndRelocAdjustment.first)
531 MyInfo.HasLocationExpressionAddr =
true;
533 if (!LocExprAddrAndRelocAdjustment.second)
536 MyInfo.AddrAdjust = *LocExprAddrAndRelocAdjustment.second;
537 MyInfo.InDebugMap =
true;
539 if (((Flags & TF_InFunctionScope) &&
543 if (Options.Verbose) {
544 outs() <<
"Keeping variable DIE:";
545 DIDumpOptions DumpOpts;
546 DumpOpts.ChildRecurseDepth = 0;
547 DumpOpts.Verbose = Options.Verbose;
548 DIE.dump(
outs(), 8 , DumpOpts);
551 return Flags | TF_Keep;
556unsigned DWARFLinker::shouldKeepSubprogramDIE(
557 AddressesMap &RelocMgr,
const DWARFDie &DIE,
const DWARFFile &File,
558 CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
unsigned Flags) {
559 Flags |= TF_InFunctionScope;
565 assert(LowPc &&
"low_pc attribute is not an address.");
566 std::optional<int64_t> RelocAdjustment =
567 RelocMgr.getSubprogramRelocAdjustment(DIE, Options.Verbose);
568 if (!RelocAdjustment)
571 MyInfo.AddrAdjust = *RelocAdjustment;
572 MyInfo.InDebugMap =
true;
574 if (Options.Verbose) {
575 outs() <<
"Keeping subprogram DIE:";
576 DIDumpOptions DumpOpts;
577 DumpOpts.ChildRecurseDepth = 0;
578 DumpOpts.Verbose = Options.Verbose;
579 DIE.dump(
outs(), 8 , DumpOpts);
582 if (DIE.getTag() == dwarf::DW_TAG_label) {
583 if (Unit.hasLabelAt(*LowPc))
586 DWARFUnit &OrigUnit = Unit.getOrigUnit();
594 Unit.addLabelLowPc(*LowPc, MyInfo.AddrAdjust);
595 return Flags | TF_Keep;
600 std::optional<uint64_t> HighPc = DIE.getHighPC(*LowPc);
602 reportWarning(
"Function without high_pc. Range will be discarded.\n", File,
606 if (*LowPc > *HighPc) {
607 reportWarning(
"low_pc greater than high_pc. Range will be discarded.\n",
613 Unit.addFunctionRange(*LowPc, *HighPc, MyInfo.AddrAdjust);
619unsigned DWARFLinker::shouldKeepDIE(AddressesMap &RelocMgr,
const DWARFDie &DIE,
620 const DWARFFile &File, CompileUnit &Unit,
621 CompileUnit::DIEInfo &MyInfo,
623 switch (DIE.getTag()) {
624 case dwarf::DW_TAG_constant:
625 case dwarf::DW_TAG_variable:
626 return shouldKeepVariableDIE(RelocMgr, DIE, MyInfo, Flags);
627 case dwarf::DW_TAG_subprogram:
628 case dwarf::DW_TAG_label:
629 return shouldKeepSubprogramDIE(RelocMgr, DIE, File, Unit, MyInfo, Flags);
630 case dwarf::DW_TAG_base_type:
633 case dwarf::DW_TAG_imported_module:
634 case dwarf::DW_TAG_imported_declaration:
635 case dwarf::DW_TAG_imported_unit:
637 return Flags | TF_Keep;
651 case dwarf::DW_TAG_structure_type:
652 case dwarf::DW_TAG_class_type:
653 case dwarf::DW_TAG_union_type:
671 case dwarf::DW_TAG_typedef:
672 case dwarf::DW_TAG_member:
673 case dwarf::DW_TAG_reference_type:
674 case dwarf::DW_TAG_ptr_to_member_type:
675 case dwarf::DW_TAG_pointer_type:
692void DWARFLinker::lookForChildDIEsToKeep(
693 const DWARFDie &Die, CompileUnit &
CU,
unsigned Flags,
694 SmallVectorImpl<WorklistItem> &Worklist) {
701 Flags &= ~DWARFLinker::TF_ParentWalk;
705 if (!Die.hasChildren() || (Flags & DWARFLinker::TF_ParentWalk))
710 for (
auto Child :
reverse(Die.children())) {
713 CompileUnit::DIEInfo &ChildInfo =
CU.getInfo(Child);
714 Worklist.emplace_back(Die,
CU, WorklistItemType::UpdateChildIncompleteness,
716 Worklist.emplace_back(Child,
CU, Flags);
723 if (!
Info.Ctxt || (Die.
getTag() == dwarf::DW_TAG_namespace))
726 if (!
CU.hasODR() && !
Info.InModuleScope)
729 return !
Info.Incomplete &&
Info.Ctxt !=
CU.getInfo(
Info.ParentIdx).Ctxt;
732void DWARFLinker::markODRCanonicalDie(
const DWARFDie &Die, CompileUnit &
CU) {
733 CompileUnit::DIEInfo &
Info =
CU.getInfo(Die);
735 Info.ODRMarkingDone =
true;
737 !
Info.Ctxt->hasCanonicalDIE())
738 Info.Ctxt->setHasCanonicalDIE();
743void DWARFLinker::lookForRefDIEsToKeep(
744 const DWARFDie &Die, CompileUnit &
CU,
unsigned Flags,
745 const UnitListTy &Units,
const DWARFFile &File,
746 SmallVectorImpl<WorklistItem> &Worklist) {
747 bool UseOdr = (
Flags & DWARFLinker::TF_DependencyWalk)
748 ? (Flags & DWARFLinker::TF_ODR)
750 DWARFUnit &Unit =
CU.getOrigUnit();
751 DWARFDataExtractor
Data = Unit.getDebugInfoExtractor();
752 const auto *Abbrev = Die.getAbbreviationDeclarationPtr();
755 SmallVector<std::pair<DWARFDie, CompileUnit &>, 4> ReferencedDIEs;
756 for (
const auto &AttrSpec : Abbrev->attributes()) {
757 DWARFFormValue Val(AttrSpec.Form);
759 AttrSpec.Attr == dwarf::DW_AT_sibling) {
761 Unit.getFormParams());
765 Val.extractValue(
Data, &
Offset, Unit.getFormParams(), &Unit);
766 CompileUnit *ReferencedCU;
768 resolveDIEReference(File, Units, Val, Die, ReferencedCU)) {
769 CompileUnit::DIEInfo &
Info = ReferencedCU->getInfo(RefDie);
780 if (AttrSpec.Form != dwarf::DW_FORM_ref_addr &&
782 Info.Ctxt->hasCanonicalDIE())
787 Info.Ctxt->hasCanonicalDIE()))
789 ReferencedDIEs.emplace_back(RefDie, *ReferencedCU);
793 unsigned ODRFlag = UseOdr ? DWARFLinker::TF_ODR : 0;
797 for (
auto &
P :
reverse(ReferencedDIEs)) {
800 CompileUnit::DIEInfo &
Info =
P.second.getInfo(
P.first);
801 Worklist.emplace_back(Die,
CU, WorklistItemType::UpdateRefIncompleteness,
803 Worklist.emplace_back(
P.first,
P.second,
804 DWARFLinker::TF_Keep |
805 DWARFLinker::TF_DependencyWalk | ODRFlag);
810void DWARFLinker::lookForParentDIEsToKeep(
811 unsigned AncestorIdx, CompileUnit &
CU,
unsigned Flags,
812 SmallVectorImpl<WorklistItem> &Worklist) {
814 if (
CU.getInfo(AncestorIdx).Keep)
817 DWARFUnit &Unit =
CU.getOrigUnit();
818 DWARFDie ParentDIE = Unit.getDIEAtIndex(AncestorIdx);
819 Worklist.emplace_back(
CU.getInfo(AncestorIdx).ParentIdx,
CU, Flags);
820 Worklist.emplace_back(ParentDIE,
CU, Flags);
848void DWARFLinker::lookForDIEsToKeep(AddressesMap &AddressesMap,
850 const DWARFDie &Die,
const DWARFFile &File,
851 CompileUnit &Cu,
unsigned Flags) {
853 SmallVector<WorklistItem, 4> Worklist;
854 Worklist.emplace_back(Die, Cu, Flags);
856 while (!Worklist.empty()) {
857 WorklistItem Current = Worklist.pop_back_val();
860 switch (Current.Type) {
861 case WorklistItemType::UpdateChildIncompleteness:
864 case WorklistItemType::UpdateRefIncompleteness:
867 case WorklistItemType::LookForChildDIEsToKeep:
868 lookForChildDIEsToKeep(Current.Die, Current.CU, Current.Flags, Worklist);
870 case WorklistItemType::LookForRefDIEsToKeep:
871 lookForRefDIEsToKeep(Current.Die, Current.CU, Current.Flags, Units, File,
874 case WorklistItemType::LookForParentDIEsToKeep:
875 lookForParentDIEsToKeep(Current.AncestorIdx, Current.CU, Current.Flags,
878 case WorklistItemType::MarkODRCanonicalDie:
879 markODRCanonicalDie(Current.Die, Current.CU);
881 case WorklistItemType::LookForDIEsToKeep:
885 unsigned Idx = Current.CU.getOrigUnit().getDIEIndex(Current.Die);
886 CompileUnit::DIEInfo &MyInfo = Current.CU.getInfo(
Idx);
891 if (Current.Flags & TF_DependencyWalk)
892 MyInfo.Prune =
false;
899 bool AlreadyKept = MyInfo.Keep;
900 if ((Current.Flags & TF_DependencyWalk) && AlreadyKept)
903 if (!(Current.Flags & TF_DependencyWalk))
904 Current.Flags = shouldKeepDIE(AddressesMap, Current.Die, File, Current.CU,
905 MyInfo, Current.Flags);
910 if (!(Current.Flags & TF_DependencyWalk) ||
911 (MyInfo.ODRMarkingDone && !MyInfo.Keep)) {
912 if (Current.CU.hasODR() || MyInfo.InModuleScope)
913 Worklist.emplace_back(Current.Die, Current.CU,
914 WorklistItemType::MarkODRCanonicalDie);
920 Worklist.emplace_back(Current.Die, Current.CU, Current.Flags,
921 WorklistItemType::LookForChildDIEsToKeep);
923 if (AlreadyKept || !(Current.Flags & TF_Keep))
932 Current.Die.getTag() != dwarf::DW_TAG_subprogram &&
933 Current.Die.getTag() != dwarf::DW_TAG_member &&
939 Worklist.emplace_back(Current.Die, Current.CU, Current.Flags,
940 WorklistItemType::LookForRefDIEsToKeep);
942 bool UseOdr = (Current.Flags & TF_DependencyWalk) ? (Current.Flags & TF_ODR)
943 : Current.CU.hasODR();
944 unsigned ODRFlag = UseOdr ? TF_ODR : 0;
945 unsigned ParFlags = TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag;
948 Worklist.emplace_back(MyInfo.ParentIdx, Current.CU, ParFlags);
964 std::vector<DWARFDie> Worklist;
965 Worklist.push_back(
CU.getOrigUnit().getUnitDIE());
968 std::vector<BrokenLink> BrokenLinks;
970 while (!Worklist.empty()) {
971 const DWARFDie Current = Worklist.back();
974 const bool CurrentDieIsKept =
CU.getInfo(Current).Keep;
977 Worklist.push_back(Child);
979 const bool ChildDieIsKept =
CU.getInfo(Child).Keep;
980 if (!CurrentDieIsKept && ChildDieIsKept)
981 BrokenLinks.emplace_back(Current, Child);
985 if (!BrokenLinks.empty()) {
988 "Found invalid link in keep chain between {0:x} and {1:x}\n",
989 Link.Parent.getOffset(), Link.Child.getOffset());
992 Link.Parent.dump(
errs(), 0, {});
993 CU.getInfo(Link.Parent).dump();
996 Link.Child.dump(
errs(), 2, {});
997 CU.getInfo(Link.Child).dump();
1010void DWARFLinker::assignAbbrev(DIEAbbrev &Abbrev) {
1012 FoldingSetNodeID
ID;
1015 DIEAbbrev *InSet = AbbreviationsSet.FindNodeOrInsertPos(
ID, InsertToken);
1020 Abbrev.setNumber(InSet->getNumber());
1023 Abbreviations.push_back(
1024 std::make_unique<DIEAbbrev>(Abbrev.getTag(), Abbrev.hasChildren()));
1025 for (
const auto &Attr : Abbrev.getData())
1026 Abbreviations.back()->AddAttribute(Attr);
1027 AbbreviationsSet.InsertNode(Abbreviations.back().get(), InsertToken);
1029 Abbrev.setNumber(Abbreviations.size());
1030 Abbreviations.back()->setNumber(Abbreviations.size());
1034unsigned DWARFLinker::DIECloner::cloneStringAttribute(DIE &Die,
1035 AttributeSpec AttrSpec,
1036 const DWARFFormValue &Val,
1038 AttributesInfo &
Info) {
1043 if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
1048 if (AttrSpec.Attr == dwarf::DW_AT_APPLE_origin) {
1049 Info.HasAppleOrigin =
true;
1050 if (std::optional<StringRef> FileName =
1051 ObjFile.Addresses->getLibraryInstallName()) {
1057 if (AttrSpec.Attr == dwarf::DW_AT_name)
1059 else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name ||
1060 AttrSpec.Attr == dwarf::DW_AT_linkage_name)
1062 if (
U.getVersion() >= 5) {
1064 auto StringOffsetIndex =
1065 StringOffsetPool.getValueIndex(
StringEntry.getOffset());
1068 dwarf::DW_FORM_strx, DIEInteger(StringOffsetIndex))
1069 ->sizeOf(
U.getFormParams());
1072 AttrSpec.Form = dwarf::DW_FORM_strp;
1079unsigned DWARFLinker::DIECloner::cloneDieReferenceAttribute(
1080 DIE &Die,
const DWARFDie &InputDIE, AttributeSpec AttrSpec,
1081 unsigned AttrSize,
const DWARFFormValue &Val,
const DWARFFile &File,
1082 CompileUnit &Unit) {
1083 const DWARFUnit &
U = Unit.getOrigUnit();
1085 if (std::optional<uint64_t> Off = Val.getAsRelativeReference())
1086 Ref = Val.getUnit()->getOffset() + *
Off;
1087 else if (Off = Val.getAsDebugInfoReference(); Off)
1092 DIE *NewRefDie =
nullptr;
1093 CompileUnit *RefUnit =
nullptr;
1096 Linker.resolveDIEReference(File, CompileUnits, Val, InputDIE, RefUnit);
1099 if (!RefDie || AttrSpec.Attr == dwarf::DW_AT_sibling)
1102 CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(RefDie);
1107 RefInfo.Ctxt->getCanonicalDIEOffset()) {
1108 assert(RefInfo.Ctxt->hasCanonicalDIE() &&
1109 "Offset to canonical die is set, but context is not marked");
1110 DIEInteger Attr(RefInfo.Ctxt->getCanonicalDIEOffset());
1112 dwarf::DW_FORM_ref_addr, Attr);
1113 return U.getRefAddrByteSize();
1116 if (!RefInfo.Clone) {
1119 RefInfo.UnclonedReference =
true;
1122 NewRefDie = RefInfo.Clone;
1124 if (AttrSpec.Form == dwarf::DW_FORM_ref_addr ||
1132 if (
Ref < InputDIE.getOffset() && !RefInfo.UnclonedReference) {
1135 RefUnit->getStartOffset() + NewRefDie->getOffset();
1136 Attr = NewRefOffset;
1138 dwarf::DW_FORM_ref_addr, DIEInteger(Attr));
1142 Unit.noteForwardReference(
1143 NewRefDie, RefUnit, RefInfo.Ctxt,
1145 dwarf::DW_FORM_ref_addr, DIEInteger(Attr)));
1147 return U.getRefAddrByteSize();
1151 dwarf::Form(AttrSpec.Form), DIEEntry(*NewRefDie));
1156void DWARFLinker::DIECloner::cloneExpression(
1157 DataExtractor &
Data, DWARFExpression Expression,
const DWARFFile &File,
1158 CompileUnit &Unit, SmallVectorImpl<uint8_t> &
OutputBuffer,
1159 int64_t AddrRelocAdjustment,
bool IsLittleEndian) {
1162 uint8_t OrigAddressByteSize = Unit.getOrigUnit().getAddressByteSize();
1165 for (
auto &
Op : Expression) {
1171 Desc.
Op[0] != Encoding::Size1))
1172 Linker.reportWarning(
"Unsupported DW_OP encoding.", File);
1176 Desc.
Op[0] == Encoding::Size1)) {
1196 if (RefOffset > 0 ||
Op.
getCode() != dwarf::DW_OP_convert) {
1197 RefOffset += Unit.getOrigUnit().getOffset();
1198 auto RefDie = Unit.getOrigUnit().getDIEForOffset(RefOffset);
1199 CompileUnit::DIEInfo &
Info = Unit.getInfo(RefDie);
1200 if (DIE *Clone =
Info.Clone)
1201 Offset = Clone->getOffset();
1203 Linker.reportWarning(
1204 "base type ref doesn't point to DW_TAG_base_type.", File);
1208 if (RealSize > ULEBsize) {
1211 Linker.reportWarning(
"base type ref doesn't fit.", File);
1213 assert(RealSize == ULEBsize &&
"padding failed");
1214 ArrayRef<uint8_t> ULEBbytes(ULEB, ULEBsize);
1215 OutputBuffer.append(ULEBbytes.begin(), ULEBbytes.end());
1216 }
else if (!Linker.Options.Update &&
Op.
getCode() == dwarf::DW_OP_addrx) {
1217 if (std::optional<object::SectionedAddress> SA =
1218 Unit.getOrigUnit().getAddrOffsetSectionItem(
1225 uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment;
1228 ArrayRef<uint8_t> AddressBytes(
1229 reinterpret_cast<const uint8_t *
>(&LinkedAddress),
1230 OrigAddressByteSize);
1231 OutputBuffer.append(AddressBytes.begin(), AddressBytes.end());
1233 Linker.reportWarning(
"cannot read DW_OP_addrx operand.", File);
1234 }
else if (!Linker.Options.Update &&
Op.
getCode() == dwarf::DW_OP_constx) {
1235 if (std::optional<object::SectionedAddress> SA =
1236 Unit.getOrigUnit().getAddrOffsetSectionItem(
1242 std::optional<uint8_t> OutOperandKind;
1243 switch (OrigAddressByteSize) {
1245 OutOperandKind = dwarf::DW_OP_const4u;
1248 OutOperandKind = dwarf::DW_OP_const8u;
1251 Linker.reportWarning(
1252 formatv((
"unsupported address size: {0}."), OrigAddressByteSize),
1257 if (OutOperandKind) {
1259 uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment;
1262 ArrayRef<uint8_t> AddressBytes(
1263 reinterpret_cast<const uint8_t *
>(&LinkedAddress),
1264 OrigAddressByteSize);
1265 OutputBuffer.append(AddressBytes.begin(), AddressBytes.end());
1268 Linker.reportWarning(
"cannot read DW_OP_constx operand.", File);
1278unsigned DWARFLinker::DIECloner::cloneBlockAttribute(
1279 DIE &Die,
const DWARFDie &InputDIE,
const DWARFFile &File,
1280 CompileUnit &Unit, AttributeSpec AttrSpec,
const DWARFFormValue &Val,
1281 bool IsLittleEndian) {
1284 DIELoc *Loc =
nullptr;
1285 DIEBlock *
Block =
nullptr;
1286 if (AttrSpec.Form == dwarf::DW_FORM_exprloc) {
1287 Loc =
new (DIEAlloc) DIELoc;
1288 Linker.DIELocs.push_back(Loc);
1290 Block =
new (DIEAlloc) DIEBlock;
1291 Linker.DIEBlocks.push_back(
Block);
1293 Attr = Loc ?
static_cast<DIEValueList *
>(Loc)
1294 :
static_cast<DIEValueList *
>(
Block);
1296 DWARFUnit &OrigUnit = Unit.getOrigUnit();
1299 SmallVector<uint8_t, 32> Buffer;
1300 ArrayRef<uint8_t> Bytes = *Val.getAsBlock();
1304 DataExtractor
Data(StringRef((
const char *)Bytes.data(), Bytes.size()),
1305 IsLittleEndian, OrigUnit.getAddressByteSize());
1306 DWARFExpression Expr(
Data, OrigUnit.getAddressByteSize(),
1307 OrigUnit.getFormParams().Format);
1308 cloneExpression(
Data, Expr, File, Unit, Buffer,
1309 Unit.getInfo(InputDIE).AddrAdjust, IsLittleEndian);
1312 for (
auto Byte : Bytes)
1314 dwarf::DW_FORM_data1, DIEInteger(Byte));
1320 Loc->setSize(Bytes.size());
1322 Block->setSize(Bytes.size());
1330 if ((AttrSpec.Form == dwarf::DW_FORM_block1 &&
1331 (Bytes.size() > UINT8_MAX)) ||
1332 (AttrSpec.Form == dwarf::DW_FORM_block2 &&
1333 (Bytes.size() > UINT16_MAX)) ||
1334 (AttrSpec.Form == dwarf::DW_FORM_block4 && (Bytes.size() > UINT32_MAX)))
1335 AttrSpec.Form = dwarf::DW_FORM_block;
1341 return Die.addValue(DIEAlloc, Value)->sizeOf(OrigUnit.getFormParams());
1344unsigned DWARFLinker::DIECloner::cloneAddressAttribute(
1345 DIE &Die,
const DWARFDie &InputDIE, AttributeSpec AttrSpec,
1346 unsigned AttrSize,
const DWARFFormValue &Val,
const CompileUnit &Unit,
1347 AttributesInfo &
Info) {
1348 if (AttrSpec.Attr == dwarf::DW_AT_low_pc)
1349 Info.HasLowPc =
true;
1353 dwarf::Form(AttrSpec.Form), DIEInteger(Val.getRawUValue()));
1369 std::optional<DWARFFormValue> AddrAttribute = InputDIE.find(AttrSpec.Attr);
1373 std::optional<uint64_t>
Addr = AddrAttribute->getAsAddress();
1375 Linker.reportWarning(
"Cann't read address attribute value.", ObjFile);
1379 if (InputDIE.getTag() == dwarf::DW_TAG_compile_unit &&
1380 AttrSpec.Attr == dwarf::DW_AT_low_pc) {
1381 if (std::optional<uint64_t> LowPC = Unit.getLowPc())
1385 }
else if (InputDIE.getTag() == dwarf::DW_TAG_compile_unit &&
1386 AttrSpec.Attr == dwarf::DW_AT_high_pc) {
1387 if (
uint64_t HighPc = Unit.getHighPc())
1395 if (AttrSpec.Form == dwarf::DW_FORM_addr) {
1397 AttrSpec.Form, DIEInteger(*
Addr));
1398 return Unit.getOrigUnit().getAddressByteSize();
1401 auto AddrIndex = AddrPool.getValueIndex(*
Addr);
1405 dwarf::Form::DW_FORM_addrx, DIEInteger(AddrIndex))
1406 ->sizeOf(Unit.getOrigUnit().getFormParams());
1409unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
1410 DIE &Die,
const DWARFDie &InputDIE,
const DWARFFile &File,
1411 CompileUnit &Unit, AttributeSpec AttrSpec,
const DWARFFormValue &Val,
1412 unsigned AttrSize, AttributesInfo &
Info) {
1417 if (AttrSpec.Attr == dwarf::DW_AT_GNU_dwo_id ||
1418 AttrSpec.Attr == dwarf::DW_AT_dwo_id)
1423 if (AttrSpec.Attr == dwarf::DW_AT_macro_info) {
1424 if (std::optional<uint64_t>
Offset = Val.getAsSectionOffset()) {
1431 if (AttrSpec.Attr == dwarf::DW_AT_macros) {
1432 if (std::optional<uint64_t>
Offset = Val.getAsSectionOffset()) {
1439 if (AttrSpec.Attr == dwarf::DW_AT_str_offsets_base) {
1443 Info.AttrStrOffsetBaseSeen =
true;
1445 .addValue(DIEAlloc, dwarf::DW_AT_str_offsets_base,
1446 dwarf::DW_FORM_sec_offset, DIEInteger(8))
1447 ->sizeOf(Unit.getOrigUnit().getFormParams());
1451 if (
auto OptionalValue = Val.getAsUnsignedConstant())
1452 Value = *OptionalValue;
1453 else if (
auto OptionalValue = Val.getAsSignedConstant())
1454 Value = *OptionalValue;
1455 else if (
auto OptionalValue = Val.getAsSectionOffset())
1456 Value = *OptionalValue;
1458 Linker.reportWarning(
1459 "Unsupported scalar attribute form. Dropping attribute.", File,
1463 if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
1464 Info.IsDeclaration =
true;
1466 if (AttrSpec.Form == dwarf::DW_FORM_loclistx)
1475 [[maybe_unused]]
dwarf::Form OriginalForm = AttrSpec.Form;
1476 if (AttrSpec.Form == dwarf::DW_FORM_rnglistx) {
1480 std::optional<uint64_t>
Index = Val.getAsSectionOffset();
1482 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1486 std::optional<uint64_t>
Offset =
1487 Unit.getOrigUnit().getRnglistOffset(*
Index);
1489 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1495 AttrSpec.Form = dwarf::DW_FORM_sec_offset;
1496 AttrSize = Unit.getOrigUnit().getFormParams().getDwarfOffsetByteSize();
1497 }
else if (AttrSpec.Form == dwarf::DW_FORM_loclistx) {
1501 std::optional<uint64_t>
Index = Val.getAsSectionOffset();
1503 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1507 std::optional<uint64_t>
Offset =
1508 Unit.getOrigUnit().getLoclistOffset(*
Index);
1510 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1516 AttrSpec.Form = dwarf::DW_FORM_sec_offset;
1517 AttrSize = Unit.getOrigUnit().getFormParams().getDwarfOffsetByteSize();
1518 }
else if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
1519 Die.getTag() == dwarf::DW_TAG_compile_unit) {
1520 std::optional<uint64_t> LowPC = Unit.getLowPc();
1524 Value = Unit.getHighPc() - *LowPC;
1525 }
else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)
1526 Value = *Val.getAsSectionOffset();
1527 else if (AttrSpec.Form == dwarf::DW_FORM_sdata)
1528 Value = *Val.getAsSignedConstant();
1529 else if (
auto OptionalValue = Val.getAsUnsignedConstant())
1530 Value = *OptionalValue;
1532 Linker.reportWarning(
1533 "Unsupported scalar attribute form. Dropping attribute.", File,
1538 DIE::value_iterator Patch =
1541 if (AttrSpec.Attr == dwarf::DW_AT_ranges ||
1542 AttrSpec.Attr == dwarf::DW_AT_start_scope) {
1543 Unit.noteRangeAttribute(Die, Patch);
1544 Info.HasRanges =
true;
1548 Unit.getOrigUnit().getVersion())) {
1550 CompileUnit::DIEInfo &LocationDieInfo = Unit.getInfo(InputDIE);
1551 Unit.noteLocationAttribute({Patch, LocationDieInfo.InDebugMap
1552 ? LocationDieInfo.AddrAdjust
1554 }
else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
1555 Info.IsDeclaration =
true;
1558 assert((
Info.HasRanges || (OriginalForm != dwarf::DW_FORM_rnglistx)) &&
1559 "Unhandled DW_FORM_rnglistx attribute");
1567unsigned DWARFLinker::DIECloner::cloneAttribute(
1568 DIE &Die,
const DWARFDie &InputDIE,
const DWARFFile &File,
1569 CompileUnit &Unit,
const DWARFFormValue &Val,
const AttributeSpec AttrSpec,
1570 unsigned AttrSize, AttributesInfo &
Info,
bool IsLittleEndian) {
1571 const DWARFUnit &
U = Unit.getOrigUnit();
1573 switch (AttrSpec.Form) {
1574 case dwarf::DW_FORM_strp:
1575 case dwarf::DW_FORM_line_strp:
1576 case dwarf::DW_FORM_string:
1577 case dwarf::DW_FORM_strx:
1578 case dwarf::DW_FORM_strx1:
1579 case dwarf::DW_FORM_strx2:
1580 case dwarf::DW_FORM_strx3:
1581 case dwarf::DW_FORM_strx4:
1582 return cloneStringAttribute(Die, AttrSpec, Val, U,
Info);
1583 case dwarf::DW_FORM_ref_addr:
1584 case dwarf::DW_FORM_ref1:
1585 case dwarf::DW_FORM_ref2:
1586 case dwarf::DW_FORM_ref4:
1587 case dwarf::DW_FORM_ref8:
1588 return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val,
1590 case dwarf::DW_FORM_block:
1591 case dwarf::DW_FORM_block1:
1592 case dwarf::DW_FORM_block2:
1593 case dwarf::DW_FORM_block4:
1594 case dwarf::DW_FORM_exprloc:
1595 return cloneBlockAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,
1597 case dwarf::DW_FORM_addr:
1598 case dwarf::DW_FORM_addrx:
1599 case dwarf::DW_FORM_addrx1:
1600 case dwarf::DW_FORM_addrx2:
1601 case dwarf::DW_FORM_addrx3:
1602 case dwarf::DW_FORM_addrx4:
1603 return cloneAddressAttribute(Die, InputDIE, AttrSpec, AttrSize, Val, Unit,
1605 case dwarf::DW_FORM_data1:
1606 case dwarf::DW_FORM_data2:
1607 case dwarf::DW_FORM_data4:
1608 case dwarf::DW_FORM_data8:
1609 case dwarf::DW_FORM_udata:
1610 case dwarf::DW_FORM_sdata:
1611 case dwarf::DW_FORM_sec_offset:
1612 case dwarf::DW_FORM_flag:
1613 case dwarf::DW_FORM_flag_present:
1614 case dwarf::DW_FORM_rnglistx:
1615 case dwarf::DW_FORM_loclistx:
1616 case dwarf::DW_FORM_implicit_const:
1617 return cloneScalarAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,
1620 Linker.reportWarning(
"Unsupported attribute form " +
1622 " in cloneAttribute. Dropping.",
1629void DWARFLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit,
1631 DwarfStringPoolEntryRef
Name,
1633 bool SkipPubSection) {
1634 std::optional<ObjCSelectorNames> Names =
1638 Unit.addNameAccelerator(Die, StringPool.getEntry(Names->Selector),
1640 Unit.addObjCAccelerator(Die, StringPool.getEntry(Names->ClassName),
1642 if (Names->ClassNameNoCategory)
1643 Unit.addObjCAccelerator(
1644 Die, StringPool.getEntry(*Names->ClassNameNoCategory), SkipPubSection);
1645 if (Names->MethodNameNoCategory)
1646 Unit.addNameAccelerator(
1647 Die, StringPool.getEntry(*Names->MethodNameNoCategory), SkipPubSection);
1654 switch (AttrSpec.
Attr) {
1657 case dwarf::DW_AT_low_pc:
1658 case dwarf::DW_AT_high_pc:
1659 case dwarf::DW_AT_ranges:
1660 return !Update && SkipPC;
1661 case dwarf::DW_AT_rnglists_base:
1667 case dwarf::DW_AT_loclists_base:
1673 case dwarf::DW_AT_location:
1674 case dwarf::DW_AT_frame_base:
1675 return !Update && SkipPC;
1685DIE *DWARFLinker::DIECloner::cloneDIE(
const DWARFDie &InputDIE,
1687 int64_t PCOffset,
uint32_t OutOffset,
1688 unsigned Flags,
bool IsLittleEndian,
1691 unsigned Idx = U.getDIEIndex(InputDIE);
1695 if (!Unit.getInfo(
Idx).Keep)
1699 assert(!(Die &&
Info.Clone) &&
"Can't supply a DIE and a cloned DIE");
1711 (
Info.Ctxt->getCanonicalDIEOffset() == 0)) {
1712 if (!
Info.Ctxt->hasCanonicalDIE())
1713 Info.Ctxt->setHasCanonicalDIE();
1717 Info.Ctxt->setCanonicalDIEOffset(OutOffset + Unit.getStartOffset());
1721 DWARFDataExtractor
Data =
U.getDebugInfoExtractor();
1726 ?
U.getDIEAtIndex(
Idx + 1).getOffset()
1727 :
U.getNextUnitOffset();
1728 AttributesInfo AttrInfo;
1733 SmallString<40> DIECopy(
Data.getData().substr(
Offset, NextOffset -
Offset));
1735 DWARFDataExtractor(DIECopy,
Data.isLittleEndian(),
Data.getAddressSize());
1738 ObjFile.Addresses->applyValidRelocs(DIECopy,
Offset,
Data.isLittleEndian());
1748 if (Die->
getTag() == dwarf::DW_TAG_subprogram)
1749 PCOffset =
Info.AddrAdjust;
1750 AttrInfo.PCOffset = PCOffset;
1752 if (Abbrev->getTag() == dwarf::DW_TAG_subprogram) {
1753 Flags |= TF_InFunctionScope;
1756 }
else if (Abbrev->getTag() == dwarf::DW_TAG_variable) {
1759 if ((Flags & TF_InFunctionScope) &&
Info.InDebugMap)
1760 Flags &= ~TF_SkipPC;
1763 else if (!
Info.InDebugMap &&
Info.HasLocationExpressionAddr &&
1768 std::optional<StringRef> LibraryInstallName =
1769 ObjFile.Addresses->getLibraryInstallName();
1770 SmallVector<AttributeLinkedOffsetFixup> AttributesFixups;
1771 for (
const auto &AttrSpec : Abbrev->attributes()) {
1778 AttributeLinkedOffsetFixup CurAttrFixup;
1780 CurAttrFixup.LinkedOffsetFixupVal =
1781 Unit.getStartOffset() + OutOffset - CurAttrFixup.InputAttrStartOffset;
1783 DWARFFormValue Val = AttrSpec.getFormValue();
1785 Val.extractValue(
Data, &
Offset,
U.getFormParams(), &U);
1787 AttrSize =
Offset - AttrSize;
1790 cloneAttribute(*Die, InputDIE, File, Unit, Val, AttrSpec, AttrSize,
1791 AttrInfo, IsLittleEndian);
1792 if (FinalAttrSize != 0 && ObjFile.Addresses->needToSaveValidRelocs())
1793 AttributesFixups.push_back(CurAttrFixup);
1795 OutOffset += FinalAttrSize;
1801 const bool NeedsAppleOrigin = (
Tag == dwarf::DW_TAG_compile_unit) &&
1802 LibraryInstallName.has_value() &&
1803 !AttrInfo.HasAppleOrigin;
1804 if (NeedsAppleOrigin) {
1805 auto StringEntry = DebugStrPool.getEntry(LibraryInstallName.value());
1807 dwarf::DW_FORM_strp, DIEInteger(
StringEntry.getOffset()));
1816 if ((
Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&
1817 Tag != dwarf::DW_TAG_compile_unit &&
1818 getDIENames(InputDIE, AttrInfo, DebugStrPool,
1819 Tag != dwarf::DW_TAG_inlined_subroutine)) {
1820 if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
1821 Unit.addNameAccelerator(Die, AttrInfo.MangledName,
1822 Tag == dwarf::DW_TAG_inlined_subroutine);
1823 if (AttrInfo.Name) {
1824 if (AttrInfo.NameWithoutTemplate)
1825 Unit.addNameAccelerator(Die, AttrInfo.NameWithoutTemplate,
1827 Unit.addNameAccelerator(Die, AttrInfo.Name,
1828 Tag == dwarf::DW_TAG_inlined_subroutine);
1831 addObjCAccelerator(Unit, Die, AttrInfo.Name, DebugStrPool,
1834 }
else if (
Tag == dwarf::DW_TAG_namespace) {
1836 AttrInfo.Name = DebugStrPool.getEntry(
"(anonymous namespace)");
1837 Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
1838 }
else if (
Tag == dwarf::DW_TAG_imported_declaration && AttrInfo.Name) {
1839 Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
1840 }
else if (
isTypeTag(
Tag) && !AttrInfo.IsDeclaration &&
1841 getDIENames(InputDIE, AttrInfo, DebugStrPool) && AttrInfo.Name &&
1842 AttrInfo.Name.getString()[0]) {
1847 bool ObjCClassIsImplementation =
1848 (RuntimeLang == dwarf::DW_LANG_ObjC ||
1849 RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
1852 Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation,
1857 bool HasChildren =
false;
1858 for (
auto Child : InputDIE.
children()) {
1859 unsigned Idx =
U.getDIEIndex(Child);
1860 if (Unit.getInfo(
Idx).Keep) {
1866 if (Unit.getOrigUnit().getVersion() >= 5 && !AttrInfo.AttrStrOffsetBaseSeen &&
1867 Die->
getTag() == dwarf::DW_TAG_compile_unit) {
1869 Die->
addValue(DIEAlloc, dwarf::DW_AT_str_offsets_base,
1870 dwarf::DW_FORM_sec_offset, DIEInteger(8));
1878 Linker.assignAbbrev(NewAbbrev);
1884 OutOffset += AbbrevNumberSize;
1887 for (AttributeLinkedOffsetFixup &
F : AttributesFixups)
1888 F.LinkedOffsetFixupVal += AbbrevNumberSize;
1890 for (AttributeLinkedOffsetFixup &
F : AttributesFixups)
1891 ObjFile.Addresses->updateAndSaveValidRelocs(
1892 Unit.getOrigUnit().getVersion() >= 5, Unit.getOrigUnit().getOffset(),
1893 F.LinkedOffsetFixupVal,
F.InputAttrStartOffset,
F.InputAttrEndOffset);
1902 for (
auto Child : InputDIE.
children()) {
1903 if (DIE *Clone = cloneDIE(Child, File, Unit, PCOffset, OutOffset, Flags,
1906 OutOffset = Clone->getOffset() + Clone->getSize();
1911 OutOffset +=
sizeof(int8_t);
1920void DWARFLinker::generateUnitRanges(CompileUnit &Unit,
const DWARFFile &File,
1925 const auto &FunctionRanges = Unit.getFunctionRanges();
1928 AddressRanges LinkedFunctionRanges;
1929 for (
const AddressRangeValuePair &
Range : FunctionRanges)
1930 LinkedFunctionRanges.insert(
1934 if (!LinkedFunctionRanges.empty())
1938 std::optional<PatchLocation> UnitRngListAttribute =
1939 Unit.getUnitRangesAttribute();
1941 if (!AllRngListAttributes.empty() || UnitRngListAttribute) {
1942 std::optional<AddressRangeValuePair> CachedRange;
1947 for (PatchLocation &AttributePatch : AllRngListAttributes) {
1950 AddressRanges LinkedRanges;
1951 if (Expected<DWARFAddressRangesVector> OriginalRanges =
1952 Unit.getOrigUnit().findRnglistFromOffset(AttributePatch.get())) {
1954 for (
const auto &
Range : *OriginalRanges) {
1955 if (!CachedRange || !CachedRange->Range.contains(
Range.LowPC))
1956 CachedRange = FunctionRanges.getRangeThatContains(
Range.LowPC);
1960 reportWarning(
"inconsistent range data.", File);
1965 LinkedRanges.insert({
Range.LowPC + CachedRange->Value,
1966 Range.HighPC + CachedRange->Value});
1970 reportWarning(
"invalid range list ignored.", File);
1975 Unit, LinkedRanges, AttributePatch, AddrPool);
1979 if (UnitRngListAttribute.has_value())
1981 Unit, LinkedFunctionRanges, *UnitRngListAttribute, AddrPool);
1988void DWARFLinker::DIECloner::generateUnitLocations(
1989 CompileUnit &Unit,
const DWARFFile &File,
1990 ExpressionHandlerRef ExprHandler) {
1995 Unit.getLocationAttributes();
1997 if (AllLocListAttributes.empty())
2003 for (
auto &CurLocAttr : AllLocListAttributes) {
2006 Expected<DWARFLocationExpressionsVector> OriginalLocations =
2007 Unit.getOrigUnit().findLoclistFromOffset(CurLocAttr.get());
2009 if (!OriginalLocations) {
2011 Linker.reportWarning(
"Invalid location attribute ignored.", File);
2016 for (DWARFLocationExpression &CurExpression : *OriginalLocations) {
2017 DWARFLocationExpression LinkedExpression;
2019 if (CurExpression.Range) {
2021 LinkedExpression.Range = {
2022 CurExpression.Range->LowPC + CurLocAttr.RelocAdjustment,
2023 CurExpression.Range->HighPC + CurLocAttr.RelocAdjustment};
2027 LinkedExpression.Expr.reserve(CurExpression.Expr.size());
2028 ExprHandler(CurExpression.Expr, LinkedExpression.Expr,
2029 CurLocAttr.RelocAdjustment);
2031 LinkedLocationExpressions.push_back(LinkedExpression);
2035 Emitter->emitDwarfDebugLocListFragment(Unit, LinkedLocationExpressions,
2036 CurLocAttr, AddrPool);
2040 Emitter->emitDwarfDebugLocListFooter(Unit, EndLabel);
2044 for (
auto &V : Die.
values())
2045 if (V.getAttribute() == dwarf::DW_AT_addr_base) {
2053void DWARFLinker::DIECloner::emitDebugAddrSection(
2054 CompileUnit &Unit,
const uint16_t DwarfVersion)
const {
2059 if (DwarfVersion < 5)
2062 if (AddrPool.getValues().empty())
2065 MCSymbol *EndLabel =
Emitter->emitDwarfDebugAddrsHeader(Unit);
2067 DIEInteger(
Emitter->getDebugAddrSectionSize()));
2068 Emitter->emitDwarfDebugAddrs(AddrPool.getValues(),
2069 Unit.getOrigUnit().getAddressByteSize());
2070 Emitter->emitDwarfDebugAddrsFooter(Unit, EndLabel);
2076 std::vector<DWARFDebugLine::Row> &Rows) {
2080 if (!Rows.empty() && Rows.back().Address < Seq.front().Address) {
2094 if (InsertPoint != Rows.end() && InsertPoint->Address == Front &&
2095 InsertPoint->EndSequence) {
2096 *InsertPoint = Seq.front();
2097 Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end());
2099 Rows.insert(InsertPoint, Seq.begin(), Seq.end());
2106 for (
auto &V : Die.
values())
2107 if (V.getAttribute() == dwarf::DW_AT_stmt_list) {
2115void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {
2116 DWARFUnit &OrigUnit = Unit.getOrigUnit();
2117 DWARFDie OrigUnitDie = OrigUnit.getUnitDIE();
2119 if (std::optional<uint64_t> MacroAttr =
2121 UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));
2125 if (std::optional<uint64_t> MacroAttr =
2127 UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));
2132void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
2137 DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
2143 if (
auto *OutputDIE = Unit.getOutputUnitDIE())
2146 if (
const DWARFDebugLine::LineTable *LT =
2147 ObjFile.Dwarf->getLineTableForUnit(&Unit.getOrigUnit())) {
2149 DWARFDebugLine::LineTable LineTable;
2152 LineTable.Prologue =
LT->Prologue;
2155 if (Linker.Options.Update) {
2156 LineTable.Rows =
LT->Rows;
2159 if (LineTable.Rows.size() == 1 && LineTable.Rows[0].EndSequence)
2160 LineTable.Rows.clear();
2162 LineTable.Sequences =
LT->Sequences;
2165 std::vector<DWARFDebugLine::Row> NewRows;
2166 NewRows.reserve(
LT->Rows.size());
2170 std::vector<DWARFDebugLine::Row> Seq;
2172 const auto &FunctionRanges = Unit.getFunctionRanges();
2173 std::optional<AddressRangeValuePair> CurrRange;
2186 for (DWARFDebugLine::Row Row :
LT->Rows) {
2192 if (!CurrRange || !CurrRange->Range.contains(Row.Address.Address)) {
2196 CurrRange ? CurrRange->Range.end() + CurrRange->Value : -1ULL;
2197 CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);
2198 if (StopAddress != -1ULL && !Seq.empty()) {
2201 auto NextLine = Seq.back();
2202 NextLine.Address.Address = StopAddress;
2203 NextLine.EndSequence = 1;
2204 NextLine.PrologueEnd = 0;
2205 NextLine.BasicBlock = 0;
2206 NextLine.EpilogueBegin = 0;
2207 Seq.push_back(NextLine);
2216 if (Row.EndSequence && Seq.empty())
2220 Row.Address.Address += CurrRange->Value;
2221 Seq.emplace_back(Row);
2223 if (Row.EndSequence)
2227 LineTable.Rows = std::move(NewRows);
2230 Emitter->emitLineTableForUnit(LineTable, Unit, DebugStrPool,
2233 Linker.reportWarning(
"Cann't load line table.", ObjFile);
2236void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
2241 for (
const auto &Namespace : Unit.getNamespaces())
2242 AppleNamespaces.addName(Namespace.Name, Namespace.Die->getOffset() +
2243 Unit.getStartOffset());
2245 for (
const auto &Pubname : Unit.getPubnames())
2246 AppleNames.addName(Pubname.Name,
2247 Pubname.Die->getOffset() + Unit.getStartOffset());
2249 for (
const auto &Pubtype : Unit.getPubtypes())
2251 Pubtype.Name, Pubtype.Die->getOffset() + Unit.getStartOffset(),
2252 Pubtype.Die->getTag(),
2255 Pubtype.QualifiedNameHash);
2257 for (
const auto &ObjC : Unit.getObjC())
2258 AppleObjc.addName(
ObjC.Name,
2259 ObjC.Die->getOffset() + Unit.getStartOffset());
2266 for (
const auto &Namespace : Unit.getNamespaces())
2268 Namespace.Name, Namespace.Die->getOffset(),
2270 Namespace.Die->getTag(), Unit.getUniqueID(),
2271 Unit.getTag() == dwarf::DW_TAG_type_unit);
2272 for (
const auto &Pubname : Unit.getPubnames())
2274 Pubname.Name, Pubname.Die->getOffset(),
2276 Pubname.Die->getTag(), Unit.getUniqueID(),
2277 Unit.getTag() == dwarf::DW_TAG_type_unit);
2278 for (
const auto &Pubtype : Unit.getPubtypes())
2280 Pubtype.Name, Pubtype.Die->getOffset(),
2282 Pubtype.Die->getTag(), Unit.getUniqueID(),
2283 Unit.getTag() == dwarf::DW_TAG_type_unit);
2295void DWARFLinker::patchFrameInfoForObject(LinkContext &Context) {
2296 DWARFContext &OrigDwarf = *Context.File.Dwarf;
2297 unsigned SrcAddrSize = OrigDwarf.getDWARFObj().getAddressSize();
2299 StringRef
FrameData = OrigDwarf.getDWARFObj().getFrameSection().Data;
2304 for (std::unique_ptr<CompileUnit> &Unit : Context.CompileUnits) {
2305 for (
auto CurRange : Unit->getFunctionRanges())
2306 AllUnitsRanges.
insert(CurRange.Range, CurRange.Value);
2309 DataExtractor
Data(FrameData, OrigDwarf.isLittleEndian(), 0);
2314 DenseMap<uint64_t, StringRef> LocalCIES;
2316 while (
Data.isValidOffset(InputOffset)) {
2317 uint64_t EntryOffset = InputOffset;
2319 if (InitialLength == 0xFFFFFFFF)
2320 return reportWarning(
"Dwarf64 bits no supported", Context.File);
2323 if (CIEId == 0xFFFFFFFF) {
2325 StringRef CIEData =
FrameData.substr(EntryOffset, InitialLength + 4);
2326 LocalCIES[EntryOffset] = CIEData;
2328 InputOffset += InitialLength - 4;
2332 uint64_t Loc =
Data.getUnsigned(&InputOffset, SrcAddrSize);
2338 std::optional<AddressRangeValuePair>
Range =
2339 AllUnitsRanges.getRangeThatContains(Loc);
2342 InputOffset = EntryOffset + InitialLength + 4;
2348 StringRef CIEData = LocalCIES[CIEId];
2349 if (CIEData.empty())
2350 return reportWarning(
"Inconsistent debug_frame content. Dropping.",
2355 auto IteratorInserted = EmittedCIEs.
insert(
2358 if (IteratorInserted.second) {
2360 IteratorInserted.first->getValue() = LastCIEOffset;
2361 TheDwarfEmitter->
emitCIE(CIEData);
2367 unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize);
2368 TheDwarfEmitter->
emitFDE(IteratorInserted.first->getValue(), SrcAddrSize,
2370 FrameData.substr(InputOffset, FDERemainingBytes));
2371 InputOffset += FDERemainingBytes;
2375uint32_t DWARFLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE,
2377 const DWARFFile &File,
2378 int ChildRecurseDepth) {
2379 const char *
Name =
nullptr;
2380 DWARFUnit *OrigUnit = &
U.getOrigUnit();
2381 CompileUnit *
CU = &
U;
2382 std::optional<DWARFFormValue>
Ref;
2388 if (!(
Ref = DIE.find(dwarf::DW_AT_specification)) &&
2389 !(
Ref = DIE.find(dwarf::DW_AT_abstract_origin)))
2397 Linker.resolveDIEReference(File, CompileUnits, *
Ref, DIE, RefCU)) {
2399 OrigUnit = &RefCU->getOrigUnit();
2404 unsigned Idx = OrigUnit->getDIEIndex(DIE);
2405 if (!
Name && DIE.getTag() == dwarf::DW_TAG_namespace)
2406 Name =
"(anonymous namespace)";
2408 if (
CU->getInfo(
Idx).ParentIdx == 0 ||
2410 CU->getOrigUnit().getDIEAtIndex(
CU->getInfo(
Idx).ParentIdx).getTag() ==
2411 dwarf::DW_TAG_module)
2414 DWARFDie Die = OrigUnit->getDIEAtIndex(
CU->getInfo(
Idx).ParentIdx);
2423 CUDie.
find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id}));
2432 if (ObjectPrefixMap.empty())
2436 for (
const auto &Entry : ObjectPrefixMap)
2439 return p.str().str();
2446 CUDie.
find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
"");
2448 if (PCMFile.empty())
2451 if (ObjectPrefixMap)
2452 PCMFile =
remapPath(PCMFile, *ObjectPrefixMap);
2457std::pair<bool, bool> DWARFLinker::isClangModuleRef(
const DWARFDie &CUDie,
2458 std::string &PCMFile,
2459 LinkContext &Context,
2462 if (PCMFile.empty())
2463 return std::make_pair(
false,
false);
2471 reportWarning(
"Anonymous module skeleton CU for " + PCMFile,
2473 return std::make_pair(
true,
true);
2476 if (!
Quiet && Options.Verbose) {
2478 outs() <<
"Found clang module reference " << PCMFile;
2481 auto Cached = ClangModules.
find(PCMFile);
2482 if (Cached != ClangModules.
end()) {
2486 if (!
Quiet && Options.Verbose && (Cached->second != DwoId))
2487 reportWarning(Twine(
"hash mismatch: this object file was built against a "
2488 "different version of the module ") +
2491 if (!
Quiet && Options.Verbose)
2492 outs() <<
" [cached].\n";
2493 return std::make_pair(
true,
true);
2496 return std::make_pair(
true,
false);
2499bool DWARFLinker::registerModuleReference(
const DWARFDie &CUDie,
2500 LinkContext &Context,
2501 ObjFileLoaderTy Loader,
2502 CompileUnitHandlerTy OnCUDieLoaded,
2504 std::string PCMFile =
getPCMFile(CUDie, Options.ObjectPrefixMap);
2505 std::pair<bool, bool> IsClangModuleRef =
2506 isClangModuleRef(CUDie, PCMFile, Context, Indent,
false);
2508 if (!IsClangModuleRef.first)
2511 if (IsClangModuleRef.second)
2514 if (Options.Verbose)
2521 if (Error
E = loadClangModule(Loader, CUDie, PCMFile, Context, OnCUDieLoaded,
2529Error DWARFLinker::loadClangModule(
2530 ObjFileLoaderTy Loader,
const DWARFDie &CUDie,
const std::string &PCMFile,
2531 LinkContext &Context, CompileUnitHandlerTy OnCUDieLoaded,
unsigned Indent) {
2537 SmallString<0>
Path(Options.PrependPath);
2544 if (Loader ==
nullptr) {
2545 reportError(
"Could not load clang module: loader is not specified.\n",
2550 auto ErrOrObj = Loader(Context.File.FileName, Path);
2554 std::unique_ptr<CompileUnit> Unit;
2555 for (
const auto &
CU : ErrOrObj->Dwarf->compile_units()) {
2558 auto ChildCUDie =
CU->getUnitDIE();
2561 if (!registerModuleReference(ChildCUDie, Context, Loader, OnCUDieLoaded,
2566 ": Clang modules are expected to have exactly 1 compile unit.\n");
2567 reportError(Err, Context.File);
2574 if (PCMDwoId != DwoId) {
2575 if (Options.Verbose)
2577 Twine(
"hash mismatch: this object file was built against a "
2578 "different version of the module ") +
2582 ClangModules[PCMFile] = PCMDwoId;
2586 Unit = std::make_unique<CompileUnit>(*
CU, UniqueUnitID++, !Options.NoODR,
2592 Context.ModuleUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)});
2597uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
2598 DWARFContext &DwarfContext,
const DWARFFile &File,
bool IsLittleEndian) {
2601 const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
2603 for (
auto &CurrentUnit : CompileUnits) {
2604 const uint16_t DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
2605 const uint32_t UnitHeaderSize = DwarfVersion >= 5 ? 12 : 11;
2606 auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();
2607 CurrentUnit->setStartOffset(OutputDebugInfoSize);
2609 OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
2612 if (CurrentUnit->getInfo(0).Keep) {
2615 CurrentUnit->createOutputDIE();
2616 rememberUnitForMacroOffset(*CurrentUnit);
2617 cloneDIE(InputDIE, File, *CurrentUnit, 0 , UnitHeaderSize,
2618 0, IsLittleEndian, CurrentUnit->getOutputUnitDIE());
2621 OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
2625 generateLineTableForUnit(*CurrentUnit);
2627 Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
2632 Linker.generateUnitRanges(*CurrentUnit, File, AddrPool);
2634 auto ProcessExpr = [&](SmallVectorImpl<uint8_t> &SrcBytes,
2635 SmallVectorImpl<uint8_t> &OutBytes,
2636 int64_t RelocAdjustment) {
2637 DWARFUnit &OrigUnit = CurrentUnit->getOrigUnit();
2638 DataExtractor
Data(SrcBytes, IsLittleEndian,
2639 OrigUnit.getAddressByteSize());
2640 cloneExpression(
Data,
2641 DWARFExpression(
Data, OrigUnit.getAddressByteSize(),
2642 OrigUnit.getFormParams().Format),
2643 File, *CurrentUnit, OutBytes, RelocAdjustment,
2646 generateUnitLocations(*CurrentUnit, File, ProcessExpr);
2647 emitDebugAddrSection(*CurrentUnit, DwarfVersion);
2655 Emitter->emitMacroTables(
File.Dwarf.get(), UnitMacroMap, DebugStrPool);
2658 for (
auto &CurrentUnit : CompileUnits) {
2659 CurrentUnit->fixupForwardReferences();
2661 if (!CurrentUnit->getOutputUnitDIE())
2664 unsigned DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
2667 CurrentUnit->getStartOffset());
2668 Emitter->emitCompileUnitHeader(*CurrentUnit, DwarfVersion);
2669 Emitter->emitDIE(*CurrentUnit->getOutputUnitDIE());
2671 CurrentUnit->computeNextUnitOffset(DwarfVersion));
2675 return OutputDebugInfoSize - StartOutputDebugInfoSize;
2678void DWARFLinker::copyInvariantDebugSection(DWARFContext &
Dwarf) {
2682 Dwarf.getDWARFObj().getRangesSection().Data,
2691 Dwarf.getDWARFObj().getRnglistsSection().Data,
2694 Dwarf.getDWARFObj().getLoclistsSection().Data,
2700 ObjectContexts.emplace_back(LinkContext(File));
2702 if (ObjectContexts.back().File.Dwarf) {
2703 for (
const std::unique_ptr<DWARFUnit> &
CU :
2704 ObjectContexts.back().File.Dwarf->compile_units()) {
2713 registerModuleReference(CUDie, ObjectContexts.back(), Loader,
2720 assert((Options.TargetDWARFVersion != 0) &&
2721 "TargetDWARFVersion should be set");
2725 unsigned NumObjects = ObjectContexts.size();
2737 for (LinkContext &OptContext : ObjectContexts) {
2738 if (Options.Verbose)
2739 outs() <<
"DEBUG MAP OBJECT: " << OptContext.File.FileName <<
"\n";
2741 if (!OptContext.File.Dwarf)
2744 if (Options.VerifyInputDWARF)
2745 verifyInput(OptContext.File);
2752 !OptContext.File.Addresses->hasValidRelocs()) {
2753 if (Options.Verbose)
2754 outs() <<
"No valid relocations found. Skipping.\n";
2758 OptContext.Skip =
true;
2763 if (!OptContext.File.Dwarf)
2767 if (!OptContext.File.Dwarf->types_section_units().empty()) {
2768 reportWarning(
"type units are not currently supported: file will "
2771 OptContext.Skip =
true;
2777 OptContext.CompileUnits.reserve(
2778 OptContext.File.Dwarf->getNumCompileUnits());
2779 for (
const auto &
CU : OptContext.File.Dwarf->compile_units()) {
2780 auto CUDie =
CU->getUnitDIE(
true);
2781 if (Options.Verbose) {
2782 outs() <<
"Input compilation unit:";
2785 DumpOpts.
Verbose = Options.Verbose;
2786 CUDie.dump(
outs(), 0, DumpOpts);
2790 for (
auto &
CU : OptContext.ModuleUnits) {
2791 if (
Error Err = cloneModuleUnit(OptContext,
CU, ODRContexts, DebugStrPool,
2792 DebugLineStrPool, StringOffsetPool))
2793 reportWarning(
toString(std::move(Err)),
CU.File);
2803 (TheDwarfEmitter ==
nullptr) ? 0
2808 std::mutex ProcessedFilesMutex;
2809 std::condition_variable ProcessedFilesConditionVariable;
2810 BitVector ProcessedFiles(NumObjects,
false);
2814 auto AnalyzeLambda = [&](
size_t I) {
2815 auto &Context = ObjectContexts[
I];
2817 if (Context.Skip || !Context.File.Dwarf)
2820 for (
const auto &
CU : Context.File.Dwarf->compile_units()) {
2823 auto CUDie =
CU->getUnitDIE(
false);
2824 std::string PCMFile =
getPCMFile(CUDie, Options.ObjectPrefixMap);
2827 !isClangModuleRef(CUDie, PCMFile, Context, 0,
true).first) {
2828 Context.CompileUnits.push_back(std::make_unique<CompileUnit>(
2829 *
CU, UniqueUnitID++, !Options.NoODR && !Options.Update,
""));
2834 for (
auto &CurrentUnit : Context.CompileUnits) {
2835 auto CUDie = CurrentUnit->getOrigUnit().getUnitDIE();
2839 *CurrentUnit, &ODRContexts.
getRoot(), ODRContexts,
2840 ModulesEndOffset, Options.ParseableSwiftInterfaces,
2842 reportWarning(Warning, Context.File, &DIE);
2854 auto CloneLambda = [&](
size_t I) {
2855 auto &OptContext = ObjectContexts[
I];
2856 if (OptContext.Skip || !OptContext.File.Dwarf)
2865 for (
auto &CurrentUnit : OptContext.CompileUnits)
2866 CurrentUnit->markEverythingAsKept();
2867 copyInvariantDebugSection(*OptContext.File.Dwarf);
2869 for (
auto &CurrentUnit : OptContext.CompileUnits) {
2870 lookForDIEsToKeep(*OptContext.File.Addresses, OptContext.CompileUnits,
2871 CurrentUnit->getOrigUnit().getUnitDIE(),
2872 OptContext.File, *CurrentUnit, 0);
2882 if (OptContext.File.Addresses->hasValidRelocs() ||
2884 SizeByObject[OptContext.File.FileName].Input =
2886 SizeByObject[OptContext.File.FileName].Output =
2887 DIECloner(*
this, TheDwarfEmitter, OptContext.File, DIEAlloc,
2888 OptContext.CompileUnits, Options.Update, DebugStrPool,
2889 DebugLineStrPool, StringOffsetPool)
2890 .cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
2891 OptContext.File.Dwarf->isLittleEndian());
2893 if ((TheDwarfEmitter !=
nullptr) && !OptContext.CompileUnits.empty() &&
2895 patchFrameInfoForObject(OptContext);
2898 cleanupAuxiliarryData(OptContext);
2901 auto EmitLambda = [&]() {
2903 if (TheDwarfEmitter !=
nullptr) {
2904 TheDwarfEmitter->
emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);
2907 Options.TargetDWARFVersion);
2910 switch (TableKind) {
2929 auto AnalyzeAll = [&]() {
2930 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2933 std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
2934 ProcessedFiles.
set(
I);
2935 ProcessedFilesConditionVariable.notify_one();
2939 auto CloneAll = [&]() {
2940 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2942 std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
2943 if (!ProcessedFiles[
I]) {
2944 ProcessedFilesConditionVariable.wait(
2945 LockGuard, [&]() {
return ProcessedFiles[
I]; });
2957 if (Options.Threads == 1) {
2958 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2965 Pool.
async(AnalyzeAll);
2966 Pool.
async(CloneAll);
2970 if (Options.Statistics) {
2972 std::vector<std::pair<StringRef, DebugInfoSize>> Sorted;
2973 for (
auto &
E : SizeByObject)
2974 Sorted.emplace_back(
E.first(),
E.second);
2976 return LHS.second.Output >
RHS.second.Output;
2979 auto ComputePercentange = [](int64_t Input, int64_t Output) ->
float {
2980 const float Difference = Output - Input;
2981 const float Sum = Input + Output;
2984 return (Difference / (Sum / 2));
2987 int64_t InputTotal = 0;
2988 int64_t OutputTotal = 0;
2989 const char *FormatStr =
"{0,-45} {1,10}b {2,10}b {3,8:P}\n";
2992 outs() <<
".debug_info section size (in bytes)\n";
2993 outs() <<
"----------------------------------------------------------------"
2994 "---------------\n";
2995 outs() <<
"Filename Object "
2997 outs() <<
"----------------------------------------------------------------"
2998 "---------------\n";
3001 for (
auto &
E : Sorted) {
3002 InputTotal +=
E.second.Input;
3003 OutputTotal +=
E.second.Output;
3006 E.second.Output, ComputePercentange(
E.second.Input,
E.second.Output));
3009 outs() <<
"----------------------------------------------------------------"
3010 "---------------\n";
3012 ComputePercentange(InputTotal, OutputTotal));
3013 outs() <<
"----------------------------------------------------------------"
3014 "---------------\n\n";
3020Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
3026 assert(Unit.Unit.get() !=
nullptr);
3028 if (!Unit.Unit->getOrigUnit().getUnitDIE().hasChildren())
3031 if (Options.Verbose) {
3033 outs() <<
"cloning .debug_info from " << Unit.File.FileName <<
"\n";
3038 &ODRContexts.
getRoot(), ODRContexts, 0,
3039 Options.ParseableSwiftInterfaces,
3041 reportWarning(Warning, Context.File, &DIE);
3044 Unit.Unit->markEverythingAsKept();
3048 CompileUnits.emplace_back(std::move(Unit.Unit));
3050 DIECloner(*
this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits,
3051 Options.Update, DebugStrPool, DebugLineStrPool, StringOffsetPool)
3052 .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,
3053 Unit.File.Dwarf->isLittleEndian());
3057void DWARFLinker::verifyInput(
const DWARFFile &File) {
3064 if (Options.InputVerificationHandler)
3065 Options.InputVerificationHandler(File,
OS.str());
static uint32_t hashFullyQualifiedName(CompileUnit &InputCU, DWARFDie &InputDIE, int ChildRecurseDepth=0)
This file implements the BitVector class.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Analysis containing CSE Info
#define LLVM_UNLIKELY(EXPR)
#define LLVM_LIKELY(EXPR)
dxil DXContainer Global Emitter
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
Provides ErrorOr<T> smart pointer.
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void addName(DwarfStringPoolEntryRef Name, Types &&... Args)
void insert(AddressRange Range, int64_t Value)
void Reset()
Deallocate all but the current slab and reset the current pointer to the beginning of it,...
void setChildrenFlag(bool hasChild)
value_iterator addValue(BumpPtrAllocator &Alloc, const DIEValue &V)
A structured debug information entry.
unsigned getAbbrevNumber() const
DIE & addChild(DIE *Child)
Add a child to the DIE.
DIEAbbrev generateAbbrev() const
Generate the abbreviation for this DIE.
static DIE * get(BumpPtrAllocator &Alloc, dwarf::Tag Tag)
void setAbbrevNumber(unsigned I)
Set the abbreviation number for this DIE.
unsigned getOffset() const
Get the compile/type unit relative offset of this DIE.
void setOffset(unsigned O)
dwarf::Tag getTag() const
static std::optional< uint64_t > getDefiningParentDieOffset(const DIE &Die)
If Die has a non-null parent and the parent is not a declaration, return its offset.
DWARFContext This data structure is the top level entity that deals with dwarf debug information pars...
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
uint64_t getOffset() const
Get the absolute offset into the debug info or types section.
iterator_range< iterator > children() const
std::optional< DWARFFormValue > find(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE.
const DWARFAbbreviationDeclaration * getAbbreviationDeclarationPtr() const
Get the abbreviation declaration for this DIE.
dwarf::Tag getTag() const
std::optional< unsigned > getSubCode() const
uint64_t getEndOffset() const
Encoding
Size and signedness of expression operations' operands.
const Description & getDescription() const
uint64_t getRawOperand(unsigned Idx) const
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
A non-threaded implementation.
void wait() override
Blocking wait for all the tasks to execute first.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
iterator find(StringRef Key)
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
StringRef - Represent a constant reference to a string, i.e.
constexpr bool empty() const
empty - Check if the string is empty.
StringRef take_back(size_t N=1) const
Return a StringRef equal to 'this' but with only the last N elements remaining.
Helper for making strong types.
auto async(Function &&F, Args &&...ArgList)
Asynchronous submission of a task to the pool.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
static raw_ostream & error()
Convenience method for printing "error: " to stderr.
This class represents DWARF information for source file and it's address map.
std::map< std::string, std::string > ObjectPrefixMapTy
AccelTableKind
The kind of accelerator tables to be emitted.
@ DebugNames
.debug_names.
@ Apple
.apple_names, .apple_namespaces, .apple_types, .apple_objc.
@ Pub
.debug_pubnames, .debug_pubtypes
std::map< std::string, std::string > SwiftInterfacesMapTy
std::function< ErrorOr< DWARFFile & >(StringRef ContainerName, StringRef Path)> ObjFileLoaderTy
const SmallVector< T > & getValues() const
Stores all information relating to a compile unit, be it in its original instance in the object file ...
void addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader=nullptr, CompileUnitHandlerTy OnCUDieLoaded=[](const DWARFUnit &) {}) override
Add object file to be linked.
Error link() override
Link debug info for added objFiles. Object files are linked all together.
This class gives a tree-like API to the DenseMap that stores the DeclContext objects.
PointerIntPair< DeclContext *, 1 > getChildDeclContext(DeclContext &Context, const DWARFDie &DIE, CompileUnit &Unit, bool InClangModule)
Get the child of Context described by DIE in Unit.
A DeclContext is a named program scope that is used for ODR uniquing of types.
virtual void emitPubTypesForUnit(const CompileUnit &Unit)=0
Emit the .debug_pubtypes contribution for Unit.
virtual void emitSectionContents(StringRef SecData, DebugSectionKind SecKind)=0
Emit section named SecName with data SecData.
virtual void emitDwarfDebugRangeListFragment(const CompileUnit &Unit, const AddressRanges &LinkedRanges, PatchLocation Patch, DebugDieValuePool &AddrPool)=0
Emit debug ranges (.debug_ranges, .debug_rnglists) fragment.
virtual void emitDwarfDebugArangesTable(const CompileUnit &Unit, const AddressRanges &LinkedRanges)=0
Emit .debug_aranges entries for Unit.
virtual uint64_t getDebugInfoSectionSize() const =0
Returns size of generated .debug_info section.
virtual void emitCIE(StringRef CIEBytes)=0
Emit a CIE.
virtual uint64_t getFrameSectionSize() const =0
Returns size of generated .debug_frame section.
virtual void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint64_t Address, StringRef Bytes)=0
Emit an FDE with data Bytes.
virtual void emitAppleNamespaces(AccelTable< AppleAccelTableStaticOffsetData > &Table)=0
Emit Apple namespaces accelerator table.
virtual void emitAppleObjc(AccelTable< AppleAccelTableStaticOffsetData > &Table)=0
Emit Apple Objective-C accelerator table.
virtual void emitDebugNames(DWARF5AccelTable &Table)=0
Emit DWARF debug names.
virtual void emitAppleTypes(AccelTable< AppleAccelTableStaticTypeData > &Table)=0
Emit Apple type accelerator table.
virtual void emitPubNamesForUnit(const CompileUnit &Unit)=0
Emit the .debug_pubnames contribution for Unit.
virtual void emitAppleNames(AccelTable< AppleAccelTableStaticOffsetData > &Table)=0
Emit Apple names accelerator table.
virtual void emitAbbrevs(const std::vector< std::unique_ptr< DIEAbbrev > > &Abbrevs, unsigned DwarfVersion)=0
Emit the abbreviation table Abbrevs to the .debug_abbrev section.
virtual MCSymbol * emitDwarfDebugRangeListHeader(const CompileUnit &Unit)=0
Emit debug ranges (.debug_ranges, .debug_rnglists) header.
virtual void emitStrings(const NonRelocatableStringpool &Pool)=0
Emit the string table described by Pool into .debug_str table.
virtual void emitLineStrings(const NonRelocatableStringpool &Pool)=0
Emit the string table described by Pool into .debug_line_str table.
virtual void emitStringOffsets(const SmallVector< uint64_t > &StringOffsets, uint16_t TargetDWARFVersion)=0
Emit the debug string offset table described by StringOffsets into the .debug_str_offsets table.
virtual void emitDwarfDebugRangeListFooter(const CompileUnit &Unit, MCSymbol *EndLabel)=0
Emit debug ranges (.debug_ranges, .debug_rnglists) footer.
An efficient, type-erasing, non-owning reference to a callable.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
A raw_ostream that writes to an std::string.
StringRef FormEncodingString(unsigned Encoding)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
AddressRangesMap RangesTy
Mapped value in the address map is the offset to apply to the linked address.
SmallVector< PatchLocation > RngListAttributesTy
IndexedValuesMap< uint64_t > DebugDieValuePool
SmallVector< PatchLocation > LocListAttributesTy
std::vector< std::unique_ptr< CompileUnit > > UnitListTy
StringRef guessDeveloperDir(StringRef SysRoot)
Make a best effort to guess the Xcode.app/Contents/Developer path from an SDK path.
StringMapEntry< std::nullopt_t > StringEntry
StringEntry keeps data of the string: the length, external offset and a string body which is placed r...
bool isInToolchainDir(StringRef Path)
Make a best effort to determine whether Path is inside a toolchain.
std::optional< uint64_t > toAddress(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an address.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
bool doesFormBelongToClass(dwarf::Form Form, DWARFFormValue::FormClass FC, uint16_t DwarfVersion)
Check whether specified Form belongs to the FC class.
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.
@ DW_FLAG_type_implementation
std::optional< uint64_t > toUnsigned(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an unsigned constant.
bool is_relative(const Twine &path, Style style=Style::native)
Is path relative?
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
bool replace_path_prefix(SmallVectorImpl< char > &Path, StringRef OldPrefix, StringRef NewPrefix, Style style=Style::native)
Replace matching path prefix with another path.
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
static const bool IsLittleEndianHost
void swapByteOrder(T &Value)
This is an optimization pass for GlobalISel generic memory operations.
ThreadPoolStrategy hardware_concurrency(unsigned ThreadCount=0)
Returns a default thread strategy where all available hardware resources are to be used,...
static void verifyKeepChain(CompileUnit &CU)
Verify the keep chain by looking for DIEs that are kept but who's parent isn't.
static void updateRefIncompleteness(const DWARFDie &Die, CompileUnit &CU, CompileUnit::DIEInfo &RefInfo)
Helper that updates the completeness of the current DIE based on the completeness of the DIEs it refe...
static bool isTlsAddressCode(uint8_t DW_OP_Code)
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
auto partition_point(R &&Range, Predicate P)
Binary search for the first iterator in a range where a predicate is false.
auto formatv(const char *Fmt, Ts &&...Vals) -> formatv_object< decltype(std::make_tuple(support::detail::build_format_adapter(std::forward< Ts >(Vals))...))>
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
static void patchAddrBase(DIE &Die, DIEInteger Offset)
static std::string remapPath(StringRef Path, const DWARFLinkerBase::ObjectPrefixMapTy &ObjectPrefixMap)
auto upper_bound(R &&Range, T &&Value)
Provide wrappers to std::upper_bound which take ranges instead of having to pass begin/end explicitly...
static CompileUnit * getUnitForOffset(const UnitListTy &Units, uint64_t Offset)
Similar to DWARFUnitSection::getUnitForOffset(), but returning our CompileUnit object instead.
static void resolveRelativeObjectPath(SmallVectorImpl< char > &Buf, DWARFDie CU)
Resolve the relative path to a build artifact referenced by DWARF by applying DW_AT_comp_dir.
static std::string getPCMFile(const DWARFDie &CUDie, const DWARFLinkerBase::ObjectPrefixMapTy *ObjectPrefixMap)
static void insertLineSequence(std::vector< DWARFDebugLine::Row > &Seq, std::vector< DWARFDebugLine::Row > &Rows)
Insert the new line info sequence Seq into the current set of already linked line info Rows.
std::vector< DWARFLocationExpression > DWARFLocationExpressionsVector
Represents a set of absolute location expressions.
static bool shouldSkipAttribute(bool Update, DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, bool SkipPC)
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
static uint64_t getDebugInfoSize(DWARFContext &Dwarf)
Compute the total size of the debug info.
static bool isTypeTag(uint16_t Tag)
@ Dwarf
DWARF v5 .debug_names.
StrongType< NonRelocatableStringpool, OffsetsTag > OffsetsStringPool
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
std::optional< StringRef > StripTemplateParameters(StringRef Name)
If Name is the name of a templated function that includes template parameters, returns a substring of...
static uint64_t getDwoId(const DWARFDie &CUDie)
static bool updatePruning(const DWARFDie &Die, CompileUnit &CU, uint64_t ModulesEndOffset)
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ Ref
The access may reference the value stored in memory.
unsigned getULEB128Size(uint64_t Value)
Utility function to get the size of the ULEB128-encoded value.
static void updateChildIncompleteness(const DWARFDie &Die, CompileUnit &CU, CompileUnit::DIEInfo &ChildInfo)
Helper that updates the completeness of the current DIE based on the completeness of one of its child...
DWARFExpression::Operation Op
static void updateChildPruning(const DWARFDie &Die, CompileUnit &CU, CompileUnit::DIEInfo &ChildInfo)
uint32_t djbHash(StringRef Buffer, uint32_t H=5381)
The Bernstein hash function used by the DWARF accelerator tables.
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...
static void analyzeContextInfo(const DWARFDie &DIE, unsigned ParentIdx, CompileUnit &CU, DeclContext *CurrentDeclContext, DeclContextTree &Contexts, uint64_t ModulesEndOffset, DWARFLinkerBase::SwiftInterfacesMapTy *ParseableSwiftInterfaces, std::function< void(const Twine &, const DWARFDie &)> ReportWarning)
Recursive helper to build the global DeclContext information and gather the child->parent relationshi...
static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag)
static bool isODRCanonicalCandidate(const DWARFDie &Die, CompileUnit &CU)
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
static void analyzeImportedModule(const DWARFDie &DIE, CompileUnit &CU, DWARFLinkerBase::SwiftInterfacesMapTy *ParseableSwiftInterfaces, std::function< void(const Twine &, const DWARFDie &)> ReportWarning)
Collect references to parseable Swift interfaces in imported DW_TAG_module blocks.
ContextWorklistItemType
The distinct types of work performed by the work loop in analyzeContextInfo.
void consumeError(Error Err)
Consume a Error without doing anything.
static bool isODRAttribute(uint16_t Attr)
static void patchStmtList(DIE &Die, DIEInteger Offset)
int64_t LinkedOffsetFixupVal
uint64_t InputAttrStartOffset
uint64_t InputAttrEndOffset
A broken link in the keep chain.
BrokenLink(DWARFDie Parent, DWARFDie Child)
This class represents an item in the work list.
CompileUnit::DIEInfo * OtherInfo
ContextWorklistItem(DWARFDie Die, DeclContext *Context, unsigned ParentIdx, bool InImportedModule)
ContextWorklistItemType Type
ContextWorklistItem(DWARFDie Die, ContextWorklistItemType T, CompileUnit::DIEInfo *OtherInfo=nullptr)
Container for dump options that control which debug information will be dumped.
DIDumpOptions noImplicitRecursion() const
Return the options with RecurseDepth set to 0 unless explicitly required.
unsigned ChildRecurseDepth
static bool mayHaveLocationList(dwarf::Attribute Attr)
Identify DWARF attributes that may contain a pointer to a location list.
static bool mayHaveLocationExpr(dwarf::Attribute Attr)
Identifies DWARF attributes that may contain a reference to a DWARF expression.
Standard .debug_line state machine structure.
SmallVector< Encoding > Op
Encoding for Op operands.
Hold the input and output of the debug info size in bytes.
Information gathered about a DIE in the object file.
bool Prune
Is this a pure forward declaration we can strip?
bool Incomplete
Does DIE transitively refer an incomplete decl?