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) {
80 uint64_t RefOffset = *RefValue.getAsReference();
82 if (
const auto RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) {
89 reportWarning(
"could not find referenced DIE", File, &DIE);
99 case dwarf::DW_AT_type:
100 case dwarf::DW_AT_containing_type:
101 case dwarf::DW_AT_specification:
102 case dwarf::DW_AT_abstract_origin:
103 case dwarf::DW_AT_import:
111 case dwarf::DW_TAG_array_type:
112 case dwarf::DW_TAG_class_type:
113 case dwarf::DW_TAG_enumeration_type:
114 case dwarf::DW_TAG_pointer_type:
115 case dwarf::DW_TAG_reference_type:
116 case dwarf::DW_TAG_string_type:
117 case dwarf::DW_TAG_structure_type:
118 case dwarf::DW_TAG_subroutine_type:
119 case dwarf::DW_TAG_template_alias:
120 case dwarf::DW_TAG_typedef:
121 case dwarf::DW_TAG_union_type:
122 case dwarf::DW_TAG_ptr_to_member_type:
123 case dwarf::DW_TAG_set_type:
124 case dwarf::DW_TAG_subrange_type:
125 case dwarf::DW_TAG_base_type:
126 case dwarf::DW_TAG_const_type:
127 case dwarf::DW_TAG_constant:
128 case dwarf::DW_TAG_file_type:
129 case dwarf::DW_TAG_namelist:
130 case dwarf::DW_TAG_packed_type:
131 case dwarf::DW_TAG_volatile_type:
132 case dwarf::DW_TAG_restrict_type:
133 case dwarf::DW_TAG_atomic_type:
134 case dwarf::DW_TAG_interface_type:
135 case dwarf::DW_TAG_unspecified_type:
136 case dwarf::DW_TAG_shared_type:
137 case dwarf::DW_TAG_immutable_type:
145bool DWARFLinker::DIECloner::getDIENames(
const DWARFDie &Die,
146 AttributesInfo &
Info,
148 bool StripTemplate) {
152 if (Die.getTag() == dwarf::DW_TAG_lexical_block)
155 if (!
Info.MangledName)
156 if (
const char *MangledName = Die.getLinkageName())
157 Info.MangledName = StringPool.getEntry(MangledName);
160 if (
const char *
Name = Die.getShortName())
161 Info.Name = StringPool.getEntry(
Name);
163 if (!
Info.MangledName)
166 if (StripTemplate &&
Info.Name &&
Info.MangledName !=
Info.Name) {
167 StringRef
Name =
Info.Name.getString();
169 Info.NameWithoutTemplate = StringPool.getEntry(*StrippedName);
172 return Info.Name ||
Info.MangledName;
186 std::function<
void(
const Twine &,
const DWARFDie &)> ReportWarning) {
187 if (
CU.getLanguage() != dwarf::DW_LANG_Swift)
190 if (!ParseableSwiftInterfaces)
194 if (!Path.ends_with(
".swiftinterface"))
199 SysRoot =
CU.getSysRoot();
200 if (!SysRoot.
empty() && Path.starts_with(SysRoot))
205 if (!Toolchain.
empty() && Path.starts_with(Toolchain))
207 std::optional<const char *>
Name =
211 auto &Entry = (*ParseableSwiftInterfaces)[*
Name];
213 DWARFDie CUDie =
CU.getOrigUnit().getUnitDIE();
218 if (!Entry.empty() && Entry != ResolvedPath)
219 ReportWarning(
Twine(
"Conflicting parseable interfaces for Swift Module ") +
220 *
Name +
": " + Entry +
" and " + Path,
222 Entry = std::string(ResolvedPath);
248 : Die(Die), ParentIdx(0), OtherInfo(OtherInfo),
Type(
T),
249 InImportedModule(
false) {}
252 bool InImportedModule)
255 InImportedModule(InImportedModule) {}
265 Info.Prune &= (Die.
getTag() == dwarf::DW_TAG_module) ||
271 if (ModulesEndOffset == 0)
272 Info.Prune &=
Info.Ctxt &&
Info.Ctxt->getCanonicalDIEOffset();
274 Info.Prune &=
Info.Ctxt &&
Info.Ctxt->getCanonicalDIEOffset() > 0 &&
275 Info.Ctxt->getCanonicalDIEOffset() <= ModulesEndOffset;
299 std::function<
void(
const Twine &,
const DWARFDie &)> ReportWarning) {
301 std::vector<ContextWorklistItem> Worklist;
302 Worklist.emplace_back(
DIE, CurrentDeclContext, ParentIdx,
false);
304 while (!Worklist.empty()) {
308 switch (Current.
Type) {
319 unsigned Idx =
CU.getOrigUnit().getDIEIndex(Current.
Die);
334 if (Current.
Die.
getTag() == dwarf::DW_TAG_module &&
337 CU.getClangModuleName()) {
345 if (
CU.hasODR() ||
Info.InModuleScope) {
349 Current.
Context = PtrInvalidPair.getPointer();
351 PtrInvalidPair.getInt() ? nullptr : PtrInvalidPair.getPointer();
353 Info.Ctxt->setDefinedInClangModule(
Info.InModuleScope);
364 Worklist.emplace_back(
366 Worklist.emplace_back(Child, Current.
Context,
Idx,
376 case dwarf::DW_TAG_class_type:
377 case dwarf::DW_TAG_common_block:
378 case dwarf::DW_TAG_lexical_block:
379 case dwarf::DW_TAG_structure_type:
380 case dwarf::DW_TAG_subprogram:
381 case dwarf::DW_TAG_subroutine_type:
382 case dwarf::DW_TAG_union_type:
388void DWARFLinker::cleanupAuxiliarryData(LinkContext &Context) {
391 for (DIEBlock *
I : DIEBlocks)
393 for (DIELoc *
I : DIELocs)
402 return DW_OP_Code == dwarf::DW_OP_form_tls_address ||
403 DW_OP_Code == dwarf::DW_OP_GNU_push_tls_address;
406std::pair<bool, std::optional<int64_t>>
407DWARFLinker::getVariableRelocAdjustment(AddressesMap &RelocMgr,
408 const DWARFDie &DIE) {
409 assert((DIE.getTag() == dwarf::DW_TAG_variable ||
410 DIE.getTag() == dwarf::DW_TAG_constant) &&
411 "Wrong type of input die");
413 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
416 DWARFUnit *U = DIE.getDwarfUnit();
417 std::optional<uint32_t> LocationIdx =
418 Abbrev->findAttributeIndex(dwarf::DW_AT_location);
420 return std::make_pair(
false, std::nullopt);
424 Abbrev->getAttributeOffsetFromIndex(*LocationIdx, DIE.getOffset(), *U);
427 std::optional<DWARFFormValue> LocationValue =
428 Abbrev->getAttributeValueFromOffset(*LocationIdx, AttrOffset, *U);
430 return std::make_pair(
false, std::nullopt);
435 std::optional<ArrayRef<uint8_t>> Expr = LocationValue->getAsBlock();
437 return std::make_pair(
false, std::nullopt);
440 DataExtractor
Data(
toStringRef(*Expr), U->getContext().isLittleEndian(),
441 U->getAddressByteSize());
442 DWARFExpression Expression(
Data, U->getAddressByteSize(),
443 U->getFormParams().Format);
445 bool HasLocationAddress =
false;
447 for (DWARFExpression::iterator It = Expression.begin();
448 It != Expression.end(); ++It) {
449 DWARFExpression::iterator NextIt = It;
452 const DWARFExpression::Operation &
Op = *It;
454 case dwarf::DW_OP_const2u:
455 case dwarf::DW_OP_const4u:
456 case dwarf::DW_OP_const8u:
457 case dwarf::DW_OP_const2s:
458 case dwarf::DW_OP_const4s:
459 case dwarf::DW_OP_const8s:
463 case dwarf::DW_OP_addr: {
464 HasLocationAddress =
true;
466 if (std::optional<int64_t> RelocAdjustment =
467 RelocMgr.getExprOpAddressRelocAdjustment(
468 *U,
Op, AttrOffset + CurExprOffset,
470 return std::make_pair(HasLocationAddress, *RelocAdjustment);
472 case dwarf::DW_OP_constx:
473 case dwarf::DW_OP_addrx: {
474 HasLocationAddress =
true;
475 if (std::optional<uint64_t> AddressOffset =
476 DIE.getDwarfUnit()->getIndexedAddressOffset(
479 if (std::optional<int64_t> RelocAdjustment =
480 RelocMgr.getExprOpAddressRelocAdjustment(
481 *U,
Op, *AddressOffset,
482 *AddressOffset + DIE.getDwarfUnit()->getAddressByteSize(),
484 return std::make_pair(HasLocationAddress, *RelocAdjustment);
494 return std::make_pair(HasLocationAddress, std::nullopt);
499unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr,
501 CompileUnit::DIEInfo &MyInfo,
503 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
506 if (!(Flags & TF_InFunctionScope) &&
507 Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
508 MyInfo.InDebugMap =
true;
509 return Flags | TF_Keep;
517 std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
518 getVariableRelocAdjustment(RelocMgr, DIE);
520 if (LocExprAddrAndRelocAdjustment.first)
521 MyInfo.HasLocationExpressionAddr =
true;
523 if (!LocExprAddrAndRelocAdjustment.second)
526 MyInfo.AddrAdjust = *LocExprAddrAndRelocAdjustment.second;
527 MyInfo.InDebugMap =
true;
529 if (((Flags & TF_InFunctionScope) &&
533 if (Options.Verbose) {
534 outs() <<
"Keeping variable DIE:";
535 DIDumpOptions DumpOpts;
536 DumpOpts.ChildRecurseDepth = 0;
537 DumpOpts.Verbose = Options.Verbose;
538 DIE.dump(
outs(), 8 , DumpOpts);
541 return Flags | TF_Keep;
546unsigned DWARFLinker::shouldKeepSubprogramDIE(
547 AddressesMap &RelocMgr,
const DWARFDie &DIE,
const DWARFFile &File,
548 CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
unsigned Flags) {
549 Flags |= TF_InFunctionScope;
555 assert(LowPc &&
"low_pc attribute is not an address.");
556 std::optional<int64_t> RelocAdjustment =
557 RelocMgr.getSubprogramRelocAdjustment(DIE, Options.Verbose);
558 if (!RelocAdjustment)
561 MyInfo.AddrAdjust = *RelocAdjustment;
562 MyInfo.InDebugMap =
true;
564 if (Options.Verbose) {
565 outs() <<
"Keeping subprogram DIE:";
566 DIDumpOptions DumpOpts;
567 DumpOpts.ChildRecurseDepth = 0;
568 DumpOpts.Verbose = Options.Verbose;
569 DIE.dump(
outs(), 8 , DumpOpts);
572 if (DIE.getTag() == dwarf::DW_TAG_label) {
573 if (Unit.hasLabelAt(*LowPc))
576 DWARFUnit &OrigUnit = Unit.getOrigUnit();
584 Unit.addLabelLowPc(*LowPc, MyInfo.AddrAdjust);
585 return Flags | TF_Keep;
590 std::optional<uint64_t> HighPc = DIE.getHighPC(*LowPc);
592 reportWarning(
"Function without high_pc. Range will be discarded.\n", File,
596 if (*LowPc > *HighPc) {
597 reportWarning(
"low_pc greater than high_pc. Range will be discarded.\n",
603 Unit.addFunctionRange(*LowPc, *HighPc, MyInfo.AddrAdjust);
609unsigned DWARFLinker::shouldKeepDIE(AddressesMap &RelocMgr,
const DWARFDie &DIE,
610 const DWARFFile &File, CompileUnit &Unit,
611 CompileUnit::DIEInfo &MyInfo,
613 switch (DIE.getTag()) {
614 case dwarf::DW_TAG_constant:
615 case dwarf::DW_TAG_variable:
616 return shouldKeepVariableDIE(RelocMgr, DIE, MyInfo, Flags);
617 case dwarf::DW_TAG_subprogram:
618 case dwarf::DW_TAG_label:
619 return shouldKeepSubprogramDIE(RelocMgr, DIE, File, Unit, MyInfo, Flags);
620 case dwarf::DW_TAG_base_type:
623 case dwarf::DW_TAG_imported_module:
624 case dwarf::DW_TAG_imported_declaration:
625 case dwarf::DW_TAG_imported_unit:
627 return Flags | TF_Keep;
641 case dwarf::DW_TAG_structure_type:
642 case dwarf::DW_TAG_class_type:
643 case dwarf::DW_TAG_union_type:
661 case dwarf::DW_TAG_typedef:
662 case dwarf::DW_TAG_member:
663 case dwarf::DW_TAG_reference_type:
664 case dwarf::DW_TAG_ptr_to_member_type:
665 case dwarf::DW_TAG_pointer_type:
682void DWARFLinker::lookForChildDIEsToKeep(
683 const DWARFDie &Die, CompileUnit &
CU,
unsigned Flags,
684 SmallVectorImpl<WorklistItem> &Worklist) {
691 Flags &= ~DWARFLinker::TF_ParentWalk;
695 if (!Die.hasChildren() || (Flags & DWARFLinker::TF_ParentWalk))
700 for (
auto Child :
reverse(Die.children())) {
703 CompileUnit::DIEInfo &ChildInfo =
CU.getInfo(Child);
704 Worklist.emplace_back(Die,
CU, WorklistItemType::UpdateChildIncompleteness,
706 Worklist.emplace_back(Child,
CU, Flags);
713 if (!
Info.Ctxt || (Die.
getTag() == dwarf::DW_TAG_namespace))
716 if (!
CU.hasODR() && !
Info.InModuleScope)
719 return !
Info.Incomplete &&
Info.Ctxt !=
CU.getInfo(
Info.ParentIdx).Ctxt;
722void DWARFLinker::markODRCanonicalDie(
const DWARFDie &Die, CompileUnit &
CU) {
723 CompileUnit::DIEInfo &
Info =
CU.getInfo(Die);
725 Info.ODRMarkingDone =
true;
727 !
Info.Ctxt->hasCanonicalDIE())
728 Info.Ctxt->setHasCanonicalDIE();
733void DWARFLinker::lookForRefDIEsToKeep(
734 const DWARFDie &Die, CompileUnit &
CU,
unsigned Flags,
735 const UnitListTy &Units,
const DWARFFile &File,
736 SmallVectorImpl<WorklistItem> &Worklist) {
737 bool UseOdr = (
Flags & DWARFLinker::TF_DependencyWalk)
738 ? (Flags & DWARFLinker::TF_ODR)
740 DWARFUnit &Unit =
CU.getOrigUnit();
741 DWARFDataExtractor
Data = Unit.getDebugInfoExtractor();
742 const auto *Abbrev = Die.getAbbreviationDeclarationPtr();
745 SmallVector<std::pair<DWARFDie, CompileUnit &>, 4> ReferencedDIEs;
746 for (
const auto &AttrSpec : Abbrev->attributes()) {
747 DWARFFormValue Val(AttrSpec.Form);
749 AttrSpec.Attr == dwarf::DW_AT_sibling) {
751 Unit.getFormParams());
755 Val.extractValue(
Data, &
Offset, Unit.getFormParams(), &Unit);
756 CompileUnit *ReferencedCU;
758 resolveDIEReference(File, Units, Val, Die, ReferencedCU)) {
759 CompileUnit::DIEInfo &
Info = ReferencedCU->getInfo(RefDie);
770 if (AttrSpec.Form != dwarf::DW_FORM_ref_addr &&
772 Info.Ctxt->hasCanonicalDIE())
777 Info.Ctxt->hasCanonicalDIE()))
779 ReferencedDIEs.emplace_back(RefDie, *ReferencedCU);
783 unsigned ODRFlag = UseOdr ? DWARFLinker::TF_ODR : 0;
787 for (
auto &
P :
reverse(ReferencedDIEs)) {
790 CompileUnit::DIEInfo &
Info =
P.second.getInfo(
P.first);
791 Worklist.emplace_back(Die,
CU, WorklistItemType::UpdateRefIncompleteness,
793 Worklist.emplace_back(
P.first,
P.second,
794 DWARFLinker::TF_Keep |
795 DWARFLinker::TF_DependencyWalk | ODRFlag);
800void DWARFLinker::lookForParentDIEsToKeep(
801 unsigned AncestorIdx, CompileUnit &
CU,
unsigned Flags,
802 SmallVectorImpl<WorklistItem> &Worklist) {
804 if (
CU.getInfo(AncestorIdx).Keep)
807 DWARFUnit &Unit =
CU.getOrigUnit();
808 DWARFDie ParentDIE = Unit.getDIEAtIndex(AncestorIdx);
809 Worklist.emplace_back(
CU.getInfo(AncestorIdx).ParentIdx,
CU, Flags);
810 Worklist.emplace_back(ParentDIE,
CU, Flags);
838void DWARFLinker::lookForDIEsToKeep(AddressesMap &AddressesMap,
840 const DWARFDie &Die,
const DWARFFile &File,
841 CompileUnit &Cu,
unsigned Flags) {
843 SmallVector<WorklistItem, 4> Worklist;
844 Worklist.emplace_back(Die, Cu, Flags);
846 while (!Worklist.empty()) {
847 WorklistItem Current = Worklist.pop_back_val();
850 switch (Current.Type) {
851 case WorklistItemType::UpdateChildIncompleteness:
854 case WorklistItemType::UpdateRefIncompleteness:
857 case WorklistItemType::LookForChildDIEsToKeep:
858 lookForChildDIEsToKeep(Current.Die, Current.CU, Current.Flags, Worklist);
860 case WorklistItemType::LookForRefDIEsToKeep:
861 lookForRefDIEsToKeep(Current.Die, Current.CU, Current.Flags, Units, File,
864 case WorklistItemType::LookForParentDIEsToKeep:
865 lookForParentDIEsToKeep(Current.AncestorIdx, Current.CU, Current.Flags,
868 case WorklistItemType::MarkODRCanonicalDie:
869 markODRCanonicalDie(Current.Die, Current.CU);
871 case WorklistItemType::LookForDIEsToKeep:
875 unsigned Idx = Current.CU.getOrigUnit().getDIEIndex(Current.Die);
876 CompileUnit::DIEInfo &MyInfo = Current.CU.getInfo(
Idx);
881 if (Current.Flags & TF_DependencyWalk)
882 MyInfo.Prune =
false;
889 bool AlreadyKept = MyInfo.Keep;
890 if ((Current.Flags & TF_DependencyWalk) && AlreadyKept)
893 if (!(Current.Flags & TF_DependencyWalk))
894 Current.Flags = shouldKeepDIE(AddressesMap, Current.Die, File, Current.CU,
895 MyInfo, Current.Flags);
900 if (!(Current.Flags & TF_DependencyWalk) ||
901 (MyInfo.ODRMarkingDone && !MyInfo.Keep)) {
902 if (Current.CU.hasODR() || MyInfo.InModuleScope)
903 Worklist.emplace_back(Current.Die, Current.CU,
904 WorklistItemType::MarkODRCanonicalDie);
910 Worklist.emplace_back(Current.Die, Current.CU, Current.Flags,
911 WorklistItemType::LookForChildDIEsToKeep);
913 if (AlreadyKept || !(Current.Flags & TF_Keep))
922 Current.Die.getTag() != dwarf::DW_TAG_subprogram &&
923 Current.Die.getTag() != dwarf::DW_TAG_member &&
929 Worklist.emplace_back(Current.Die, Current.CU, Current.Flags,
930 WorklistItemType::LookForRefDIEsToKeep);
932 bool UseOdr = (Current.Flags & TF_DependencyWalk) ? (Current.Flags & TF_ODR)
933 : Current.CU.hasODR();
934 unsigned ODRFlag = UseOdr ? TF_ODR : 0;
935 unsigned ParFlags = TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag;
938 Worklist.emplace_back(MyInfo.ParentIdx, Current.CU, ParFlags);
954 std::vector<DWARFDie> Worklist;
955 Worklist.push_back(
CU.getOrigUnit().getUnitDIE());
958 std::vector<BrokenLink> BrokenLinks;
960 while (!Worklist.empty()) {
961 const DWARFDie Current = Worklist.back();
964 const bool CurrentDieIsKept =
CU.getInfo(Current).Keep;
967 Worklist.push_back(Child);
969 const bool ChildDieIsKept =
CU.getInfo(Child).Keep;
970 if (!CurrentDieIsKept && ChildDieIsKept)
971 BrokenLinks.emplace_back(Current, Child);
975 if (!BrokenLinks.empty()) {
978 "Found invalid link in keep chain between {0:x} and {1:x}\n",
979 Link.Parent.getOffset(), Link.Child.getOffset());
982 Link.Parent.dump(
errs(), 0, {});
983 CU.getInfo(Link.Parent).dump();
986 Link.Child.dump(
errs(), 2, {});
987 CU.getInfo(Link.Child).dump();
1000void DWARFLinker::assignAbbrev(DIEAbbrev &Abbrev) {
1002 FoldingSetNodeID
ID;
1005 DIEAbbrev *InSet = AbbreviationsSet.FindNodeOrInsertPos(
ID, InsertToken);
1010 Abbrev.setNumber(InSet->getNumber());
1013 Abbreviations.push_back(
1014 std::make_unique<DIEAbbrev>(Abbrev.getTag(), Abbrev.hasChildren()));
1015 for (
const auto &Attr : Abbrev.getData())
1016 Abbreviations.back()->AddAttribute(Attr);
1017 AbbreviationsSet.InsertNode(Abbreviations.back().get(), InsertToken);
1019 Abbrev.setNumber(Abbreviations.size());
1020 Abbreviations.back()->setNumber(Abbreviations.size());
1024unsigned DWARFLinker::DIECloner::cloneStringAttribute(DIE &Die,
1025 AttributeSpec AttrSpec,
1026 const DWARFFormValue &Val,
1028 AttributesInfo &
Info) {
1033 if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
1038 if (AttrSpec.Attr == dwarf::DW_AT_APPLE_origin) {
1039 Info.HasAppleOrigin =
true;
1040 if (std::optional<StringRef> FileName =
1041 ObjFile.Addresses->getLibraryInstallName()) {
1047 if (AttrSpec.Attr == dwarf::DW_AT_name)
1049 else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name ||
1050 AttrSpec.Attr == dwarf::DW_AT_linkage_name)
1052 if (
U.getVersion() >= 5) {
1054 auto StringOffsetIndex =
1055 StringOffsetPool.getValueIndex(
StringEntry.getOffset());
1058 dwarf::DW_FORM_strx, DIEInteger(StringOffsetIndex))
1059 ->sizeOf(
U.getFormParams());
1062 AttrSpec.Form = dwarf::DW_FORM_strp;
1069unsigned DWARFLinker::DIECloner::cloneDieReferenceAttribute(
1070 DIE &Die,
const DWARFDie &InputDIE, AttributeSpec AttrSpec,
1071 unsigned AttrSize,
const DWARFFormValue &Val,
const DWARFFile &File,
1072 CompileUnit &Unit) {
1073 const DWARFUnit &
U = Unit.getOrigUnit();
1076 DIE *NewRefDie =
nullptr;
1077 CompileUnit *RefUnit =
nullptr;
1080 Linker.resolveDIEReference(File, CompileUnits, Val, InputDIE, RefUnit);
1083 if (!RefDie || AttrSpec.Attr == dwarf::DW_AT_sibling)
1086 CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(RefDie);
1091 RefInfo.Ctxt->getCanonicalDIEOffset()) {
1092 assert(RefInfo.Ctxt->hasCanonicalDIE() &&
1093 "Offset to canonical die is set, but context is not marked");
1094 DIEInteger Attr(RefInfo.Ctxt->getCanonicalDIEOffset());
1096 dwarf::DW_FORM_ref_addr, Attr);
1097 return U.getRefAddrByteSize();
1100 if (!RefInfo.Clone) {
1103 RefInfo.UnclonedReference =
true;
1106 NewRefDie = RefInfo.Clone;
1108 if (AttrSpec.Form == dwarf::DW_FORM_ref_addr ||
1116 if (
Ref < InputDIE.getOffset() && !RefInfo.UnclonedReference) {
1119 RefUnit->getStartOffset() + NewRefDie->getOffset();
1120 Attr = NewRefOffset;
1122 dwarf::DW_FORM_ref_addr, DIEInteger(Attr));
1126 Unit.noteForwardReference(
1127 NewRefDie, RefUnit, RefInfo.Ctxt,
1129 dwarf::DW_FORM_ref_addr, DIEInteger(Attr)));
1131 return U.getRefAddrByteSize();
1135 dwarf::Form(AttrSpec.Form), DIEEntry(*NewRefDie));
1140void DWARFLinker::DIECloner::cloneExpression(
1141 DataExtractor &
Data, DWARFExpression Expression,
const DWARFFile &File,
1142 CompileUnit &Unit, SmallVectorImpl<uint8_t> &
OutputBuffer,
1143 int64_t AddrRelocAdjustment,
bool IsLittleEndian) {
1146 uint8_t OrigAddressByteSize = Unit.getOrigUnit().getAddressByteSize();
1149 for (
auto &
Op : Expression) {
1155 Desc.
Op[0] != Encoding::Size1))
1156 Linker.reportWarning(
"Unsupported DW_OP encoding.", File);
1160 Desc.
Op[0] == Encoding::Size1)) {
1180 if (RefOffset > 0 ||
Op.
getCode() != dwarf::DW_OP_convert) {
1181 RefOffset += Unit.getOrigUnit().getOffset();
1182 auto RefDie = Unit.getOrigUnit().getDIEForOffset(RefOffset);
1183 CompileUnit::DIEInfo &
Info = Unit.getInfo(RefDie);
1184 if (DIE *Clone =
Info.Clone)
1185 Offset = Clone->getOffset();
1187 Linker.reportWarning(
1188 "base type ref doesn't point to DW_TAG_base_type.", File);
1192 if (RealSize > ULEBsize) {
1195 Linker.reportWarning(
"base type ref doesn't fit.", File);
1197 assert(RealSize == ULEBsize &&
"padding failed");
1198 ArrayRef<uint8_t> ULEBbytes(ULEB, ULEBsize);
1199 OutputBuffer.append(ULEBbytes.begin(), ULEBbytes.end());
1200 }
else if (!Linker.Options.Update &&
Op.
getCode() == dwarf::DW_OP_addrx) {
1201 if (std::optional<object::SectionedAddress> SA =
1202 Unit.getOrigUnit().getAddrOffsetSectionItem(
1209 uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment;
1212 ArrayRef<uint8_t> AddressBytes(
1213 reinterpret_cast<const uint8_t *
>(&LinkedAddress),
1214 OrigAddressByteSize);
1215 OutputBuffer.append(AddressBytes.begin(), AddressBytes.end());
1217 Linker.reportWarning(
"cannot read DW_OP_addrx operand.", File);
1218 }
else if (!Linker.Options.Update &&
Op.
getCode() == dwarf::DW_OP_constx) {
1219 if (std::optional<object::SectionedAddress> SA =
1220 Unit.getOrigUnit().getAddrOffsetSectionItem(
1226 std::optional<uint8_t> OutOperandKind;
1227 switch (OrigAddressByteSize) {
1229 OutOperandKind = dwarf::DW_OP_const4u;
1232 OutOperandKind = dwarf::DW_OP_const8u;
1235 Linker.reportWarning(
1236 formatv((
"unsupported address size: {0}."), OrigAddressByteSize),
1241 if (OutOperandKind) {
1243 uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment;
1246 ArrayRef<uint8_t> AddressBytes(
1247 reinterpret_cast<const uint8_t *
>(&LinkedAddress),
1248 OrigAddressByteSize);
1249 OutputBuffer.append(AddressBytes.begin(), AddressBytes.end());
1252 Linker.reportWarning(
"cannot read DW_OP_constx operand.", File);
1262unsigned DWARFLinker::DIECloner::cloneBlockAttribute(
1263 DIE &Die,
const DWARFDie &InputDIE,
const DWARFFile &File,
1264 CompileUnit &Unit, AttributeSpec AttrSpec,
const DWARFFormValue &Val,
1265 bool IsLittleEndian) {
1268 DIELoc *Loc =
nullptr;
1269 DIEBlock *
Block =
nullptr;
1270 if (AttrSpec.Form == dwarf::DW_FORM_exprloc) {
1271 Loc =
new (DIEAlloc) DIELoc;
1272 Linker.DIELocs.push_back(Loc);
1274 Block =
new (DIEAlloc) DIEBlock;
1275 Linker.DIEBlocks.push_back(
Block);
1277 Attr = Loc ?
static_cast<DIEValueList *
>(Loc)
1278 :
static_cast<DIEValueList *
>(
Block);
1280 DWARFUnit &OrigUnit = Unit.getOrigUnit();
1283 SmallVector<uint8_t, 32> Buffer;
1284 ArrayRef<uint8_t> Bytes = *Val.getAsBlock();
1288 DataExtractor
Data(StringRef((
const char *)Bytes.data(), Bytes.size()),
1289 IsLittleEndian, OrigUnit.getAddressByteSize());
1290 DWARFExpression Expr(
Data, OrigUnit.getAddressByteSize(),
1291 OrigUnit.getFormParams().Format);
1292 cloneExpression(
Data, Expr, File, Unit, Buffer,
1293 Unit.getInfo(InputDIE).AddrAdjust, IsLittleEndian);
1296 for (
auto Byte : Bytes)
1298 dwarf::DW_FORM_data1, DIEInteger(Byte));
1304 Loc->setSize(Bytes.size());
1306 Block->setSize(Bytes.size());
1314 if ((AttrSpec.Form == dwarf::DW_FORM_block1 &&
1315 (Bytes.size() > UINT8_MAX)) ||
1316 (AttrSpec.Form == dwarf::DW_FORM_block2 &&
1317 (Bytes.size() > UINT16_MAX)) ||
1318 (AttrSpec.Form == dwarf::DW_FORM_block4 && (Bytes.size() > UINT32_MAX)))
1319 AttrSpec.Form = dwarf::DW_FORM_block;
1325 return Die.addValue(DIEAlloc, Value)->sizeOf(OrigUnit.getFormParams());
1328unsigned DWARFLinker::DIECloner::cloneAddressAttribute(
1329 DIE &Die,
const DWARFDie &InputDIE, AttributeSpec AttrSpec,
1330 unsigned AttrSize,
const DWARFFormValue &Val,
const CompileUnit &Unit,
1331 AttributesInfo &
Info) {
1332 if (AttrSpec.Attr == dwarf::DW_AT_low_pc)
1333 Info.HasLowPc =
true;
1337 dwarf::Form(AttrSpec.Form), DIEInteger(Val.getRawUValue()));
1353 std::optional<DWARFFormValue> AddrAttribute = InputDIE.find(AttrSpec.Attr);
1357 std::optional<uint64_t>
Addr = AddrAttribute->getAsAddress();
1359 Linker.reportWarning(
"Cann't read address attribute value.", ObjFile);
1363 if (InputDIE.getTag() == dwarf::DW_TAG_compile_unit &&
1364 AttrSpec.Attr == dwarf::DW_AT_low_pc) {
1365 if (std::optional<uint64_t> LowPC = Unit.getLowPc())
1369 }
else if (InputDIE.getTag() == dwarf::DW_TAG_compile_unit &&
1370 AttrSpec.Attr == dwarf::DW_AT_high_pc) {
1371 if (
uint64_t HighPc = Unit.getHighPc())
1379 if (AttrSpec.Form == dwarf::DW_FORM_addr) {
1381 AttrSpec.Form, DIEInteger(*
Addr));
1382 return Unit.getOrigUnit().getAddressByteSize();
1385 auto AddrIndex = AddrPool.getValueIndex(*
Addr);
1389 dwarf::Form::DW_FORM_addrx, DIEInteger(AddrIndex))
1390 ->sizeOf(Unit.getOrigUnit().getFormParams());
1393unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
1394 DIE &Die,
const DWARFDie &InputDIE,
const DWARFFile &File,
1395 CompileUnit &Unit, AttributeSpec AttrSpec,
const DWARFFormValue &Val,
1396 unsigned AttrSize, AttributesInfo &
Info) {
1401 if (AttrSpec.Attr == dwarf::DW_AT_macro_info) {
1402 if (std::optional<uint64_t>
Offset = Val.getAsSectionOffset()) {
1409 if (AttrSpec.Attr == dwarf::DW_AT_macros) {
1410 if (std::optional<uint64_t>
Offset = Val.getAsSectionOffset()) {
1417 if (AttrSpec.Attr == dwarf::DW_AT_str_offsets_base) {
1421 Info.AttrStrOffsetBaseSeen =
true;
1423 .addValue(DIEAlloc, dwarf::DW_AT_str_offsets_base,
1424 dwarf::DW_FORM_sec_offset, DIEInteger(8))
1425 ->sizeOf(Unit.getOrigUnit().getFormParams());
1429 if (
auto OptionalValue = Val.getAsUnsignedConstant())
1430 Value = *OptionalValue;
1431 else if (
auto OptionalValue = Val.getAsSignedConstant())
1432 Value = *OptionalValue;
1433 else if (
auto OptionalValue = Val.getAsSectionOffset())
1434 Value = *OptionalValue;
1436 Linker.reportWarning(
1437 "Unsupported scalar attribute form. Dropping attribute.", File,
1441 if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
1442 Info.IsDeclaration =
true;
1444 if (AttrSpec.Form == dwarf::DW_FORM_loclistx)
1453 [[maybe_unused]]
dwarf::Form OriginalForm = AttrSpec.Form;
1454 if (AttrSpec.Form == dwarf::DW_FORM_rnglistx) {
1458 std::optional<uint64_t>
Index = Val.getAsSectionOffset();
1460 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1464 std::optional<uint64_t>
Offset =
1465 Unit.getOrigUnit().getRnglistOffset(*
Index);
1467 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1473 AttrSpec.Form = dwarf::DW_FORM_sec_offset;
1474 AttrSize = Unit.getOrigUnit().getFormParams().getDwarfOffsetByteSize();
1475 }
else if (AttrSpec.Form == dwarf::DW_FORM_loclistx) {
1479 std::optional<uint64_t>
Index = Val.getAsSectionOffset();
1481 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1485 std::optional<uint64_t>
Offset =
1486 Unit.getOrigUnit().getLoclistOffset(*
Index);
1488 Linker.reportWarning(
"Cannot read the attribute. Dropping.", File,
1494 AttrSpec.Form = dwarf::DW_FORM_sec_offset;
1495 AttrSize = Unit.getOrigUnit().getFormParams().getDwarfOffsetByteSize();
1496 }
else if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
1497 Die.getTag() == dwarf::DW_TAG_compile_unit) {
1498 std::optional<uint64_t> LowPC = Unit.getLowPc();
1502 Value = Unit.getHighPc() - *LowPC;
1503 }
else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)
1504 Value = *Val.getAsSectionOffset();
1505 else if (AttrSpec.Form == dwarf::DW_FORM_sdata)
1506 Value = *Val.getAsSignedConstant();
1507 else if (
auto OptionalValue = Val.getAsUnsignedConstant())
1508 Value = *OptionalValue;
1510 Linker.reportWarning(
1511 "Unsupported scalar attribute form. Dropping attribute.", File,
1516 DIE::value_iterator Patch =
1519 if (AttrSpec.Attr == dwarf::DW_AT_ranges ||
1520 AttrSpec.Attr == dwarf::DW_AT_start_scope) {
1521 Unit.noteRangeAttribute(Die, Patch);
1522 Info.HasRanges =
true;
1526 Unit.getOrigUnit().getVersion())) {
1528 CompileUnit::DIEInfo &LocationDieInfo = Unit.getInfo(InputDIE);
1529 Unit.noteLocationAttribute({Patch, LocationDieInfo.InDebugMap
1530 ? LocationDieInfo.AddrAdjust
1532 }
else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
1533 Info.IsDeclaration =
true;
1536 assert((
Info.HasRanges || (OriginalForm != dwarf::DW_FORM_rnglistx)) &&
1537 "Unhandled DW_FORM_rnglistx attribute");
1545unsigned DWARFLinker::DIECloner::cloneAttribute(
1546 DIE &Die,
const DWARFDie &InputDIE,
const DWARFFile &File,
1547 CompileUnit &Unit,
const DWARFFormValue &Val,
const AttributeSpec AttrSpec,
1548 unsigned AttrSize, AttributesInfo &
Info,
bool IsLittleEndian) {
1549 const DWARFUnit &
U = Unit.getOrigUnit();
1551 switch (AttrSpec.Form) {
1552 case dwarf::DW_FORM_strp:
1553 case dwarf::DW_FORM_line_strp:
1554 case dwarf::DW_FORM_string:
1555 case dwarf::DW_FORM_strx:
1556 case dwarf::DW_FORM_strx1:
1557 case dwarf::DW_FORM_strx2:
1558 case dwarf::DW_FORM_strx3:
1559 case dwarf::DW_FORM_strx4:
1560 return cloneStringAttribute(Die, AttrSpec, Val, U,
Info);
1561 case dwarf::DW_FORM_ref_addr:
1562 case dwarf::DW_FORM_ref1:
1563 case dwarf::DW_FORM_ref2:
1564 case dwarf::DW_FORM_ref4:
1565 case dwarf::DW_FORM_ref8:
1566 return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val,
1568 case dwarf::DW_FORM_block:
1569 case dwarf::DW_FORM_block1:
1570 case dwarf::DW_FORM_block2:
1571 case dwarf::DW_FORM_block4:
1572 case dwarf::DW_FORM_exprloc:
1573 return cloneBlockAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,
1575 case dwarf::DW_FORM_addr:
1576 case dwarf::DW_FORM_addrx:
1577 case dwarf::DW_FORM_addrx1:
1578 case dwarf::DW_FORM_addrx2:
1579 case dwarf::DW_FORM_addrx3:
1580 case dwarf::DW_FORM_addrx4:
1581 return cloneAddressAttribute(Die, InputDIE, AttrSpec, AttrSize, Val, Unit,
1583 case dwarf::DW_FORM_data1:
1584 case dwarf::DW_FORM_data2:
1585 case dwarf::DW_FORM_data4:
1586 case dwarf::DW_FORM_data8:
1587 case dwarf::DW_FORM_udata:
1588 case dwarf::DW_FORM_sdata:
1589 case dwarf::DW_FORM_sec_offset:
1590 case dwarf::DW_FORM_flag:
1591 case dwarf::DW_FORM_flag_present:
1592 case dwarf::DW_FORM_rnglistx:
1593 case dwarf::DW_FORM_loclistx:
1594 case dwarf::DW_FORM_implicit_const:
1595 return cloneScalarAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,
1598 Linker.reportWarning(
"Unsupported attribute form " +
1600 " in cloneAttribute. Dropping.",
1607void DWARFLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit,
1609 DwarfStringPoolEntryRef
Name,
1611 bool SkipPubSection) {
1612 std::optional<ObjCSelectorNames> Names =
1616 Unit.addNameAccelerator(Die, StringPool.getEntry(Names->Selector),
1618 Unit.addObjCAccelerator(Die, StringPool.getEntry(Names->ClassName),
1620 if (Names->ClassNameNoCategory)
1621 Unit.addObjCAccelerator(
1622 Die, StringPool.getEntry(*Names->ClassNameNoCategory), SkipPubSection);
1623 if (Names->MethodNameNoCategory)
1624 Unit.addNameAccelerator(
1625 Die, StringPool.getEntry(*Names->MethodNameNoCategory), SkipPubSection);
1632 switch (AttrSpec.
Attr) {
1635 case dwarf::DW_AT_low_pc:
1636 case dwarf::DW_AT_high_pc:
1637 case dwarf::DW_AT_ranges:
1638 return !Update && SkipPC;
1639 case dwarf::DW_AT_rnglists_base:
1645 case dwarf::DW_AT_loclists_base:
1651 case dwarf::DW_AT_location:
1652 case dwarf::DW_AT_frame_base:
1653 return !Update && SkipPC;
1663DIE *DWARFLinker::DIECloner::cloneDIE(
const DWARFDie &InputDIE,
1665 int64_t PCOffset,
uint32_t OutOffset,
1666 unsigned Flags,
bool IsLittleEndian,
1669 unsigned Idx = U.getDIEIndex(InputDIE);
1673 if (!Unit.getInfo(
Idx).Keep)
1677 assert(!(Die &&
Info.Clone) &&
"Can't supply a DIE and a cloned DIE");
1689 (
Info.Ctxt->getCanonicalDIEOffset() == 0)) {
1690 if (!
Info.Ctxt->hasCanonicalDIE())
1691 Info.Ctxt->setHasCanonicalDIE();
1695 Info.Ctxt->setCanonicalDIEOffset(OutOffset + Unit.getStartOffset());
1699 DWARFDataExtractor
Data =
U.getDebugInfoExtractor();
1704 ?
U.getDIEAtIndex(
Idx + 1).getOffset()
1705 :
U.getNextUnitOffset();
1706 AttributesInfo AttrInfo;
1711 SmallString<40> DIECopy(
Data.getData().substr(
Offset, NextOffset -
Offset));
1713 DWARFDataExtractor(DIECopy,
Data.isLittleEndian(),
Data.getAddressSize());
1716 ObjFile.Addresses->applyValidRelocs(DIECopy,
Offset,
Data.isLittleEndian());
1726 if (Die->
getTag() == dwarf::DW_TAG_subprogram)
1727 PCOffset =
Info.AddrAdjust;
1728 AttrInfo.PCOffset = PCOffset;
1730 if (Abbrev->getTag() == dwarf::DW_TAG_subprogram) {
1731 Flags |= TF_InFunctionScope;
1734 }
else if (Abbrev->getTag() == dwarf::DW_TAG_variable) {
1737 if ((Flags & TF_InFunctionScope) &&
Info.InDebugMap)
1738 Flags &= ~TF_SkipPC;
1741 else if (!
Info.InDebugMap &&
Info.HasLocationExpressionAddr &&
1746 std::optional<StringRef> LibraryInstallName =
1747 ObjFile.Addresses->getLibraryInstallName();
1748 SmallVector<AttributeLinkedOffsetFixup> AttributesFixups;
1749 for (
const auto &AttrSpec : Abbrev->attributes()) {
1756 AttributeLinkedOffsetFixup CurAttrFixup;
1758 CurAttrFixup.LinkedOffsetFixupVal =
1759 Unit.getStartOffset() + OutOffset - CurAttrFixup.InputAttrStartOffset;
1761 DWARFFormValue Val = AttrSpec.getFormValue();
1763 Val.extractValue(
Data, &
Offset,
U.getFormParams(), &U);
1765 AttrSize =
Offset - AttrSize;
1768 cloneAttribute(*Die, InputDIE, File, Unit, Val, AttrSpec, AttrSize,
1769 AttrInfo, IsLittleEndian);
1770 if (FinalAttrSize != 0 && ObjFile.Addresses->needToSaveValidRelocs())
1771 AttributesFixups.push_back(CurAttrFixup);
1773 OutOffset += FinalAttrSize;
1779 const bool NeedsAppleOrigin = (
Tag == dwarf::DW_TAG_compile_unit) &&
1780 LibraryInstallName.has_value() &&
1781 !AttrInfo.HasAppleOrigin;
1782 if (NeedsAppleOrigin) {
1783 auto StringEntry = DebugStrPool.getEntry(LibraryInstallName.value());
1785 dwarf::DW_FORM_strp, DIEInteger(
StringEntry.getOffset()));
1794 if ((
Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&
1795 Tag != dwarf::DW_TAG_compile_unit &&
1796 getDIENames(InputDIE, AttrInfo, DebugStrPool,
1797 Tag != dwarf::DW_TAG_inlined_subroutine)) {
1798 if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
1799 Unit.addNameAccelerator(Die, AttrInfo.MangledName,
1800 Tag == dwarf::DW_TAG_inlined_subroutine);
1801 if (AttrInfo.Name) {
1802 if (AttrInfo.NameWithoutTemplate)
1803 Unit.addNameAccelerator(Die, AttrInfo.NameWithoutTemplate,
1805 Unit.addNameAccelerator(Die, AttrInfo.Name,
1806 Tag == dwarf::DW_TAG_inlined_subroutine);
1809 addObjCAccelerator(Unit, Die, AttrInfo.Name, DebugStrPool,
1812 }
else if (
Tag == dwarf::DW_TAG_namespace) {
1814 AttrInfo.Name = DebugStrPool.getEntry(
"(anonymous namespace)");
1815 Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
1816 }
else if (
Tag == dwarf::DW_TAG_imported_declaration && AttrInfo.Name) {
1817 Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
1818 }
else if (
isTypeTag(
Tag) && !AttrInfo.IsDeclaration &&
1819 getDIENames(InputDIE, AttrInfo, DebugStrPool) && AttrInfo.Name &&
1820 AttrInfo.Name.getString()[0]) {
1825 bool ObjCClassIsImplementation =
1826 (RuntimeLang == dwarf::DW_LANG_ObjC ||
1827 RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
1830 Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation,
1835 bool HasChildren =
false;
1836 for (
auto Child : InputDIE.
children()) {
1837 unsigned Idx =
U.getDIEIndex(Child);
1838 if (Unit.getInfo(
Idx).Keep) {
1844 if (Unit.getOrigUnit().getVersion() >= 5 && !AttrInfo.AttrStrOffsetBaseSeen &&
1845 Die->
getTag() == dwarf::DW_TAG_compile_unit) {
1847 Die->
addValue(DIEAlloc, dwarf::DW_AT_str_offsets_base,
1848 dwarf::DW_FORM_sec_offset, DIEInteger(8));
1856 Linker.assignAbbrev(NewAbbrev);
1862 OutOffset += AbbrevNumberSize;
1865 for (AttributeLinkedOffsetFixup &
F : AttributesFixups)
1866 F.LinkedOffsetFixupVal += AbbrevNumberSize;
1868 for (AttributeLinkedOffsetFixup &
F : AttributesFixups)
1869 ObjFile.Addresses->updateAndSaveValidRelocs(
1870 Unit.getOrigUnit().getVersion() >= 5, Unit.getOrigUnit().getOffset(),
1871 F.LinkedOffsetFixupVal,
F.InputAttrStartOffset,
F.InputAttrEndOffset);
1880 for (
auto Child : InputDIE.
children()) {
1881 if (DIE *Clone = cloneDIE(Child, File, Unit, PCOffset, OutOffset, Flags,
1884 OutOffset = Clone->getOffset() + Clone->getSize();
1889 OutOffset +=
sizeof(int8_t);
1898void DWARFLinker::generateUnitRanges(CompileUnit &Unit,
const DWARFFile &File,
1903 const auto &FunctionRanges = Unit.getFunctionRanges();
1906 AddressRanges LinkedFunctionRanges;
1907 for (
const AddressRangeValuePair &Range : FunctionRanges)
1908 LinkedFunctionRanges.insert(
1912 if (!LinkedFunctionRanges.empty())
1916 std::optional<PatchLocation> UnitRngListAttribute =
1917 Unit.getUnitRangesAttribute();
1919 if (!AllRngListAttributes.empty() || UnitRngListAttribute) {
1920 std::optional<AddressRangeValuePair> CachedRange;
1925 for (PatchLocation &AttributePatch : AllRngListAttributes) {
1928 AddressRanges LinkedRanges;
1929 if (Expected<DWARFAddressRangesVector> OriginalRanges =
1930 Unit.getOrigUnit().findRnglistFromOffset(AttributePatch.get())) {
1932 for (
const auto &Range : *OriginalRanges) {
1933 if (!CachedRange || !CachedRange->Range.contains(
Range.LowPC))
1934 CachedRange = FunctionRanges.getRangeThatContains(
Range.LowPC);
1938 reportWarning(
"inconsistent range data.", File);
1943 LinkedRanges.insert({
Range.LowPC + CachedRange->Value,
1944 Range.HighPC + CachedRange->Value});
1948 reportWarning(
"invalid range list ignored.", File);
1953 Unit, LinkedRanges, AttributePatch, AddrPool);
1957 if (UnitRngListAttribute.has_value())
1959 Unit, LinkedFunctionRanges, *UnitRngListAttribute, AddrPool);
1966void DWARFLinker::DIECloner::generateUnitLocations(
1967 CompileUnit &Unit,
const DWARFFile &File,
1968 ExpressionHandlerRef ExprHandler) {
1973 Unit.getLocationAttributes();
1975 if (AllLocListAttributes.empty())
1981 for (
auto &CurLocAttr : AllLocListAttributes) {
1984 Expected<DWARFLocationExpressionsVector> OriginalLocations =
1985 Unit.getOrigUnit().findLoclistFromOffset(CurLocAttr.get());
1987 if (!OriginalLocations) {
1989 Linker.reportWarning(
"Invalid location attribute ignored.", File);
1994 for (DWARFLocationExpression &CurExpression : *OriginalLocations) {
1995 DWARFLocationExpression LinkedExpression;
1997 if (CurExpression.Range) {
1999 LinkedExpression.Range = {
2000 CurExpression.Range->LowPC + CurLocAttr.RelocAdjustment,
2001 CurExpression.Range->HighPC + CurLocAttr.RelocAdjustment};
2005 LinkedExpression.Expr.reserve(CurExpression.Expr.size());
2006 ExprHandler(CurExpression.Expr, LinkedExpression.Expr,
2007 CurLocAttr.RelocAdjustment);
2009 LinkedLocationExpressions.push_back(LinkedExpression);
2013 Emitter->emitDwarfDebugLocListFragment(Unit, LinkedLocationExpressions,
2014 CurLocAttr, AddrPool);
2018 Emitter->emitDwarfDebugLocListFooter(Unit, EndLabel);
2022 for (
auto &V : Die.
values())
2023 if (V.getAttribute() == dwarf::DW_AT_addr_base) {
2031void DWARFLinker::DIECloner::emitDebugAddrSection(
2032 CompileUnit &Unit,
const uint16_t DwarfVersion)
const {
2037 if (DwarfVersion < 5)
2040 if (AddrPool.getValues().empty())
2043 MCSymbol *EndLabel =
Emitter->emitDwarfDebugAddrsHeader(Unit);
2045 DIEInteger(
Emitter->getDebugAddrSectionSize()));
2046 Emitter->emitDwarfDebugAddrs(AddrPool.getValues(),
2047 Unit.getOrigUnit().getAddressByteSize());
2048 Emitter->emitDwarfDebugAddrsFooter(Unit, EndLabel);
2054 std::vector<DWARFDebugLine::Row> &Rows) {
2058 if (!Rows.empty() && Rows.back().Address < Seq.front().Address) {
2072 if (InsertPoint != Rows.end() && InsertPoint->Address == Front &&
2073 InsertPoint->EndSequence) {
2074 *InsertPoint = Seq.front();
2075 Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end());
2077 Rows.insert(InsertPoint, Seq.begin(), Seq.end());
2084 for (
auto &V : Die.
values())
2085 if (V.getAttribute() == dwarf::DW_AT_stmt_list) {
2093void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {
2094 DWARFUnit &OrigUnit = Unit.getOrigUnit();
2095 DWARFDie OrigUnitDie = OrigUnit.getUnitDIE();
2097 if (std::optional<uint64_t> MacroAttr =
2099 UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));
2103 if (std::optional<uint64_t> MacroAttr =
2105 UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));
2110void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
2115 DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
2121 if (
auto *OutputDIE = Unit.getOutputUnitDIE())
2124 if (
const DWARFDebugLine::LineTable *LT =
2125 ObjFile.Dwarf->getLineTableForUnit(&Unit.getOrigUnit())) {
2127 DWARFDebugLine::LineTable LineTable;
2130 LineTable.Prologue =
LT->Prologue;
2133 if (Linker.Options.Update) {
2134 LineTable.Rows =
LT->Rows;
2137 if (LineTable.Rows.size() == 1 && LineTable.Rows[0].EndSequence)
2138 LineTable.Rows.clear();
2140 LineTable.Sequences =
LT->Sequences;
2143 std::vector<DWARFDebugLine::Row> NewRows;
2144 NewRows.reserve(
LT->Rows.size());
2148 std::vector<DWARFDebugLine::Row> Seq;
2150 const auto &FunctionRanges = Unit.getFunctionRanges();
2151 std::optional<AddressRangeValuePair> CurrRange;
2164 for (DWARFDebugLine::Row Row :
LT->Rows) {
2170 if (!CurrRange || !CurrRange->Range.contains(Row.Address.Address)) {
2174 CurrRange ? CurrRange->Range.end() + CurrRange->Value : -1ULL;
2175 CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);
2176 if (StopAddress != -1ULL && !Seq.empty()) {
2179 auto NextLine = Seq.back();
2180 NextLine.Address.Address = StopAddress;
2181 NextLine.EndSequence = 1;
2182 NextLine.PrologueEnd = 0;
2183 NextLine.BasicBlock = 0;
2184 NextLine.EpilogueBegin = 0;
2185 Seq.push_back(NextLine);
2194 if (Row.EndSequence && Seq.empty())
2198 Row.Address.Address += CurrRange->Value;
2199 Seq.emplace_back(Row);
2201 if (Row.EndSequence)
2205 LineTable.Rows = std::move(NewRows);
2208 Emitter->emitLineTableForUnit(LineTable, Unit, DebugStrPool,
2211 Linker.reportWarning(
"Cann't load line table.", ObjFile);
2214void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
2219 for (
const auto &Namespace : Unit.getNamespaces())
2220 AppleNamespaces.addName(Namespace.Name, Namespace.Die->getOffset() +
2221 Unit.getStartOffset());
2223 for (
const auto &Pubname : Unit.getPubnames())
2224 AppleNames.addName(Pubname.Name,
2225 Pubname.Die->getOffset() + Unit.getStartOffset());
2227 for (
const auto &Pubtype : Unit.getPubtypes())
2229 Pubtype.Name, Pubtype.Die->getOffset() + Unit.getStartOffset(),
2230 Pubtype.Die->getTag(),
2233 Pubtype.QualifiedNameHash);
2235 for (
const auto &ObjC : Unit.getObjC())
2236 AppleObjc.addName(
ObjC.Name,
2237 ObjC.Die->getOffset() + Unit.getStartOffset());
2244 for (
const auto &Namespace : Unit.getNamespaces())
2246 Namespace.Name, Namespace.Die->getOffset(),
2248 Namespace.Die->getTag(), Unit.getUniqueID());
2249 for (
const auto &Pubname : Unit.getPubnames())
2251 Pubname.Name, Pubname.Die->getOffset(),
2253 Pubname.Die->getTag(), Unit.getUniqueID());
2254 for (
const auto &Pubtype : Unit.getPubtypes())
2256 Pubtype.Name, Pubtype.Die->getOffset(),
2258 Pubtype.Die->getTag(), Unit.getUniqueID());
2270void DWARFLinker::patchFrameInfoForObject(LinkContext &Context) {
2271 DWARFContext &OrigDwarf = *
Context.File.Dwarf;
2272 unsigned SrcAddrSize = OrigDwarf.getDWARFObj().getAddressSize();
2274 StringRef
FrameData = OrigDwarf.getDWARFObj().getFrameSection().Data;
2279 for (std::unique_ptr<CompileUnit> &Unit :
Context.CompileUnits) {
2280 for (
auto CurRange : Unit->getFunctionRanges())
2281 AllUnitsRanges.
insert(CurRange.Range, CurRange.Value);
2284 DataExtractor
Data(FrameData, OrigDwarf.isLittleEndian(), 0);
2289 DenseMap<uint64_t, StringRef> LocalCIES;
2291 while (
Data.isValidOffset(InputOffset)) {
2292 uint64_t EntryOffset = InputOffset;
2294 if (InitialLength == 0xFFFFFFFF)
2295 return reportWarning(
"Dwarf64 bits no supported",
Context.File);
2298 if (CIEId == 0xFFFFFFFF) {
2300 StringRef CIEData =
FrameData.substr(EntryOffset, InitialLength + 4);
2301 LocalCIES[EntryOffset] = CIEData;
2303 InputOffset += InitialLength - 4;
2307 uint64_t Loc =
Data.getUnsigned(&InputOffset, SrcAddrSize);
2313 std::optional<AddressRangeValuePair>
Range =
2314 AllUnitsRanges.getRangeThatContains(Loc);
2317 InputOffset = EntryOffset + InitialLength + 4;
2323 StringRef CIEData = LocalCIES[CIEId];
2324 if (CIEData.empty())
2325 return reportWarning(
"Inconsistent debug_frame content. Dropping.",
2330 auto IteratorInserted = EmittedCIEs.
insert(
2333 if (IteratorInserted.second) {
2335 IteratorInserted.first->getValue() = LastCIEOffset;
2336 TheDwarfEmitter->
emitCIE(CIEData);
2342 unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize);
2343 TheDwarfEmitter->
emitFDE(IteratorInserted.first->getValue(), SrcAddrSize,
2345 FrameData.substr(InputOffset, FDERemainingBytes));
2346 InputOffset += FDERemainingBytes;
2350uint32_t DWARFLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE,
2352 const DWARFFile &File,
2353 int ChildRecurseDepth) {
2354 const char *
Name =
nullptr;
2355 DWARFUnit *OrigUnit = &
U.getOrigUnit();
2356 CompileUnit *
CU = &
U;
2357 std::optional<DWARFFormValue>
Ref;
2363 if (!(
Ref = DIE.find(dwarf::DW_AT_specification)) &&
2364 !(
Ref = DIE.find(dwarf::DW_AT_abstract_origin)))
2372 Linker.resolveDIEReference(File, CompileUnits, *
Ref, DIE, RefCU)) {
2374 OrigUnit = &RefCU->getOrigUnit();
2379 unsigned Idx = OrigUnit->getDIEIndex(DIE);
2380 if (!
Name && DIE.getTag() == dwarf::DW_TAG_namespace)
2381 Name =
"(anonymous namespace)";
2383 if (
CU->getInfo(
Idx).ParentIdx == 0 ||
2385 CU->getOrigUnit().getDIEAtIndex(
CU->getInfo(
Idx).ParentIdx).getTag() ==
2386 dwarf::DW_TAG_module)
2389 DWARFDie Die = OrigUnit->getDIEAtIndex(
CU->getInfo(
Idx).ParentIdx);
2398 CUDie.
find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id}));
2407 if (ObjectPrefixMap.empty())
2411 for (
const auto &Entry : ObjectPrefixMap)
2414 return p.str().str();
2421 CUDie.
find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
"");
2423 if (PCMFile.empty())
2426 if (ObjectPrefixMap)
2427 PCMFile =
remapPath(PCMFile, *ObjectPrefixMap);
2432std::pair<bool, bool> DWARFLinker::isClangModuleRef(
const DWARFDie &CUDie,
2433 std::string &PCMFile,
2434 LinkContext &Context,
2437 if (PCMFile.empty())
2438 return std::make_pair(
false,
false);
2446 reportWarning(
"Anonymous module skeleton CU for " + PCMFile,
2448 return std::make_pair(
true,
true);
2451 if (!
Quiet && Options.Verbose) {
2453 outs() <<
"Found clang module reference " << PCMFile;
2456 auto Cached = ClangModules.
find(PCMFile);
2457 if (Cached != ClangModules.
end()) {
2461 if (!
Quiet && Options.Verbose && (Cached->second != DwoId))
2462 reportWarning(Twine(
"hash mismatch: this object file was built against a "
2463 "different version of the module ") +
2466 if (!
Quiet && Options.Verbose)
2467 outs() <<
" [cached].\n";
2468 return std::make_pair(
true,
true);
2471 return std::make_pair(
true,
false);
2474bool DWARFLinker::registerModuleReference(
const DWARFDie &CUDie,
2475 LinkContext &Context,
2476 ObjFileLoaderTy Loader,
2477 CompileUnitHandlerTy OnCUDieLoaded,
2479 std::string PCMFile =
getPCMFile(CUDie, Options.ObjectPrefixMap);
2480 std::pair<bool, bool> IsClangModuleRef =
2481 isClangModuleRef(CUDie, PCMFile, Context, Indent,
false);
2483 if (!IsClangModuleRef.first)
2486 if (IsClangModuleRef.second)
2489 if (Options.Verbose)
2496 if (Error
E = loadClangModule(Loader, CUDie, PCMFile, Context, OnCUDieLoaded,
2504Error DWARFLinker::loadClangModule(
2505 ObjFileLoaderTy Loader,
const DWARFDie &CUDie,
const std::string &PCMFile,
2506 LinkContext &Context, CompileUnitHandlerTy OnCUDieLoaded,
unsigned Indent) {
2512 SmallString<0>
Path(Options.PrependPath);
2519 if (Loader ==
nullptr) {
2520 reportError(
"Could not load clang module: loader is not specified.\n",
2525 auto ErrOrObj = Loader(
Context.File.FileName, Path);
2529 std::unique_ptr<CompileUnit> Unit;
2530 for (
const auto &
CU : ErrOrObj->Dwarf->compile_units()) {
2533 auto ChildCUDie =
CU->getUnitDIE();
2536 if (!registerModuleReference(ChildCUDie, Context, Loader, OnCUDieLoaded,
2541 ": Clang modules are expected to have exactly 1 compile unit.\n");
2542 reportError(Err,
Context.File);
2549 if (PCMDwoId != DwoId) {
2550 if (Options.Verbose)
2552 Twine(
"hash mismatch: this object file was built against a "
2553 "different version of the module ") +
2557 ClangModules[PCMFile] = PCMDwoId;
2561 Unit = std::make_unique<CompileUnit>(*
CU, UniqueUnitID++, !Options.NoODR,
2567 Context.ModuleUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)});
2572uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
2573 DWARFContext &DwarfContext,
const DWARFFile &File,
bool IsLittleEndian) {
2576 const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
2578 for (
auto &CurrentUnit : CompileUnits) {
2579 const uint16_t DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
2580 const uint32_t UnitHeaderSize = DwarfVersion >= 5 ? 12 : 11;
2581 auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();
2582 CurrentUnit->setStartOffset(OutputDebugInfoSize);
2584 OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
2587 if (CurrentUnit->getInfo(0).Keep) {
2590 CurrentUnit->createOutputDIE();
2591 rememberUnitForMacroOffset(*CurrentUnit);
2592 cloneDIE(InputDIE, File, *CurrentUnit, 0 , UnitHeaderSize,
2593 0, IsLittleEndian, CurrentUnit->getOutputUnitDIE());
2596 OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
2600 generateLineTableForUnit(*CurrentUnit);
2602 Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
2607 Linker.generateUnitRanges(*CurrentUnit, File, AddrPool);
2609 auto ProcessExpr = [&](SmallVectorImpl<uint8_t> &SrcBytes,
2610 SmallVectorImpl<uint8_t> &OutBytes,
2611 int64_t RelocAdjustment) {
2612 DWARFUnit &OrigUnit = CurrentUnit->getOrigUnit();
2613 DataExtractor
Data(SrcBytes, IsLittleEndian,
2614 OrigUnit.getAddressByteSize());
2615 cloneExpression(
Data,
2616 DWARFExpression(
Data, OrigUnit.getAddressByteSize(),
2617 OrigUnit.getFormParams().Format),
2618 File, *CurrentUnit, OutBytes, RelocAdjustment,
2621 generateUnitLocations(*CurrentUnit, File, ProcessExpr);
2622 emitDebugAddrSection(*CurrentUnit, DwarfVersion);
2630 Emitter->emitMacroTables(
File.Dwarf.get(), UnitMacroMap, DebugStrPool);
2633 for (
auto &CurrentUnit : CompileUnits) {
2634 CurrentUnit->fixupForwardReferences();
2636 if (!CurrentUnit->getOutputUnitDIE())
2639 unsigned DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
2642 CurrentUnit->getStartOffset());
2643 Emitter->emitCompileUnitHeader(*CurrentUnit, DwarfVersion);
2644 Emitter->emitDIE(*CurrentUnit->getOutputUnitDIE());
2646 CurrentUnit->computeNextUnitOffset(DwarfVersion));
2650 return OutputDebugInfoSize - StartOutputDebugInfoSize;
2653void DWARFLinker::copyInvariantDebugSection(DWARFContext &
Dwarf) {
2657 Dwarf.getDWARFObj().getRangesSection().Data,
2666 Dwarf.getDWARFObj().getRnglistsSection().Data,
2669 Dwarf.getDWARFObj().getLoclistsSection().Data,
2675 ObjectContexts.emplace_back(LinkContext(File));
2677 if (ObjectContexts.back().File.Dwarf) {
2678 for (
const std::unique_ptr<DWARFUnit> &
CU :
2679 ObjectContexts.back().File.Dwarf->compile_units()) {
2688 registerModuleReference(CUDie, ObjectContexts.back(), Loader,
2695 assert((Options.TargetDWARFVersion != 0) &&
2696 "TargetDWARFVersion should be set");
2700 unsigned NumObjects = ObjectContexts.size();
2712 for (LinkContext &OptContext : ObjectContexts) {
2713 if (Options.Verbose)
2714 outs() <<
"DEBUG MAP OBJECT: " << OptContext.File.FileName <<
"\n";
2716 if (!OptContext.File.Dwarf)
2719 if (Options.VerifyInputDWARF)
2720 verifyInput(OptContext.File);
2727 !OptContext.File.Addresses->hasValidRelocs()) {
2728 if (Options.Verbose)
2729 outs() <<
"No valid relocations found. Skipping.\n";
2733 OptContext.Skip =
true;
2738 if (!OptContext.File.Dwarf)
2742 if (!OptContext.File.Dwarf->types_section_units().empty()) {
2743 reportWarning(
"type units are not currently supported: file will "
2746 OptContext.Skip =
true;
2752 OptContext.CompileUnits.reserve(
2753 OptContext.File.Dwarf->getNumCompileUnits());
2754 for (
const auto &
CU : OptContext.File.Dwarf->compile_units()) {
2755 auto CUDie =
CU->getUnitDIE(
true);
2756 if (Options.Verbose) {
2757 outs() <<
"Input compilation unit:";
2760 DumpOpts.
Verbose = Options.Verbose;
2761 CUDie.dump(
outs(), 0, DumpOpts);
2765 for (
auto &
CU : OptContext.ModuleUnits) {
2766 if (
Error Err = cloneModuleUnit(OptContext,
CU, ODRContexts, DebugStrPool,
2767 DebugLineStrPool, StringOffsetPool))
2768 reportWarning(
toString(std::move(Err)),
CU.File);
2778 (TheDwarfEmitter ==
nullptr) ? 0
2783 std::mutex ProcessedFilesMutex;
2784 std::condition_variable ProcessedFilesConditionVariable;
2785 BitVector ProcessedFiles(NumObjects,
false);
2789 auto AnalyzeLambda = [&](
size_t I) {
2795 for (
const auto &
CU :
Context.File.Dwarf->compile_units()) {
2798 auto CUDie =
CU->getUnitDIE(
false);
2799 std::string PCMFile =
getPCMFile(CUDie, Options.ObjectPrefixMap);
2802 !isClangModuleRef(CUDie, PCMFile,
Context, 0,
true).first) {
2803 Context.CompileUnits.push_back(std::make_unique<CompileUnit>(
2804 *
CU, UniqueUnitID++, !Options.NoODR && !Options.Update,
""));
2809 for (
auto &CurrentUnit :
Context.CompileUnits) {
2810 auto CUDie = CurrentUnit->getOrigUnit().getUnitDIE();
2814 *CurrentUnit, &ODRContexts.
getRoot(), ODRContexts,
2815 ModulesEndOffset, Options.ParseableSwiftInterfaces,
2817 reportWarning(Warning, Context.File, &DIE);
2829 auto CloneLambda = [&](
size_t I) {
2830 auto &OptContext = ObjectContexts[
I];
2831 if (OptContext.Skip || !OptContext.File.Dwarf)
2840 for (
auto &CurrentUnit : OptContext.CompileUnits)
2841 CurrentUnit->markEverythingAsKept();
2842 copyInvariantDebugSection(*OptContext.File.Dwarf);
2844 for (
auto &CurrentUnit : OptContext.CompileUnits) {
2845 lookForDIEsToKeep(*OptContext.File.Addresses, OptContext.CompileUnits,
2846 CurrentUnit->getOrigUnit().getUnitDIE(),
2847 OptContext.File, *CurrentUnit, 0);
2857 if (OptContext.File.Addresses->hasValidRelocs() ||
2859 SizeByObject[OptContext.File.FileName].Input =
2861 SizeByObject[OptContext.File.FileName].Output =
2862 DIECloner(*
this, TheDwarfEmitter, OptContext.File, DIEAlloc,
2863 OptContext.CompileUnits, Options.Update, DebugStrPool,
2864 DebugLineStrPool, StringOffsetPool)
2865 .cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
2866 OptContext.File.Dwarf->isLittleEndian());
2868 if ((TheDwarfEmitter !=
nullptr) && !OptContext.CompileUnits.empty() &&
2870 patchFrameInfoForObject(OptContext);
2873 cleanupAuxiliarryData(OptContext);
2876 auto EmitLambda = [&]() {
2878 if (TheDwarfEmitter !=
nullptr) {
2879 TheDwarfEmitter->
emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);
2882 Options.TargetDWARFVersion);
2885 switch (TableKind) {
2904 auto AnalyzeAll = [&]() {
2905 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2908 std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
2909 ProcessedFiles.
set(
I);
2910 ProcessedFilesConditionVariable.notify_one();
2914 auto CloneAll = [&]() {
2915 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2917 std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
2918 if (!ProcessedFiles[
I]) {
2919 ProcessedFilesConditionVariable.wait(
2920 LockGuard, [&]() {
return ProcessedFiles[
I]; });
2932 if (Options.Threads == 1) {
2933 for (
unsigned I = 0,
E = NumObjects;
I !=
E; ++
I) {
2940 Pool.
async(AnalyzeAll);
2941 Pool.
async(CloneAll);
2945 if (Options.Statistics) {
2947 std::vector<std::pair<StringRef, DebugInfoSize>> Sorted;
2948 for (
auto &
E : SizeByObject)
2949 Sorted.emplace_back(
E.first(),
E.second);
2951 return LHS.second.Output >
RHS.second.Output;
2954 auto ComputePercentange = [](int64_t Input, int64_t Output) ->
float {
2955 const float Difference = Output - Input;
2956 const float Sum = Input + Output;
2959 return (Difference / (Sum / 2));
2962 int64_t InputTotal = 0;
2963 int64_t OutputTotal = 0;
2964 const char *FormatStr =
"{0,-45} {1,10}b {2,10}b {3,8:P}\n";
2967 outs() <<
".debug_info section size (in bytes)\n";
2968 outs() <<
"----------------------------------------------------------------"
2969 "---------------\n";
2970 outs() <<
"Filename Object "
2972 outs() <<
"----------------------------------------------------------------"
2973 "---------------\n";
2976 for (
auto &
E : Sorted) {
2977 InputTotal +=
E.second.Input;
2978 OutputTotal +=
E.second.Output;
2981 E.second.Output, ComputePercentange(
E.second.Input,
E.second.Output));
2984 outs() <<
"----------------------------------------------------------------"
2985 "---------------\n";
2987 ComputePercentange(InputTotal, OutputTotal));
2988 outs() <<
"----------------------------------------------------------------"
2989 "---------------\n\n";
2995Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
3001 assert(Unit.Unit.get() !=
nullptr);
3003 if (!Unit.Unit->getOrigUnit().getUnitDIE().hasChildren())
3006 if (Options.Verbose) {
3008 outs() <<
"cloning .debug_info from " << Unit.File.FileName <<
"\n";
3013 &ODRContexts.
getRoot(), ODRContexts, 0,
3014 Options.ParseableSwiftInterfaces,
3016 reportWarning(Warning, Context.File, &DIE);
3019 Unit.Unit->markEverythingAsKept();
3023 CompileUnits.emplace_back(std::move(Unit.Unit));
3025 DIECloner(*
this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits,
3026 Options.Update, DebugStrPool, DebugLineStrPool, StringOffsetPool)
3027 .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,
3028 Unit.File.Dwarf->isLittleEndian());
3032void DWARFLinker::verifyInput(
const DWARFFile &File) {
3039 if (Options.InputVerificationHandler)
3040 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.
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
StringMapEntry< std::nullopt_t > StringEntry
StringEntry keeps data of the string: the length, external offset and a string body which is placed r...
SmallString< 128 > guessToolchainBaseDir(StringRef SysRoot)
Make a best effort to guess the Xcode.app/Contents/Developer/Toolchains/ path from an SDK path.
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?