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_macro_info) {
1418 if (std::optional<uint64_t>
Offset = Val.getAsSectionOffset()) {
1425 if (AttrSpec.Attr == dwarf::DW_AT_macros) {
1426 if (std::optional<uint64_t>
Offset = Val.getAsSectionOffset()) {
1433 if (AttrSpec.Attr == dwarf::DW_AT_str_offsets_base) {
1437 Info.AttrStrOffsetBaseSeen =
true;
1439 .addValue(DIEAlloc, dwarf::DW_AT_str_offsets_base,
1440 dwarf::DW_FORM_sec_offset, DIEInteger(8))
1441 ->sizeOf(Unit.getOrigUnit().getFormParams());
1445 if (
auto OptionalValue = Val.getAsUnsignedConstant())
1446 Value = *OptionalValue;
1447 else if (
auto OptionalValue = Val.getAsSignedConstant())
1448 Value = *OptionalValue;
1449 else if (
auto OptionalValue = Val.getAsSectionOffset())
1450 Value = *OptionalValue;
1452 Linker.reportWarning(
1453 "Unsupported scalar attribute form. Dropping attribute.", File,
1457 if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
1458 Info.IsDeclaration =
true;
1460 if (AttrSpec.Form == dwarf::DW_FORM_loclistx)
1469 [[maybe_unused]]
dwarf::Form OriginalForm = AttrSpec.Form;
1470 if (AttrSpec.Form == dwarf::DW_FORM_rnglistx) {
1474 std::optional<uint64_t>
Index = Val.getAsSectionOffset();
1476 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1480 std::optional<uint64_t>
Offset =
1481 Unit.getOrigUnit().getRnglistOffset(*
Index);
1483 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1489 AttrSpec.Form = dwarf::DW_FORM_sec_offset;
1490 AttrSize = Unit.getOrigUnit().getFormParams().getDwarfOffsetByteSize();
1491 }
else if (AttrSpec.Form == dwarf::DW_FORM_loclistx) {
1495 std::optional<uint64_t>
Index = Val.getAsSectionOffset();
1497 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1501 std::optional<uint64_t>
Offset =
1502 Unit.getOrigUnit().getLoclistOffset(*
Index);
1504 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1510 AttrSpec.Form = dwarf::DW_FORM_sec_offset;
1511 AttrSize = Unit.getOrigUnit().getFormParams().getDwarfOffsetByteSize();
1512 }
else if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
1513 Die.getTag() == dwarf::DW_TAG_compile_unit) {
1514 std::optional<uint64_t> LowPC = Unit.getLowPc();
1518 Value = Unit.getHighPc() - *LowPC;
1519 }
else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)
1520 Value = *Val.getAsSectionOffset();
1521 else if (AttrSpec.Form == dwarf::DW_FORM_sdata)
1522 Value = *Val.getAsSignedConstant();
1523 else if (
auto OptionalValue = Val.getAsUnsignedConstant())
1524 Value = *OptionalValue;
1526 Linker.reportWarning(
1527 "Unsupported scalar attribute form. Dropping attribute.", File,
1532 DIE::value_iterator Patch =
1535 if (AttrSpec.Attr == dwarf::DW_AT_ranges ||
1536 AttrSpec.Attr == dwarf::DW_AT_start_scope) {
1537 Unit.noteRangeAttribute(Die, Patch);
1538 Info.HasRanges =
true;
1542 Unit.getOrigUnit().getVersion())) {
1544 CompileUnit::DIEInfo &LocationDieInfo = Unit.getInfo(InputDIE);
1545 Unit.noteLocationAttribute({Patch, LocationDieInfo.InDebugMap
1546 ? LocationDieInfo.AddrAdjust
1548 }
else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
1549 Info.IsDeclaration =
true;
1552 assert((
Info.HasRanges || (OriginalForm != dwarf::DW_FORM_rnglistx)) &&
1553 "Unhandled DW_FORM_rnglistx attribute");
1561unsigned DWARFLinker::DIECloner::cloneAttribute(
1562 DIE &Die,
const DWARFDie &InputDIE,
const DWARFFile &File,
1563 CompileUnit &Unit,
const DWARFFormValue &Val,
const AttributeSpec AttrSpec,
1564 unsigned AttrSize, AttributesInfo &
Info,
bool IsLittleEndian) {
1565 const DWARFUnit &
U = Unit.getOrigUnit();
1567 switch (AttrSpec.Form) {
1568 case dwarf::DW_FORM_strp:
1569 case dwarf::DW_FORM_line_strp:
1570 case dwarf::DW_FORM_string:
1571 case dwarf::DW_FORM_strx:
1572 case dwarf::DW_FORM_strx1:
1573 case dwarf::DW_FORM_strx2:
1574 case dwarf::DW_FORM_strx3:
1575 case dwarf::DW_FORM_strx4:
1576 return cloneStringAttribute(Die, AttrSpec, Val, U,
Info);
1577 case dwarf::DW_FORM_ref_addr:
1578 case dwarf::DW_FORM_ref1:
1579 case dwarf::DW_FORM_ref2:
1580 case dwarf::DW_FORM_ref4:
1581 case dwarf::DW_FORM_ref8:
1582 return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val,
1584 case dwarf::DW_FORM_block:
1585 case dwarf::DW_FORM_block1:
1586 case dwarf::DW_FORM_block2:
1587 case dwarf::DW_FORM_block4:
1588 case dwarf::DW_FORM_exprloc:
1589 return cloneBlockAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,
1591 case dwarf::DW_FORM_addr:
1592 case dwarf::DW_FORM_addrx:
1593 case dwarf::DW_FORM_addrx1:
1594 case dwarf::DW_FORM_addrx2:
1595 case dwarf::DW_FORM_addrx3:
1596 case dwarf::DW_FORM_addrx4:
1597 return cloneAddressAttribute(Die, InputDIE, AttrSpec, AttrSize, Val, Unit,
1599 case dwarf::DW_FORM_data1:
1600 case dwarf::DW_FORM_data2:
1601 case dwarf::DW_FORM_data4:
1602 case dwarf::DW_FORM_data8:
1603 case dwarf::DW_FORM_udata:
1604 case dwarf::DW_FORM_sdata:
1605 case dwarf::DW_FORM_sec_offset:
1606 case dwarf::DW_FORM_flag:
1607 case dwarf::DW_FORM_flag_present:
1608 case dwarf::DW_FORM_rnglistx:
1609 case dwarf::DW_FORM_loclistx:
1610 case dwarf::DW_FORM_implicit_const:
1611 return cloneScalarAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,
1614 Linker.reportWarning(
"Unsupported attribute form " +
1616 " in cloneAttribute. Dropping.",
1623void DWARFLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit,
1625 DwarfStringPoolEntryRef
Name,
1627 bool SkipPubSection) {
1628 std::optional<ObjCSelectorNames> Names =
1632 Unit.addNameAccelerator(Die, StringPool.getEntry(Names->Selector),
1634 Unit.addObjCAccelerator(Die, StringPool.getEntry(Names->ClassName),
1636 if (Names->ClassNameNoCategory)
1637 Unit.addObjCAccelerator(
1638 Die, StringPool.getEntry(*Names->ClassNameNoCategory), SkipPubSection);
1639 if (Names->MethodNameNoCategory)
1640 Unit.addNameAccelerator(
1641 Die, StringPool.getEntry(*Names->MethodNameNoCategory), SkipPubSection);
1648 switch (AttrSpec.
Attr) {
1651 case dwarf::DW_AT_low_pc:
1652 case dwarf::DW_AT_high_pc:
1653 case dwarf::DW_AT_ranges:
1654 return !Update && SkipPC;
1655 case dwarf::DW_AT_rnglists_base:
1661 case dwarf::DW_AT_loclists_base:
1667 case dwarf::DW_AT_location:
1668 case dwarf::DW_AT_frame_base:
1669 return !Update && SkipPC;
1679DIE *DWARFLinker::DIECloner::cloneDIE(
const DWARFDie &InputDIE,
1681 int64_t PCOffset,
uint32_t OutOffset,
1682 unsigned Flags,
bool IsLittleEndian,
1685 unsigned Idx = U.getDIEIndex(InputDIE);
1689 if (!Unit.getInfo(
Idx).Keep)
1693 assert(!(Die &&
Info.Clone) &&
"Can't supply a DIE and a cloned DIE");
1705 (
Info.Ctxt->getCanonicalDIEOffset() == 0)) {
1706 if (!
Info.Ctxt->hasCanonicalDIE())
1707 Info.Ctxt->setHasCanonicalDIE();
1711 Info.Ctxt->setCanonicalDIEOffset(OutOffset + Unit.getStartOffset());
1715 DWARFDataExtractor
Data =
U.getDebugInfoExtractor();
1720 ?
U.getDIEAtIndex(
Idx + 1).getOffset()
1721 :
U.getNextUnitOffset();
1722 AttributesInfo AttrInfo;
1727 SmallString<40> DIECopy(
Data.getData().substr(
Offset, NextOffset -
Offset));
1729 DWARFDataExtractor(DIECopy,
Data.isLittleEndian(),
Data.getAddressSize());
1732 ObjFile.Addresses->applyValidRelocs(DIECopy,
Offset,
Data.isLittleEndian());
1742 if (Die->
getTag() == dwarf::DW_TAG_subprogram)
1743 PCOffset =
Info.AddrAdjust;
1744 AttrInfo.PCOffset = PCOffset;
1746 if (Abbrev->getTag() == dwarf::DW_TAG_subprogram) {
1747 Flags |= TF_InFunctionScope;
1750 }
else if (Abbrev->getTag() == dwarf::DW_TAG_variable) {
1753 if ((Flags & TF_InFunctionScope) &&
Info.InDebugMap)
1754 Flags &= ~TF_SkipPC;
1757 else if (!
Info.InDebugMap &&
Info.HasLocationExpressionAddr &&
1762 std::optional<StringRef> LibraryInstallName =
1763 ObjFile.Addresses->getLibraryInstallName();
1764 SmallVector<AttributeLinkedOffsetFixup> AttributesFixups;
1765 for (
const auto &AttrSpec : Abbrev->attributes()) {
1772 AttributeLinkedOffsetFixup CurAttrFixup;
1774 CurAttrFixup.LinkedOffsetFixupVal =
1775 Unit.getStartOffset() + OutOffset - CurAttrFixup.InputAttrStartOffset;
1777 DWARFFormValue Val = AttrSpec.getFormValue();
1779 Val.extractValue(
Data, &
Offset,
U.getFormParams(), &U);
1781 AttrSize =
Offset - AttrSize;
1784 cloneAttribute(*Die, InputDIE, File, Unit, Val, AttrSpec, AttrSize,
1785 AttrInfo, IsLittleEndian);
1786 if (FinalAttrSize != 0 && ObjFile.Addresses->needToSaveValidRelocs())
1787 AttributesFixups.push_back(CurAttrFixup);
1789 OutOffset += FinalAttrSize;
1795 const bool NeedsAppleOrigin = (
Tag == dwarf::DW_TAG_compile_unit) &&
1796 LibraryInstallName.has_value() &&
1797 !AttrInfo.HasAppleOrigin;
1798 if (NeedsAppleOrigin) {
1799 auto StringEntry = DebugStrPool.getEntry(LibraryInstallName.value());
1801 dwarf::DW_FORM_strp, DIEInteger(
StringEntry.getOffset()));
1810 if ((
Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&
1811 Tag != dwarf::DW_TAG_compile_unit &&
1812 getDIENames(InputDIE, AttrInfo, DebugStrPool,
1813 Tag != dwarf::DW_TAG_inlined_subroutine)) {
1814 if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
1815 Unit.addNameAccelerator(Die, AttrInfo.MangledName,
1816 Tag == dwarf::DW_TAG_inlined_subroutine);
1817 if (AttrInfo.Name) {
1818 if (AttrInfo.NameWithoutTemplate)
1819 Unit.addNameAccelerator(Die, AttrInfo.NameWithoutTemplate,
1821 Unit.addNameAccelerator(Die, AttrInfo.Name,
1822 Tag == dwarf::DW_TAG_inlined_subroutine);
1825 addObjCAccelerator(Unit, Die, AttrInfo.Name, DebugStrPool,
1828 }
else if (
Tag == dwarf::DW_TAG_namespace) {
1830 AttrInfo.Name = DebugStrPool.getEntry(
"(anonymous namespace)");
1831 Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
1832 }
else if (
Tag == dwarf::DW_TAG_imported_declaration && AttrInfo.Name) {
1833 Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
1834 }
else if (
isTypeTag(
Tag) && !AttrInfo.IsDeclaration &&
1835 getDIENames(InputDIE, AttrInfo, DebugStrPool) && AttrInfo.Name &&
1836 AttrInfo.Name.getString()[0]) {
1841 bool ObjCClassIsImplementation =
1842 (RuntimeLang == dwarf::DW_LANG_ObjC ||
1843 RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
1846 Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation,
1851 bool HasChildren =
false;
1852 for (
auto Child : InputDIE.
children()) {
1853 unsigned Idx =
U.getDIEIndex(Child);
1854 if (Unit.getInfo(
Idx).Keep) {
1860 if (Unit.getOrigUnit().getVersion() >= 5 && !AttrInfo.AttrStrOffsetBaseSeen &&
1861 Die->
getTag() == dwarf::DW_TAG_compile_unit) {
1863 Die->
addValue(DIEAlloc, dwarf::DW_AT_str_offsets_base,
1864 dwarf::DW_FORM_sec_offset, DIEInteger(8));
1872 Linker.assignAbbrev(NewAbbrev);
1878 OutOffset += AbbrevNumberSize;
1881 for (AttributeLinkedOffsetFixup &
F : AttributesFixups)
1882 F.LinkedOffsetFixupVal += AbbrevNumberSize;
1884 for (AttributeLinkedOffsetFixup &
F : AttributesFixups)
1885 ObjFile.Addresses->updateAndSaveValidRelocs(
1886 Unit.getOrigUnit().getVersion() >= 5, Unit.getOrigUnit().getOffset(),
1887 F.LinkedOffsetFixupVal,
F.InputAttrStartOffset,
F.InputAttrEndOffset);
1896 for (
auto Child : InputDIE.
children()) {
1897 if (DIE *Clone = cloneDIE(Child, File, Unit, PCOffset, OutOffset, Flags,
1900 OutOffset = Clone->getOffset() + Clone->getSize();
1905 OutOffset +=
sizeof(int8_t);
1914void DWARFLinker::generateUnitRanges(CompileUnit &Unit,
const DWARFFile &File,
1919 const auto &FunctionRanges = Unit.getFunctionRanges();
1922 AddressRanges LinkedFunctionRanges;
1923 for (
const AddressRangeValuePair &
Range : FunctionRanges)
1924 LinkedFunctionRanges.insert(
1928 if (!LinkedFunctionRanges.empty())
1932 std::optional<PatchLocation> UnitRngListAttribute =
1933 Unit.getUnitRangesAttribute();
1935 if (!AllRngListAttributes.empty() || UnitRngListAttribute) {
1936 std::optional<AddressRangeValuePair> CachedRange;
1941 for (PatchLocation &AttributePatch : AllRngListAttributes) {
1944 AddressRanges LinkedRanges;
1945 if (Expected<DWARFAddressRangesVector> OriginalRanges =
1946 Unit.getOrigUnit().findRnglistFromOffset(AttributePatch.get())) {
1948 for (
const auto &
Range : *OriginalRanges) {
1949 if (!CachedRange || !CachedRange->Range.contains(
Range.LowPC))
1950 CachedRange = FunctionRanges.getRangeThatContains(
Range.LowPC);
1954 reportWarning(
"inconsistent range data.", File);
1959 LinkedRanges.insert({
Range.LowPC + CachedRange->Value,
1960 Range.HighPC + CachedRange->Value});
1964 reportWarning(
"invalid range list ignored.", File);
1969 Unit, LinkedRanges, AttributePatch, AddrPool);
1973 if (UnitRngListAttribute.has_value())
1975 Unit, LinkedFunctionRanges, *UnitRngListAttribute, AddrPool);
1982void DWARFLinker::DIECloner::generateUnitLocations(
1983 CompileUnit &Unit,
const DWARFFile &File,
1984 ExpressionHandlerRef ExprHandler) {
1989 Unit.getLocationAttributes();
1991 if (AllLocListAttributes.empty())
1997 for (
auto &CurLocAttr : AllLocListAttributes) {
2000 Expected<DWARFLocationExpressionsVector> OriginalLocations =
2001 Unit.getOrigUnit().findLoclistFromOffset(CurLocAttr.get());
2003 if (!OriginalLocations) {
2005 Linker.reportWarning(
"Invalid location attribute ignored.", File);
2010 for (DWARFLocationExpression &CurExpression : *OriginalLocations) {
2011 DWARFLocationExpression LinkedExpression;
2013 if (CurExpression.Range) {
2015 LinkedExpression.Range = {
2016 CurExpression.Range->LowPC + CurLocAttr.RelocAdjustment,
2017 CurExpression.Range->HighPC + CurLocAttr.RelocAdjustment};
2021 LinkedExpression.Expr.reserve(CurExpression.Expr.size());
2022 ExprHandler(CurExpression.Expr, LinkedExpression.Expr,
2023 CurLocAttr.RelocAdjustment);
2025 LinkedLocationExpressions.push_back(LinkedExpression);
2029 Emitter->emitDwarfDebugLocListFragment(Unit, LinkedLocationExpressions,
2030 CurLocAttr, AddrPool);
2034 Emitter->emitDwarfDebugLocListFooter(Unit, EndLabel);
2038 for (
auto &V : Die.
values())
2039 if (V.getAttribute() == dwarf::DW_AT_addr_base) {
2047void DWARFLinker::DIECloner::emitDebugAddrSection(
2048 CompileUnit &Unit,
const uint16_t DwarfVersion)
const {
2053 if (DwarfVersion < 5)
2056 if (AddrPool.getValues().empty())
2059 MCSymbol *EndLabel =
Emitter->emitDwarfDebugAddrsHeader(Unit);
2061 DIEInteger(
Emitter->getDebugAddrSectionSize()));
2062 Emitter->emitDwarfDebugAddrs(AddrPool.getValues(),
2063 Unit.getOrigUnit().getAddressByteSize());
2064 Emitter->emitDwarfDebugAddrsFooter(Unit, EndLabel);
2070 std::vector<DWARFDebugLine::Row> &Rows) {
2074 if (!Rows.empty() && Rows.back().Address < Seq.front().Address) {
2088 if (InsertPoint != Rows.end() && InsertPoint->Address == Front &&
2089 InsertPoint->EndSequence) {
2090 *InsertPoint = Seq.front();
2091 Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end());
2093 Rows.insert(InsertPoint, Seq.begin(), Seq.end());
2100 for (
auto &V : Die.
values())
2101 if (V.getAttribute() == dwarf::DW_AT_stmt_list) {
2109void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {
2110 DWARFUnit &OrigUnit = Unit.getOrigUnit();
2111 DWARFDie OrigUnitDie = OrigUnit.getUnitDIE();
2113 if (std::optional<uint64_t> MacroAttr =
2115 UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));
2119 if (std::optional<uint64_t> MacroAttr =
2121 UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));
2126void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
2131 DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
2137 if (
auto *OutputDIE = Unit.getOutputUnitDIE())
2140 if (
const DWARFDebugLine::LineTable *LT =
2141 ObjFile.Dwarf->getLineTableForUnit(&Unit.getOrigUnit())) {
2143 DWARFDebugLine::LineTable LineTable;
2146 LineTable.Prologue =
LT->Prologue;
2149 if (Linker.Options.Update) {
2150 LineTable.Rows =
LT->Rows;
2153 if (LineTable.Rows.size() == 1 && LineTable.Rows[0].EndSequence)
2154 LineTable.Rows.clear();
2156 LineTable.Sequences =
LT->Sequences;
2159 std::vector<DWARFDebugLine::Row> NewRows;
2160 NewRows.reserve(
LT->Rows.size());
2164 std::vector<DWARFDebugLine::Row> Seq;
2166 const auto &FunctionRanges = Unit.getFunctionRanges();
2167 std::optional<AddressRangeValuePair> CurrRange;
2180 for (DWARFDebugLine::Row Row :
LT->Rows) {
2186 if (!CurrRange || !CurrRange->Range.contains(Row.Address.Address)) {
2190 CurrRange ? CurrRange->Range.end() + CurrRange->Value : -1ULL;
2191 CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);
2192 if (StopAddress != -1ULL && !Seq.empty()) {
2195 auto NextLine = Seq.back();
2196 NextLine.Address.Address = StopAddress;
2197 NextLine.EndSequence = 1;
2198 NextLine.PrologueEnd = 0;
2199 NextLine.BasicBlock = 0;
2200 NextLine.EpilogueBegin = 0;
2201 Seq.push_back(NextLine);
2210 if (Row.EndSequence && Seq.empty())
2214 Row.Address.Address += CurrRange->Value;
2215 Seq.emplace_back(Row);
2217 if (Row.EndSequence)
2221 LineTable.Rows = std::move(NewRows);
2224 Emitter->emitLineTableForUnit(LineTable, Unit, DebugStrPool,
2227 Linker.reportWarning(
"Cann't load line table.", ObjFile);
2230void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
2235 for (
const auto &Namespace : Unit.getNamespaces())
2236 AppleNamespaces.addName(Namespace.Name, Namespace.Die->getOffset() +
2237 Unit.getStartOffset());
2239 for (
const auto &Pubname : Unit.getPubnames())
2240 AppleNames.addName(Pubname.Name,
2241 Pubname.Die->getOffset() + Unit.getStartOffset());
2243 for (
const auto &Pubtype : Unit.getPubtypes())
2245 Pubtype.Name, Pubtype.Die->getOffset() + Unit.getStartOffset(),
2246 Pubtype.Die->getTag(),
2249 Pubtype.QualifiedNameHash);
2251 for (
const auto &ObjC : Unit.getObjC())
2252 AppleObjc.addName(
ObjC.Name,
2253 ObjC.Die->getOffset() + Unit.getStartOffset());
2260 for (
const auto &Namespace : Unit.getNamespaces())
2262 Namespace.Name, Namespace.Die->getOffset(),
2264 Namespace.Die->getTag(), Unit.getUniqueID(),
2265 Unit.getTag() == dwarf::DW_TAG_type_unit);
2266 for (
const auto &Pubname : Unit.getPubnames())
2268 Pubname.Name, Pubname.Die->getOffset(),
2270 Pubname.Die->getTag(), Unit.getUniqueID(),
2271 Unit.getTag() == dwarf::DW_TAG_type_unit);
2272 for (
const auto &Pubtype : Unit.getPubtypes())
2274 Pubtype.Name, Pubtype.Die->getOffset(),
2276 Pubtype.Die->getTag(), Unit.getUniqueID(),
2277 Unit.getTag() == dwarf::DW_TAG_type_unit);
2289void DWARFLinker::patchFrameInfoForObject(LinkContext &Context) {
2290 DWARFContext &OrigDwarf = *Context.File.Dwarf;
2291 unsigned SrcAddrSize = OrigDwarf.getDWARFObj().getAddressSize();
2293 StringRef
FrameData = OrigDwarf.getDWARFObj().getFrameSection().Data;
2298 for (std::unique_ptr<CompileUnit> &Unit : Context.CompileUnits) {
2299 for (
auto CurRange : Unit->getFunctionRanges())
2300 AllUnitsRanges.
insert(CurRange.Range, CurRange.Value);
2303 DataExtractor
Data(FrameData, OrigDwarf.isLittleEndian(), 0);
2308 DenseMap<uint64_t, StringRef> LocalCIES;
2310 while (
Data.isValidOffset(InputOffset)) {
2311 uint64_t EntryOffset = InputOffset;
2313 if (InitialLength == 0xFFFFFFFF)
2314 return reportWarning(
"Dwarf64 bits no supported", Context.File);
2317 if (CIEId == 0xFFFFFFFF) {
2319 StringRef CIEData =
FrameData.substr(EntryOffset, InitialLength + 4);
2320 LocalCIES[EntryOffset] = CIEData;
2322 InputOffset += InitialLength - 4;
2326 uint64_t Loc =
Data.getUnsigned(&InputOffset, SrcAddrSize);
2332 std::optional<AddressRangeValuePair>
Range =
2333 AllUnitsRanges.getRangeThatContains(Loc);
2336 InputOffset = EntryOffset + InitialLength + 4;
2342 StringRef CIEData = LocalCIES[CIEId];
2343 if (CIEData.empty())
2344 return reportWarning(
"Inconsistent debug_frame content. Dropping.",
2349 auto IteratorInserted = EmittedCIEs.
insert(
2352 if (IteratorInserted.second) {
2354 IteratorInserted.first->getValue() = LastCIEOffset;
2355 TheDwarfEmitter->
emitCIE(CIEData);
2361 unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize);
2362 TheDwarfEmitter->
emitFDE(IteratorInserted.first->getValue(), SrcAddrSize,
2364 FrameData.substr(InputOffset, FDERemainingBytes));
2365 InputOffset += FDERemainingBytes;
2369uint32_t DWARFLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE,
2371 const DWARFFile &File,
2372 int ChildRecurseDepth) {
2373 const char *
Name =
nullptr;
2374 DWARFUnit *OrigUnit = &
U.getOrigUnit();
2375 CompileUnit *
CU = &
U;
2376 std::optional<DWARFFormValue>
Ref;
2382 if (!(
Ref = DIE.find(dwarf::DW_AT_specification)) &&
2383 !(
Ref = DIE.find(dwarf::DW_AT_abstract_origin)))
2391 Linker.resolveDIEReference(File, CompileUnits, *
Ref, DIE, RefCU)) {
2393 OrigUnit = &RefCU->getOrigUnit();
2398 unsigned Idx = OrigUnit->getDIEIndex(DIE);
2399 if (!
Name && DIE.getTag() == dwarf::DW_TAG_namespace)
2400 Name =
"(anonymous namespace)";
2402 if (
CU->getInfo(
Idx).ParentIdx == 0 ||
2404 CU->getOrigUnit().getDIEAtIndex(
CU->getInfo(
Idx).ParentIdx).getTag() ==
2405 dwarf::DW_TAG_module)
2408 DWARFDie Die = OrigUnit->getDIEAtIndex(
CU->getInfo(
Idx).ParentIdx);
2417 CUDie.
find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id}));
2426 if (ObjectPrefixMap.empty())
2430 for (
const auto &Entry : ObjectPrefixMap)
2433 return p.str().str();
2440 CUDie.
find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
"");
2442 if (PCMFile.empty())
2445 if (ObjectPrefixMap)
2446 PCMFile =
remapPath(PCMFile, *ObjectPrefixMap);
2451std::pair<bool, bool> DWARFLinker::isClangModuleRef(
const DWARFDie &CUDie,
2452 std::string &PCMFile,
2453 LinkContext &Context,
2456 if (PCMFile.empty())
2457 return std::make_pair(
false,
false);
2465 reportWarning(
"Anonymous module skeleton CU for " + PCMFile,
2467 return std::make_pair(
true,
true);
2470 if (!
Quiet && Options.Verbose) {
2472 outs() <<
"Found clang module reference " << PCMFile;
2475 auto Cached = ClangModules.
find(PCMFile);
2476 if (Cached != ClangModules.
end()) {
2480 if (!
Quiet && Options.Verbose && (Cached->second != DwoId))
2481 reportWarning(Twine(
"hash mismatch: this object file was built against a "
2482 "different version of the module ") +
2485 if (!
Quiet && Options.Verbose)
2486 outs() <<
" [cached].\n";
2487 return std::make_pair(
true,
true);
2490 return std::make_pair(
true,
false);
2493bool DWARFLinker::registerModuleReference(
const DWARFDie &CUDie,
2494 LinkContext &Context,
2495 ObjFileLoaderTy Loader,
2496 CompileUnitHandlerTy OnCUDieLoaded,
2498 std::string PCMFile =
getPCMFile(CUDie, Options.ObjectPrefixMap);
2499 std::pair<bool, bool> IsClangModuleRef =
2500 isClangModuleRef(CUDie, PCMFile, Context, Indent,
false);
2502 if (!IsClangModuleRef.first)
2505 if (IsClangModuleRef.second)
2508 if (Options.Verbose)
2515 if (Error
E = loadClangModule(Loader, CUDie, PCMFile, Context, OnCUDieLoaded,
2523Error DWARFLinker::loadClangModule(
2524 ObjFileLoaderTy Loader,
const DWARFDie &CUDie,
const std::string &PCMFile,
2525 LinkContext &Context, CompileUnitHandlerTy OnCUDieLoaded,
unsigned Indent) {
2531 SmallString<0>
Path(Options.PrependPath);
2538 if (Loader ==
nullptr) {
2539 reportError(
"Could not load clang module: loader is not specified.\n",
2544 auto ErrOrObj = Loader(Context.File.FileName, Path);
2548 std::unique_ptr<CompileUnit> Unit;
2549 for (
const auto &
CU : ErrOrObj->Dwarf->compile_units()) {
2552 auto ChildCUDie =
CU->getUnitDIE();
2555 if (!registerModuleReference(ChildCUDie, Context, Loader, OnCUDieLoaded,
2560 ": Clang modules are expected to have exactly 1 compile unit.\n");
2561 reportError(Err, Context.File);
2568 if (PCMDwoId != DwoId) {
2569 if (Options.Verbose)
2571 Twine(
"hash mismatch: this object file was built against a "
2572 "different version of the module ") +
2576 ClangModules[PCMFile] = PCMDwoId;
2580 Unit = std::make_unique<CompileUnit>(*
CU, UniqueUnitID++, !Options.NoODR,
2586 Context.ModuleUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)});
2591uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
2592 DWARFContext &DwarfContext,
const DWARFFile &File,
bool IsLittleEndian) {
2595 const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
2597 for (
auto &CurrentUnit : CompileUnits) {
2598 const uint16_t DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
2599 const uint32_t UnitHeaderSize = DwarfVersion >= 5 ? 12 : 11;
2600 auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();
2601 CurrentUnit->setStartOffset(OutputDebugInfoSize);
2603 OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
2606 if (CurrentUnit->getInfo(0).Keep) {
2609 CurrentUnit->createOutputDIE();
2610 rememberUnitForMacroOffset(*CurrentUnit);
2611 cloneDIE(InputDIE, File, *CurrentUnit, 0 , UnitHeaderSize,
2612 0, IsLittleEndian, CurrentUnit->getOutputUnitDIE());
2615 OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
2619 generateLineTableForUnit(*CurrentUnit);
2621 Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
2626 Linker.generateUnitRanges(*CurrentUnit, File, AddrPool);
2628 auto ProcessExpr = [&](SmallVectorImpl<uint8_t> &SrcBytes,
2629 SmallVectorImpl<uint8_t> &OutBytes,
2630 int64_t RelocAdjustment) {
2631 DWARFUnit &OrigUnit = CurrentUnit->getOrigUnit();
2632 DataExtractor
Data(SrcBytes, IsLittleEndian,
2633 OrigUnit.getAddressByteSize());
2634 cloneExpression(
Data,
2635 DWARFExpression(
Data, OrigUnit.getAddressByteSize(),
2636 OrigUnit.getFormParams().Format),
2637 File, *CurrentUnit, OutBytes, RelocAdjustment,
2640 generateUnitLocations(*CurrentUnit, File, ProcessExpr);
2641 emitDebugAddrSection(*CurrentUnit, DwarfVersion);
2649 Emitter->emitMacroTables(
File.Dwarf.get(), UnitMacroMap, DebugStrPool);
2652 for (
auto &CurrentUnit : CompileUnits) {
2653 CurrentUnit->fixupForwardReferences();
2655 if (!CurrentUnit->getOutputUnitDIE())
2658 unsigned DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
2661 CurrentUnit->getStartOffset());
2662 Emitter->emitCompileUnitHeader(*CurrentUnit, DwarfVersion);
2663 Emitter->emitDIE(*CurrentUnit->getOutputUnitDIE());
2665 CurrentUnit->computeNextUnitOffset(DwarfVersion));
2669 return OutputDebugInfoSize - StartOutputDebugInfoSize;
2672void DWARFLinker::copyInvariantDebugSection(DWARFContext &
Dwarf) {
2676 Dwarf.getDWARFObj().getRangesSection().Data,
2685 Dwarf.getDWARFObj().getRnglistsSection().Data,
2688 Dwarf.getDWARFObj().getLoclistsSection().Data,
2694 ObjectContexts.emplace_back(LinkContext(File));
2696 if (ObjectContexts.back().File.Dwarf) {
2697 for (
const std::unique_ptr<DWARFUnit> &
CU :
2698 ObjectContexts.back().File.Dwarf->compile_units()) {
2707 registerModuleReference(CUDie, ObjectContexts.back(), Loader,
2714 assert((Options.TargetDWARFVersion != 0) &&
2715 "TargetDWARFVersion should be set");
2719 unsigned NumObjects = ObjectContexts.size();
2731 for (LinkContext &OptContext : ObjectContexts) {
2732 if (Options.Verbose)
2733 outs() <<
"DEBUG MAP OBJECT: " << OptContext.File.FileName <<
"\n";
2735 if (!OptContext.File.Dwarf)
2738 if (Options.VerifyInputDWARF)
2739 verifyInput(OptContext.File);
2746 !OptContext.File.Addresses->hasValidRelocs()) {
2747 if (Options.Verbose)
2748 outs() <<
"No valid relocations found. Skipping.\n";
2752 OptContext.Skip =
true;
2757 if (!OptContext.File.Dwarf)
2761 if (!OptContext.File.Dwarf->types_section_units().empty()) {
2762 reportWarning(
"type units are not currently supported: file will "
2765 OptContext.Skip =
true;
2771 OptContext.CompileUnits.reserve(
2772 OptContext.File.Dwarf->getNumCompileUnits());
2773 for (
const auto &
CU : OptContext.File.Dwarf->compile_units()) {
2774 auto CUDie =
CU->getUnitDIE(
true);
2775 if (Options.Verbose) {
2776 outs() <<
"Input compilation unit:";
2779 DumpOpts.
Verbose = Options.Verbose;
2780 CUDie.dump(
outs(), 0, DumpOpts);
2784 for (
auto &
CU : OptContext.ModuleUnits) {
2785 if (
Error Err = cloneModuleUnit(OptContext,
CU, ODRContexts, DebugStrPool,
2786 DebugLineStrPool, StringOffsetPool))
2787 reportWarning(
toString(std::move(Err)),
CU.File);
2797 (TheDwarfEmitter ==
nullptr) ? 0
2802 std::mutex ProcessedFilesMutex;
2803 std::condition_variable ProcessedFilesConditionVariable;
2804 BitVector ProcessedFiles(NumObjects,
false);
2808 auto AnalyzeLambda = [&](
size_t I) {
2809 auto &Context = ObjectContexts[
I];
2811 if (Context.Skip || !Context.File.Dwarf)
2814 for (
const auto &
CU : Context.File.Dwarf->compile_units()) {
2817 auto CUDie =
CU->getUnitDIE(
false);
2818 std::string PCMFile =
getPCMFile(CUDie, Options.ObjectPrefixMap);
2821 !isClangModuleRef(CUDie, PCMFile, Context, 0,
true).first) {
2822 Context.CompileUnits.push_back(std::make_unique<CompileUnit>(
2823 *
CU, UniqueUnitID++, !Options.NoODR && !Options.Update,
""));
2828 for (
auto &CurrentUnit : Context.CompileUnits) {
2829 auto CUDie = CurrentUnit->getOrigUnit().getUnitDIE();
2833 *CurrentUnit, &ODRContexts.
getRoot(), ODRContexts,
2834 ModulesEndOffset, Options.ParseableSwiftInterfaces,
2836 reportWarning(Warning, Context.File, &DIE);
2848 auto CloneLambda = [&](
size_t I) {
2849 auto &OptContext = ObjectContexts[
I];
2850 if (OptContext.Skip || !OptContext.File.Dwarf)
2859 for (
auto &CurrentUnit : OptContext.CompileUnits)
2860 CurrentUnit->markEverythingAsKept();
2861 copyInvariantDebugSection(*OptContext.File.Dwarf);
2863 for (
auto &CurrentUnit : OptContext.CompileUnits) {
2864 lookForDIEsToKeep(*OptContext.File.Addresses, OptContext.CompileUnits,
2865 CurrentUnit->getOrigUnit().getUnitDIE(),
2866 OptContext.File, *CurrentUnit, 0);
2876 if (OptContext.File.Addresses->hasValidRelocs() ||
2878 SizeByObject[OptContext.File.FileName].Input =
2880 SizeByObject[OptContext.File.FileName].Output =
2881 DIECloner(*
this, TheDwarfEmitter, OptContext.File, DIEAlloc,
2882 OptContext.CompileUnits, Options.Update, DebugStrPool,
2883 DebugLineStrPool, StringOffsetPool)
2884 .cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
2885 OptContext.File.Dwarf->isLittleEndian());
2887 if ((TheDwarfEmitter !=
nullptr) && !OptContext.CompileUnits.empty() &&
2889 patchFrameInfoForObject(OptContext);
2892 cleanupAuxiliarryData(OptContext);
2895 auto EmitLambda = [&]() {
2897 if (TheDwarfEmitter !=
nullptr) {
2898 TheDwarfEmitter->
emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);
2901 Options.TargetDWARFVersion);
2904 switch (TableKind) {
2923 auto AnalyzeAll = [&]() {
2924 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2927 std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
2928 ProcessedFiles.
set(
I);
2929 ProcessedFilesConditionVariable.notify_one();
2933 auto CloneAll = [&]() {
2934 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2936 std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
2937 if (!ProcessedFiles[
I]) {
2938 ProcessedFilesConditionVariable.wait(
2939 LockGuard, [&]() {
return ProcessedFiles[
I]; });
2951 if (Options.Threads == 1) {
2952 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2959 Pool.
async(AnalyzeAll);
2960 Pool.
async(CloneAll);
2964 if (Options.Statistics) {
2966 std::vector<std::pair<StringRef, DebugInfoSize>> Sorted;
2967 for (
auto &
E : SizeByObject)
2968 Sorted.emplace_back(
E.first(),
E.second);
2970 return LHS.second.Output >
RHS.second.Output;
2973 auto ComputePercentange = [](int64_t Input, int64_t Output) ->
float {
2974 const float Difference = Output - Input;
2975 const float Sum = Input + Output;
2978 return (Difference / (Sum / 2));
2981 int64_t InputTotal = 0;
2982 int64_t OutputTotal = 0;
2983 const char *FormatStr =
"{0,-45} {1,10}b {2,10}b {3,8:P}\n";
2986 outs() <<
".debug_info section size (in bytes)\n";
2987 outs() <<
"----------------------------------------------------------------"
2988 "---------------\n";
2989 outs() <<
"Filename Object "
2991 outs() <<
"----------------------------------------------------------------"
2992 "---------------\n";
2995 for (
auto &
E : Sorted) {
2996 InputTotal +=
E.second.Input;
2997 OutputTotal +=
E.second.Output;
3000 E.second.Output, ComputePercentange(
E.second.Input,
E.second.Output));
3003 outs() <<
"----------------------------------------------------------------"
3004 "---------------\n";
3006 ComputePercentange(InputTotal, OutputTotal));
3007 outs() <<
"----------------------------------------------------------------"
3008 "---------------\n\n";
3014Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
3020 assert(Unit.Unit.get() !=
nullptr);
3022 if (!Unit.Unit->getOrigUnit().getUnitDIE().hasChildren())
3025 if (Options.Verbose) {
3027 outs() <<
"cloning .debug_info from " << Unit.File.FileName <<
"\n";
3032 &ODRContexts.
getRoot(), ODRContexts, 0,
3033 Options.ParseableSwiftInterfaces,
3035 reportWarning(Warning, Context.File, &DIE);
3038 Unit.Unit->markEverythingAsKept();
3042 CompileUnits.emplace_back(std::move(Unit.Unit));
3044 DIECloner(*
this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits,
3045 Options.Update, DebugStrPool, DebugLineStrPool, StringOffsetPool)
3046 .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,
3047 Unit.File.Dwarf->isLittleEndian());
3051void DWARFLinker::verifyInput(
const DWARFFile &File) {
3058 if (Options.InputVerificationHandler)
3059 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?