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 bool Success = getDIENames(InputDIE, AttrInfo, DebugStrPool);
1845 bool ObjCClassIsImplementation =
1846 (RuntimeLang == dwarf::DW_LANG_ObjC ||
1847 RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
1850 if (
Success && AttrInfo.Name && !AttrInfo.Name.getString().empty()) {
1852 Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation,
1857 if (
Success && AttrInfo.MangledName &&
1858 RuntimeLang == dwarf::DW_LANG_Swift &&
1859 !AttrInfo.MangledName.getString().empty() &&
1860 AttrInfo.MangledName != AttrInfo.Name) {
1861 auto Hash =
djbHash(AttrInfo.MangledName.getString().data());
1862 Unit.addTypeAccelerator(Die, AttrInfo.MangledName,
1863 ObjCClassIsImplementation, Hash);
1868 bool HasChildren =
false;
1869 for (
auto Child : InputDIE.
children()) {
1870 unsigned Idx =
U.getDIEIndex(Child);
1871 if (Unit.getInfo(
Idx).Keep) {
1877 if (Unit.getOrigUnit().getVersion() >= 5 && !AttrInfo.AttrStrOffsetBaseSeen &&
1878 Die->
getTag() == dwarf::DW_TAG_compile_unit) {
1880 Die->
addValue(DIEAlloc, dwarf::DW_AT_str_offsets_base,
1881 dwarf::DW_FORM_sec_offset, DIEInteger(8));
1889 Linker.assignAbbrev(NewAbbrev);
1895 OutOffset += AbbrevNumberSize;
1898 for (AttributeLinkedOffsetFixup &
F : AttributesFixups)
1899 F.LinkedOffsetFixupVal += AbbrevNumberSize;
1901 for (AttributeLinkedOffsetFixup &
F : AttributesFixups)
1902 ObjFile.Addresses->updateAndSaveValidRelocs(
1903 Unit.getOrigUnit().getVersion() >= 5, Unit.getOrigUnit().getOffset(),
1904 F.LinkedOffsetFixupVal,
F.InputAttrStartOffset,
F.InputAttrEndOffset);
1913 for (
auto Child : InputDIE.
children()) {
1914 if (DIE *Clone = cloneDIE(Child, File, Unit, PCOffset, OutOffset, Flags,
1917 OutOffset = Clone->getOffset() + Clone->getSize();
1922 OutOffset +=
sizeof(int8_t);
1931void DWARFLinker::generateUnitRanges(CompileUnit &Unit,
const DWARFFile &File,
1936 const auto &FunctionRanges = Unit.getFunctionRanges();
1939 AddressRanges LinkedFunctionRanges;
1940 for (
const AddressRangeValuePair &
Range : FunctionRanges)
1941 LinkedFunctionRanges.insert(
1945 if (!LinkedFunctionRanges.empty())
1949 std::optional<PatchLocation> UnitRngListAttribute =
1950 Unit.getUnitRangesAttribute();
1952 if (!AllRngListAttributes.empty() || UnitRngListAttribute) {
1953 std::optional<AddressRangeValuePair> CachedRange;
1958 for (PatchLocation &AttributePatch : AllRngListAttributes) {
1961 AddressRanges LinkedRanges;
1962 if (Expected<DWARFAddressRangesVector> OriginalRanges =
1963 Unit.getOrigUnit().findRnglistFromOffset(AttributePatch.get())) {
1965 for (
const auto &
Range : *OriginalRanges) {
1966 if (!CachedRange || !CachedRange->Range.contains(
Range.LowPC))
1967 CachedRange = FunctionRanges.getRangeThatContains(
Range.LowPC);
1971 reportWarning(
"inconsistent range data.", File);
1976 LinkedRanges.insert({
Range.LowPC + CachedRange->Value,
1977 Range.HighPC + CachedRange->Value});
1981 reportWarning(
"invalid range list ignored.", File);
1986 Unit, LinkedRanges, AttributePatch, AddrPool);
1990 if (UnitRngListAttribute.has_value())
1992 Unit, LinkedFunctionRanges, *UnitRngListAttribute, AddrPool);
1999void DWARFLinker::DIECloner::generateUnitLocations(
2000 CompileUnit &Unit,
const DWARFFile &File,
2001 ExpressionHandlerRef ExprHandler) {
2006 Unit.getLocationAttributes();
2008 if (AllLocListAttributes.empty())
2014 for (
auto &CurLocAttr : AllLocListAttributes) {
2017 Expected<DWARFLocationExpressionsVector> OriginalLocations =
2018 Unit.getOrigUnit().findLoclistFromOffset(CurLocAttr.get());
2020 if (!OriginalLocations) {
2022 Linker.reportWarning(
"Invalid location attribute ignored.", File);
2027 for (DWARFLocationExpression &CurExpression : *OriginalLocations) {
2028 DWARFLocationExpression LinkedExpression;
2030 if (CurExpression.Range) {
2032 LinkedExpression.Range = {
2033 CurExpression.Range->LowPC + CurLocAttr.RelocAdjustment,
2034 CurExpression.Range->HighPC + CurLocAttr.RelocAdjustment};
2038 LinkedExpression.Expr.reserve(CurExpression.Expr.size());
2039 ExprHandler(CurExpression.Expr, LinkedExpression.Expr,
2040 CurLocAttr.RelocAdjustment);
2042 LinkedLocationExpressions.push_back(LinkedExpression);
2046 Emitter->emitDwarfDebugLocListFragment(Unit, LinkedLocationExpressions,
2047 CurLocAttr, AddrPool);
2051 Emitter->emitDwarfDebugLocListFooter(Unit, EndLabel);
2055 for (
auto &V : Die.
values())
2056 if (V.getAttribute() == dwarf::DW_AT_addr_base) {
2064void DWARFLinker::DIECloner::emitDebugAddrSection(
2065 CompileUnit &Unit,
const uint16_t DwarfVersion)
const {
2070 if (DwarfVersion < 5)
2073 if (AddrPool.getValues().empty())
2076 MCSymbol *EndLabel =
Emitter->emitDwarfDebugAddrsHeader(Unit);
2078 DIEInteger(
Emitter->getDebugAddrSectionSize()));
2079 Emitter->emitDwarfDebugAddrs(AddrPool.getValues(),
2080 Unit.getOrigUnit().getAddressByteSize());
2081 Emitter->emitDwarfDebugAddrsFooter(Unit, EndLabel);
2087 std::vector<DWARFDebugLine::Row> &Rows) {
2091 if (!Rows.empty() && Rows.back().Address < Seq.front().Address) {
2105 if (InsertPoint != Rows.end() && InsertPoint->Address == Front &&
2106 InsertPoint->EndSequence) {
2107 *InsertPoint = Seq.front();
2108 Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end());
2110 Rows.insert(InsertPoint, Seq.begin(), Seq.end());
2117 for (
auto &V : Die.
values())
2118 if (V.getAttribute() == dwarf::DW_AT_stmt_list) {
2126void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {
2127 DWARFUnit &OrigUnit = Unit.getOrigUnit();
2128 DWARFDie OrigUnitDie = OrigUnit.getUnitDIE();
2130 if (std::optional<uint64_t> MacroAttr =
2132 UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));
2136 if (std::optional<uint64_t> MacroAttr =
2138 UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));
2143void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
2148 DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
2154 if (
auto *OutputDIE = Unit.getOutputUnitDIE())
2157 if (
const DWARFDebugLine::LineTable *LT =
2158 ObjFile.Dwarf->getLineTableForUnit(&Unit.getOrigUnit())) {
2160 DWARFDebugLine::LineTable LineTable;
2163 LineTable.Prologue =
LT->Prologue;
2166 if (Linker.Options.Update) {
2167 LineTable.Rows =
LT->Rows;
2170 if (LineTable.Rows.size() == 1 && LineTable.Rows[0].EndSequence)
2171 LineTable.Rows.clear();
2173 LineTable.Sequences =
LT->Sequences;
2176 std::vector<DWARFDebugLine::Row> NewRows;
2177 NewRows.reserve(
LT->Rows.size());
2181 std::vector<DWARFDebugLine::Row> Seq;
2183 const auto &FunctionRanges = Unit.getFunctionRanges();
2184 std::optional<AddressRangeValuePair> CurrRange;
2197 for (DWARFDebugLine::Row Row :
LT->Rows) {
2203 if (!CurrRange || !CurrRange->Range.contains(Row.Address.Address)) {
2207 CurrRange ? CurrRange->Range.end() + CurrRange->Value : -1ULL;
2208 CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);
2209 if (StopAddress != -1ULL && !Seq.empty()) {
2212 auto NextLine = Seq.back();
2213 NextLine.Address.Address = StopAddress;
2214 NextLine.EndSequence = 1;
2215 NextLine.PrologueEnd = 0;
2216 NextLine.BasicBlock = 0;
2217 NextLine.EpilogueBegin = 0;
2218 Seq.push_back(NextLine);
2227 if (Row.EndSequence && Seq.empty())
2231 Row.Address.Address += CurrRange->Value;
2232 Seq.emplace_back(Row);
2234 if (Row.EndSequence)
2238 LineTable.Rows = std::move(NewRows);
2241 Emitter->emitLineTableForUnit(LineTable, Unit, DebugStrPool,
2244 Linker.reportWarning(
"Cann't load line table.", ObjFile);
2247void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
2252 for (
const auto &Namespace : Unit.getNamespaces())
2253 AppleNamespaces.addName(Namespace.Name, Namespace.Die->getOffset() +
2254 Unit.getStartOffset());
2256 for (
const auto &Pubname : Unit.getPubnames())
2257 AppleNames.addName(Pubname.Name,
2258 Pubname.Die->getOffset() + Unit.getStartOffset());
2260 for (
const auto &Pubtype : Unit.getPubtypes())
2262 Pubtype.Name, Pubtype.Die->getOffset() + Unit.getStartOffset(),
2263 Pubtype.Die->getTag(),
2266 Pubtype.QualifiedNameHash);
2268 for (
const auto &ObjC : Unit.getObjC())
2269 AppleObjc.addName(
ObjC.Name,
2270 ObjC.Die->getOffset() + Unit.getStartOffset());
2277 for (
const auto &Namespace : Unit.getNamespaces())
2279 Namespace.Name, Namespace.Die->getOffset(),
2281 Namespace.Die->getTag(), Unit.getUniqueID(),
2282 Unit.getTag() == dwarf::DW_TAG_type_unit);
2283 for (
const auto &Pubname : Unit.getPubnames())
2285 Pubname.Name, Pubname.Die->getOffset(),
2287 Pubname.Die->getTag(), Unit.getUniqueID(),
2288 Unit.getTag() == dwarf::DW_TAG_type_unit);
2289 for (
const auto &Pubtype : Unit.getPubtypes())
2291 Pubtype.Name, Pubtype.Die->getOffset(),
2293 Pubtype.Die->getTag(), Unit.getUniqueID(),
2294 Unit.getTag() == dwarf::DW_TAG_type_unit);
2306void DWARFLinker::patchFrameInfoForObject(LinkContext &Context) {
2307 DWARFContext &OrigDwarf = *Context.File.Dwarf;
2308 unsigned SrcAddrSize = OrigDwarf.getDWARFObj().getAddressSize();
2310 StringRef
FrameData = OrigDwarf.getDWARFObj().getFrameSection().Data;
2315 for (std::unique_ptr<CompileUnit> &Unit : Context.CompileUnits) {
2316 for (
auto CurRange : Unit->getFunctionRanges())
2317 AllUnitsRanges.
insert(CurRange.Range, CurRange.Value);
2320 DataExtractor
Data(FrameData, OrigDwarf.isLittleEndian(), 0);
2325 DenseMap<uint64_t, StringRef> LocalCIES;
2327 while (
Data.isValidOffset(InputOffset)) {
2328 uint64_t EntryOffset = InputOffset;
2330 if (InitialLength == 0xFFFFFFFF)
2331 return reportWarning(
"Dwarf64 bits no supported", Context.File);
2334 if (CIEId == 0xFFFFFFFF) {
2336 StringRef CIEData =
FrameData.substr(EntryOffset, InitialLength + 4);
2337 LocalCIES[EntryOffset] = CIEData;
2339 InputOffset += InitialLength - 4;
2343 uint64_t Loc =
Data.getUnsigned(&InputOffset, SrcAddrSize);
2349 std::optional<AddressRangeValuePair>
Range =
2350 AllUnitsRanges.getRangeThatContains(Loc);
2353 InputOffset = EntryOffset + InitialLength + 4;
2359 StringRef CIEData = LocalCIES[CIEId];
2360 if (CIEData.empty())
2361 return reportWarning(
"Inconsistent debug_frame content. Dropping.",
2366 auto IteratorInserted = EmittedCIEs.
insert(
2369 if (IteratorInserted.second) {
2371 IteratorInserted.first->getValue() = LastCIEOffset;
2372 TheDwarfEmitter->
emitCIE(CIEData);
2378 unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize);
2379 TheDwarfEmitter->
emitFDE(IteratorInserted.first->getValue(), SrcAddrSize,
2381 FrameData.substr(InputOffset, FDERemainingBytes));
2382 InputOffset += FDERemainingBytes;
2386uint32_t DWARFLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE,
2388 const DWARFFile &File,
2389 int ChildRecurseDepth) {
2390 const char *
Name =
nullptr;
2391 DWARFUnit *OrigUnit = &
U.getOrigUnit();
2392 CompileUnit *
CU = &
U;
2393 std::optional<DWARFFormValue>
Ref;
2399 if (!(
Ref = DIE.find(dwarf::DW_AT_specification)) &&
2400 !(
Ref = DIE.find(dwarf::DW_AT_abstract_origin)))
2408 Linker.resolveDIEReference(File, CompileUnits, *
Ref, DIE, RefCU)) {
2410 OrigUnit = &RefCU->getOrigUnit();
2415 unsigned Idx = OrigUnit->getDIEIndex(DIE);
2416 if (!
Name && DIE.getTag() == dwarf::DW_TAG_namespace)
2417 Name =
"(anonymous namespace)";
2419 if (
CU->getInfo(
Idx).ParentIdx == 0 ||
2421 CU->getOrigUnit().getDIEAtIndex(
CU->getInfo(
Idx).ParentIdx).getTag() ==
2422 dwarf::DW_TAG_module)
2425 DWARFDie Die = OrigUnit->getDIEAtIndex(
CU->getInfo(
Idx).ParentIdx);
2434 CUDie.
find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id}));
2443 if (ObjectPrefixMap.empty())
2447 for (
const auto &Entry : ObjectPrefixMap)
2450 return p.str().str();
2457 CUDie.
find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
"");
2459 if (PCMFile.empty())
2462 if (ObjectPrefixMap)
2463 PCMFile =
remapPath(PCMFile, *ObjectPrefixMap);
2468std::pair<bool, bool> DWARFLinker::isClangModuleRef(
const DWARFDie &CUDie,
2469 std::string &PCMFile,
2470 LinkContext &Context,
2473 if (PCMFile.empty())
2474 return std::make_pair(
false,
false);
2482 reportWarning(
"Anonymous module skeleton CU for " + PCMFile,
2484 return std::make_pair(
true,
true);
2487 if (!
Quiet && Options.Verbose) {
2489 outs() <<
"Found clang module reference " << PCMFile;
2492 auto Cached = ClangModules.
find(PCMFile);
2493 if (Cached != ClangModules.
end()) {
2497 if (!
Quiet && Options.Verbose && (Cached->second != DwoId))
2498 reportWarning(Twine(
"hash mismatch: this object file was built against a "
2499 "different version of the module ") +
2502 if (!
Quiet && Options.Verbose)
2503 outs() <<
" [cached].\n";
2504 return std::make_pair(
true,
true);
2507 return std::make_pair(
true,
false);
2510bool DWARFLinker::registerModuleReference(
const DWARFDie &CUDie,
2511 LinkContext &Context,
2512 ObjFileLoaderTy Loader,
2513 CompileUnitHandlerTy OnCUDieLoaded,
2515 std::string PCMFile =
getPCMFile(CUDie, Options.ObjectPrefixMap);
2516 std::pair<bool, bool> IsClangModuleRef =
2517 isClangModuleRef(CUDie, PCMFile, Context, Indent,
false);
2519 if (!IsClangModuleRef.first)
2522 if (IsClangModuleRef.second)
2525 if (Options.Verbose)
2532 if (Error
E = loadClangModule(Loader, CUDie, PCMFile, Context, OnCUDieLoaded,
2540Error DWARFLinker::loadClangModule(
2541 ObjFileLoaderTy Loader,
const DWARFDie &CUDie,
const std::string &PCMFile,
2542 LinkContext &Context, CompileUnitHandlerTy OnCUDieLoaded,
unsigned Indent) {
2548 SmallString<0>
Path(Options.PrependPath);
2555 if (Loader ==
nullptr) {
2556 reportError(
"Could not load clang module: loader is not specified.\n",
2561 auto ErrOrObj = Loader(Context.File.FileName, Path);
2565 std::unique_ptr<CompileUnit> Unit;
2566 for (
const auto &
CU : ErrOrObj->Dwarf->compile_units()) {
2569 auto ChildCUDie =
CU->getUnitDIE();
2572 if (!registerModuleReference(ChildCUDie, Context, Loader, OnCUDieLoaded,
2577 ": Clang modules are expected to have exactly 1 compile unit.\n");
2578 reportError(Err, Context.File);
2585 if (PCMDwoId != DwoId) {
2586 if (Options.Verbose)
2588 Twine(
"hash mismatch: this object file was built against a "
2589 "different version of the module ") +
2593 ClangModules[PCMFile] = PCMDwoId;
2597 Unit = std::make_unique<CompileUnit>(*
CU, UniqueUnitID++, !Options.NoODR,
2603 Context.ModuleUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)});
2608uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
2609 DWARFContext &DwarfContext,
const DWARFFile &File,
bool IsLittleEndian) {
2612 const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
2614 for (
auto &CurrentUnit : CompileUnits) {
2615 const uint16_t DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
2616 const uint32_t UnitHeaderSize = DwarfVersion >= 5 ? 12 : 11;
2617 auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();
2618 CurrentUnit->setStartOffset(OutputDebugInfoSize);
2620 OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
2623 if (CurrentUnit->getInfo(0).Keep) {
2626 CurrentUnit->createOutputDIE();
2627 rememberUnitForMacroOffset(*CurrentUnit);
2628 cloneDIE(InputDIE, File, *CurrentUnit, 0 , UnitHeaderSize,
2629 0, IsLittleEndian, CurrentUnit->getOutputUnitDIE());
2632 OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
2636 generateLineTableForUnit(*CurrentUnit);
2638 Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
2643 Linker.generateUnitRanges(*CurrentUnit, File, AddrPool);
2645 auto ProcessExpr = [&](SmallVectorImpl<uint8_t> &SrcBytes,
2646 SmallVectorImpl<uint8_t> &OutBytes,
2647 int64_t RelocAdjustment) {
2648 DWARFUnit &OrigUnit = CurrentUnit->getOrigUnit();
2649 DataExtractor
Data(SrcBytes, IsLittleEndian,
2650 OrigUnit.getAddressByteSize());
2651 cloneExpression(
Data,
2652 DWARFExpression(
Data, OrigUnit.getAddressByteSize(),
2653 OrigUnit.getFormParams().Format),
2654 File, *CurrentUnit, OutBytes, RelocAdjustment,
2657 generateUnitLocations(*CurrentUnit, File, ProcessExpr);
2658 emitDebugAddrSection(*CurrentUnit, DwarfVersion);
2666 Emitter->emitMacroTables(
File.Dwarf.get(), UnitMacroMap, DebugStrPool);
2669 for (
auto &CurrentUnit : CompileUnits) {
2670 CurrentUnit->fixupForwardReferences();
2672 if (!CurrentUnit->getOutputUnitDIE())
2675 unsigned DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
2678 CurrentUnit->getStartOffset());
2679 Emitter->emitCompileUnitHeader(*CurrentUnit, DwarfVersion);
2680 Emitter->emitDIE(*CurrentUnit->getOutputUnitDIE());
2682 CurrentUnit->computeNextUnitOffset(DwarfVersion));
2686 return OutputDebugInfoSize - StartOutputDebugInfoSize;
2689void DWARFLinker::copyInvariantDebugSection(DWARFContext &
Dwarf) {
2693 Dwarf.getDWARFObj().getRangesSection().Data,
2702 Dwarf.getDWARFObj().getRnglistsSection().Data,
2705 Dwarf.getDWARFObj().getLoclistsSection().Data,
2711 ObjectContexts.emplace_back(LinkContext(File));
2713 if (ObjectContexts.back().File.Dwarf) {
2714 for (
const std::unique_ptr<DWARFUnit> &
CU :
2715 ObjectContexts.back().File.Dwarf->compile_units()) {
2724 registerModuleReference(CUDie, ObjectContexts.back(), Loader,
2731 assert((Options.TargetDWARFVersion != 0) &&
2732 "TargetDWARFVersion should be set");
2736 unsigned NumObjects = ObjectContexts.size();
2748 for (LinkContext &OptContext : ObjectContexts) {
2749 if (Options.Verbose)
2750 outs() <<
"DEBUG MAP OBJECT: " << OptContext.File.FileName <<
"\n";
2752 if (!OptContext.File.Dwarf)
2755 if (Options.VerifyInputDWARF)
2756 verifyInput(OptContext.File);
2763 !OptContext.File.Addresses->hasValidRelocs()) {
2764 if (Options.Verbose)
2765 outs() <<
"No valid relocations found. Skipping.\n";
2769 OptContext.Skip =
true;
2774 if (!OptContext.File.Dwarf)
2778 if (!OptContext.File.Dwarf->types_section_units().empty()) {
2779 reportWarning(
"type units are not currently supported: file will "
2782 OptContext.Skip =
true;
2788 OptContext.CompileUnits.reserve(
2789 OptContext.File.Dwarf->getNumCompileUnits());
2790 for (
const auto &
CU : OptContext.File.Dwarf->compile_units()) {
2791 auto CUDie =
CU->getUnitDIE(
true);
2792 if (Options.Verbose) {
2793 outs() <<
"Input compilation unit:";
2796 DumpOpts.
Verbose = Options.Verbose;
2797 CUDie.dump(
outs(), 0, DumpOpts);
2801 for (
auto &
CU : OptContext.ModuleUnits) {
2802 if (
Error Err = cloneModuleUnit(OptContext,
CU, ODRContexts, DebugStrPool,
2803 DebugLineStrPool, StringOffsetPool))
2804 reportWarning(
toString(std::move(Err)),
CU.File);
2814 (TheDwarfEmitter ==
nullptr) ? 0
2819 std::mutex ProcessedFilesMutex;
2820 std::condition_variable ProcessedFilesConditionVariable;
2821 BitVector ProcessedFiles(NumObjects,
false);
2825 auto AnalyzeLambda = [&](
size_t I) {
2826 auto &Context = ObjectContexts[
I];
2828 if (Context.Skip || !Context.File.Dwarf)
2831 for (
const auto &
CU : Context.File.Dwarf->compile_units()) {
2834 auto CUDie =
CU->getUnitDIE(
false);
2835 std::string PCMFile =
getPCMFile(CUDie, Options.ObjectPrefixMap);
2838 !isClangModuleRef(CUDie, PCMFile, Context, 0,
true).first) {
2839 Context.CompileUnits.push_back(std::make_unique<CompileUnit>(
2840 *
CU, UniqueUnitID++, !Options.NoODR && !Options.Update,
""));
2845 for (
auto &CurrentUnit : Context.CompileUnits) {
2846 auto CUDie = CurrentUnit->getOrigUnit().getUnitDIE();
2850 *CurrentUnit, &ODRContexts.
getRoot(), ODRContexts,
2851 ModulesEndOffset, Options.ParseableSwiftInterfaces,
2853 reportWarning(Warning, Context.File, &DIE);
2865 auto CloneLambda = [&](
size_t I) {
2866 auto &OptContext = ObjectContexts[
I];
2867 if (OptContext.Skip || !OptContext.File.Dwarf)
2876 for (
auto &CurrentUnit : OptContext.CompileUnits)
2877 CurrentUnit->markEverythingAsKept();
2878 copyInvariantDebugSection(*OptContext.File.Dwarf);
2880 for (
auto &CurrentUnit : OptContext.CompileUnits) {
2881 lookForDIEsToKeep(*OptContext.File.Addresses, OptContext.CompileUnits,
2882 CurrentUnit->getOrigUnit().getUnitDIE(),
2883 OptContext.File, *CurrentUnit, 0);
2893 if (OptContext.File.Addresses->hasValidRelocs() ||
2895 SizeByObject[OptContext.File.FileName].Input =
2897 SizeByObject[OptContext.File.FileName].Output =
2898 DIECloner(*
this, TheDwarfEmitter, OptContext.File, DIEAlloc,
2899 OptContext.CompileUnits, Options.Update, DebugStrPool,
2900 DebugLineStrPool, StringOffsetPool)
2901 .cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
2902 OptContext.File.Dwarf->isLittleEndian());
2904 if ((TheDwarfEmitter !=
nullptr) && !OptContext.CompileUnits.empty() &&
2906 patchFrameInfoForObject(OptContext);
2909 cleanupAuxiliarryData(OptContext);
2912 auto EmitLambda = [&]() {
2914 if (TheDwarfEmitter !=
nullptr) {
2915 TheDwarfEmitter->
emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);
2918 Options.TargetDWARFVersion);
2921 switch (TableKind) {
2940 auto AnalyzeAll = [&]() {
2941 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2944 std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
2945 ProcessedFiles.
set(
I);
2946 ProcessedFilesConditionVariable.notify_one();
2950 auto CloneAll = [&]() {
2951 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2953 std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
2954 if (!ProcessedFiles[
I]) {
2955 ProcessedFilesConditionVariable.wait(
2956 LockGuard, [&]() {
return ProcessedFiles[
I]; });
2968 if (Options.Threads == 1) {
2969 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2976 Pool.
async(AnalyzeAll);
2977 Pool.
async(CloneAll);
2981 if (Options.Statistics) {
2983 std::vector<std::pair<StringRef, DebugInfoSize>> Sorted;
2984 for (
auto &
E : SizeByObject)
2985 Sorted.emplace_back(
E.first(),
E.second);
2987 return LHS.second.Output >
RHS.second.Output;
2990 auto ComputePercentange = [](int64_t Input, int64_t Output) ->
float {
2991 const float Difference = Output - Input;
2992 const float Sum = Input + Output;
2995 return (Difference / (Sum / 2));
2998 int64_t InputTotal = 0;
2999 int64_t OutputTotal = 0;
3000 const char *FormatStr =
"{0,-45} {1,10}b {2,10}b {3,8:P}\n";
3003 outs() <<
".debug_info section size (in bytes)\n";
3004 outs() <<
"----------------------------------------------------------------"
3005 "---------------\n";
3006 outs() <<
"Filename Object "
3008 outs() <<
"----------------------------------------------------------------"
3009 "---------------\n";
3012 for (
auto &
E : Sorted) {
3013 InputTotal +=
E.second.Input;
3014 OutputTotal +=
E.second.Output;
3017 E.second.Output, ComputePercentange(
E.second.Input,
E.second.Output));
3020 outs() <<
"----------------------------------------------------------------"
3021 "---------------\n";
3023 ComputePercentange(InputTotal, OutputTotal));
3024 outs() <<
"----------------------------------------------------------------"
3025 "---------------\n\n";
3031Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
3037 assert(Unit.Unit.get() !=
nullptr);
3039 if (!Unit.Unit->getOrigUnit().getUnitDIE().hasChildren())
3042 if (Options.Verbose) {
3044 outs() <<
"cloning .debug_info from " << Unit.File.FileName <<
"\n";
3049 &ODRContexts.
getRoot(), ODRContexts, 0,
3050 Options.ParseableSwiftInterfaces,
3052 reportWarning(Warning, Context.File, &DIE);
3055 Unit.Unit->markEverythingAsKept();
3059 CompileUnits.emplace_back(std::move(Unit.Unit));
3061 DIECloner(*
this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits,
3062 Options.Update, DebugStrPool, DebugLineStrPool, StringOffsetPool)
3063 .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,
3064 Unit.File.Dwarf->isLittleEndian());
3068void DWARFLinker::verifyInput(
const DWARFFile &File) {
3075 if (Options.InputVerificationHandler)
3076 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.
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.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
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)
const char * toString(DWARFSectionKind Kind)
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?