diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp | 1880 |
1 files changed, 1880 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp new file mode 100644 index 000000000000..ffcf9f365aec --- /dev/null +++ b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp @@ -0,0 +1,1880 @@ +//=== DWARFLinkerCompileUnit.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DWARFLinkerCompileUnit.h" +#include "AcceleratorRecordsSaver.h" +#include "DIEAttributeCloner.h" +#include "DIEGenerator.h" +#include "DependencyTracker.h" +#include "SyntheticTypeNameBuilder.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Path.h" +#include <utility> + +using namespace llvm; +using namespace dwarf_linker; +using namespace dwarf_linker::parallel; + +CompileUnit::CompileUnit(LinkingGlobalData &GlobalData, unsigned ID, + StringRef ClangModuleName, DWARFFile &File, + OffsetToUnitTy UnitFromOffset, + dwarf::FormParams Format, llvm::endianness Endianess) + : DwarfUnit(GlobalData, ID, ClangModuleName), File(File), + getUnitFromOffset(UnitFromOffset), Stage(Stage::CreatedNotLoaded), + AcceleratorRecords(&GlobalData.getAllocator()) { + UnitName = File.FileName; + setOutputFormat(Format, Endianess); + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); +} + +CompileUnit::CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit, + unsigned ID, StringRef ClangModuleName, + DWARFFile &File, OffsetToUnitTy UnitFromOffset, + dwarf::FormParams Format, llvm::endianness Endianess) + : DwarfUnit(GlobalData, ID, ClangModuleName), File(File), + OrigUnit(&OrigUnit), getUnitFromOffset(UnitFromOffset), + Stage(Stage::CreatedNotLoaded), + AcceleratorRecords(&GlobalData.getAllocator()) { + setOutputFormat(Format, Endianess); + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); + + DWARFDie CUDie = OrigUnit.getUnitDIE(); + if (!CUDie) + return; + + if (std::optional<DWARFFormValue> Val = CUDie.find(dwarf::DW_AT_language)) { + uint16_t LangVal = dwarf::toUnsigned(Val, 0); + if (isODRLanguage(LangVal)) + Language = LangVal; + } + + if (!GlobalData.getOptions().NoODR && Language.has_value()) + NoODR = false; + + if (const char *CUName = CUDie.getName(DINameKind::ShortName)) + UnitName = CUName; + else + UnitName = File.FileName; + SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str(); +} + +void CompileUnit::loadLineTable() { + LineTablePtr = File.Dwarf->getLineTableForUnit(&getOrigUnit()); +} + +void CompileUnit::maybeResetToLoadedStage() { + // Nothing to reset if stage is less than "Loaded". + if (getStage() < Stage::Loaded) + return; + + // Note: We need to do erasing for "Loaded" stage because + // if live analysys failed then we will have "Loaded" stage + // with marking from "LivenessAnalysisDone" stage partially + // done. That marking should be cleared. + + for (DIEInfo &Info : DieInfoArray) + Info.unsetFlagsWhichSetDuringLiveAnalysis(); + + LowPc = std::nullopt; + HighPc = 0; + Labels.clear(); + Ranges.clear(); + Dependencies.reset(nullptr); + + if (getStage() < Stage::Cloned) { + setStage(Stage::Loaded); + return; + } + + AcceleratorRecords.erase(); + AbbreviationsSet.clear(); + Abbreviations.clear(); + OutUnitDIE = nullptr; + DebugAddrIndexMap.clear(); + + for (uint64_t &Offset : OutDieOffsetArray) + Offset = 0; + for (TypeEntry *&Name : TypeEntries) + Name = nullptr; + eraseSections(); + + setStage(Stage::CreatedNotLoaded); +} + +bool CompileUnit::loadInputDIEs() { + DWARFDie InputUnitDIE = getUnitDIE(false); + if (!InputUnitDIE) + return false; + + // load input dies, resize Info structures array. + DieInfoArray.resize(getOrigUnit().getNumDIEs()); + OutDieOffsetArray.resize(getOrigUnit().getNumDIEs(), 0); + if (!NoODR) + TypeEntries.resize(getOrigUnit().getNumDIEs()); + return true; +} + +void CompileUnit::analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry, + bool IsODRUnavailableFunctionScope) { + CompileUnit::DIEInfo &DieInfo = getDIEInfo(DieEntry); + + for (const DWARFDebugInfoEntry *CurChild = getFirstChildEntry(DieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = getSiblingEntry(CurChild)) { + CompileUnit::DIEInfo &ChildInfo = getDIEInfo(CurChild); + bool ChildIsODRUnavailableFunctionScope = IsODRUnavailableFunctionScope; + + if (DieInfo.getIsInMouduleScope()) + ChildInfo.setIsInMouduleScope(); + + if (DieInfo.getIsInFunctionScope()) + ChildInfo.setIsInFunctionScope(); + + if (DieInfo.getIsInAnonNamespaceScope()) + ChildInfo.setIsInAnonNamespaceScope(); + + switch (CurChild->getTag()) { + case dwarf::DW_TAG_module: + ChildInfo.setIsInMouduleScope(); + if (DieEntry->getTag() == dwarf::DW_TAG_compile_unit && + dwarf::toString(find(CurChild, dwarf::DW_AT_name), "") != + getClangModuleName()) + analyzeImportedModule(CurChild); + break; + case dwarf::DW_TAG_subprogram: + ChildInfo.setIsInFunctionScope(); + if (!ChildIsODRUnavailableFunctionScope && + !ChildInfo.getIsInMouduleScope()) { + if (find(CurChild, + {dwarf::DW_AT_abstract_origin, dwarf::DW_AT_specification})) + ChildIsODRUnavailableFunctionScope = true; + } + break; + case dwarf::DW_TAG_namespace: { + UnitEntryPairTy NamespaceEntry = {this, CurChild}; + + if (find(CurChild, dwarf::DW_AT_extension)) + NamespaceEntry = NamespaceEntry.getNamespaceOrigin(); + + if (!NamespaceEntry.CU->find(NamespaceEntry.DieEntry, dwarf::DW_AT_name)) + ChildInfo.setIsInAnonNamespaceScope(); + } break; + default: + break; + } + + if (!isClangModule() && !getGlobalData().getOptions().UpdateIndexTablesOnly) + ChildInfo.setTrackLiveness(); + + if ((!ChildInfo.getIsInAnonNamespaceScope() && + !ChildIsODRUnavailableFunctionScope && !NoODR)) + ChildInfo.setODRAvailable(); + + if (CurChild->hasChildren()) + analyzeDWARFStructureRec(CurChild, ChildIsODRUnavailableFunctionScope); + } +} + +StringEntry *CompileUnit::getFileName(unsigned FileIdx, + StringPool &GlobalStrings) { + if (LineTablePtr) { + if (LineTablePtr->hasFileAtIndex(FileIdx)) { + // Cache the resolved paths based on the index in the line table, + // because calling realpath is expensive. + ResolvedPathsMap::const_iterator It = ResolvedFullPaths.find(FileIdx); + if (It == ResolvedFullPaths.end()) { + std::string OrigFileName; + bool FoundFileName = LineTablePtr->getFileNameByIndex( + FileIdx, getOrigUnit().getCompilationDir(), + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, + OrigFileName); + (void)FoundFileName; + assert(FoundFileName && "Must get file name from line table"); + + // Second level of caching, this time based on the file's parent + // path. + StringRef FileName = sys::path::filename(OrigFileName); + StringRef ParentPath = sys::path::parent_path(OrigFileName); + + // If the ParentPath has not yet been resolved, resolve and cache it for + // future look-ups. + StringMap<StringEntry *>::iterator ParentIt = + ResolvedParentPaths.find(ParentPath); + if (ParentIt == ResolvedParentPaths.end()) { + SmallString<256> RealPath; + sys::fs::real_path(ParentPath, RealPath); + ParentIt = + ResolvedParentPaths + .insert({ParentPath, GlobalStrings.insert(RealPath).first}) + .first; + } + + // Join the file name again with the resolved path. + SmallString<256> ResolvedPath(ParentIt->second->first()); + sys::path::append(ResolvedPath, FileName); + + It = ResolvedFullPaths + .insert(std::make_pair( + FileIdx, GlobalStrings.insert(ResolvedPath).first)) + .first; + } + + return It->second; + } + } + + return nullptr; +} + +void CompileUnit::cleanupDataAfterClonning() { + AbbreviationsSet.clear(); + ResolvedFullPaths.shrink_and_clear(); + ResolvedParentPaths.clear(); + FileNames.shrink_and_clear(); + DieInfoArray = SmallVector<DIEInfo>(); + OutDieOffsetArray = SmallVector<uint64_t>(); + TypeEntries = SmallVector<TypeEntry *>(); + Dependencies.reset(nullptr); + getOrigUnit().clear(); +} + +/// Make a best effort to guess the +/// Xcode.app/Contents/Developer/Toolchains/ path from an SDK path. +static SmallString<128> guessToolchainBaseDir(StringRef SysRoot) { + SmallString<128> Result; + // Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk + StringRef Base = sys::path::parent_path(SysRoot); + if (sys::path::filename(Base) != "SDKs") + return Result; + Base = sys::path::parent_path(Base); + Result = Base; + Result += "/Toolchains"; + return Result; +} + +/// Collect references to parseable Swift interfaces in imported +/// DW_TAG_module blocks. +void CompileUnit::analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry) { + if (!Language || Language != dwarf::DW_LANG_Swift) + return; + + if (!GlobalData.getOptions().ParseableSwiftInterfaces) + return; + + StringRef Path = + dwarf::toStringRef(find(DieEntry, dwarf::DW_AT_LLVM_include_path)); + if (!Path.ends_with(".swiftinterface")) + return; + // Don't track interfaces that are part of the SDK. + StringRef SysRoot = + dwarf::toStringRef(find(DieEntry, dwarf::DW_AT_LLVM_sysroot)); + if (SysRoot.empty()) + SysRoot = getSysRoot(); + if (!SysRoot.empty() && Path.starts_with(SysRoot)) + return; + // Don't track interfaces that are part of the toolchain. + // For example: Swift, _Concurrency, ... + SmallString<128> Toolchain = guessToolchainBaseDir(SysRoot); + if (!Toolchain.empty() && Path.starts_with(Toolchain)) + return; + if (std::optional<DWARFFormValue> Val = find(DieEntry, dwarf::DW_AT_name)) { + Expected<const char *> Name = Val->getAsCString(); + if (!Name) { + warn(Name.takeError()); + return; + } + + auto &Entry = (*GlobalData.getOptions().ParseableSwiftInterfaces)[*Name]; + // The prepend path is applied later when copying. + SmallString<128> ResolvedPath; + if (sys::path::is_relative(Path)) + sys::path::append( + ResolvedPath, + dwarf::toString(getUnitDIE().find(dwarf::DW_AT_comp_dir), "")); + sys::path::append(ResolvedPath, Path); + if (!Entry.empty() && Entry != ResolvedPath) { + DWARFDie Die = getDIE(DieEntry); + warn(Twine("conflicting parseable interfaces for Swift Module ") + *Name + + ": " + Entry + " and " + Path + ".", + &Die); + } + Entry = std::string(ResolvedPath.str()); + } +} + +Error CompileUnit::assignTypeNames(TypePool &TypePoolRef) { + if (!getUnitDIE().isValid()) + return Error::success(); + + SyntheticTypeNameBuilder NameBuilder(TypePoolRef); + return assignTypeNamesRec(getDebugInfoEntry(0), NameBuilder); +} + +Error CompileUnit::assignTypeNamesRec(const DWARFDebugInfoEntry *DieEntry, + SyntheticTypeNameBuilder &NameBuilder) { + OrderedChildrenIndexAssigner ChildrenIndexAssigner(*this, DieEntry); + for (const DWARFDebugInfoEntry *CurChild = getFirstChildEntry(DieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = getSiblingEntry(CurChild)) { + CompileUnit::DIEInfo &ChildInfo = getDIEInfo(CurChild); + if (!ChildInfo.needToPlaceInTypeTable()) + continue; + + assert(ChildInfo.getODRAvailable()); + if (Error Err = NameBuilder.assignName( + {this, CurChild}, + ChildrenIndexAssigner.getChildIndex(*this, CurChild))) + return Err; + + if (Error Err = assignTypeNamesRec(CurChild, NameBuilder)) + return Err; + } + + return Error::success(); +} + +void CompileUnit::updateDieRefPatchesWithClonedOffsets() { + if (std::optional<SectionDescriptor *> DebugInfoSection = + tryGetSectionDescriptor(DebugSectionKind::DebugInfo)) { + + (*DebugInfoSection) + ->ListDebugDieRefPatch.forEach([&](DebugDieRefPatch &Patch) { + /// Replace stored DIE indexes with DIE output offsets. + Patch.RefDieIdxOrClonedOffset = + Patch.RefCU.getPointer()->getDieOutOffset( + Patch.RefDieIdxOrClonedOffset); + }); + + (*DebugInfoSection) + ->ListDebugULEB128DieRefPatch.forEach( + [&](DebugULEB128DieRefPatch &Patch) { + /// Replace stored DIE indexes with DIE output offsets. + Patch.RefDieIdxOrClonedOffset = + Patch.RefCU.getPointer()->getDieOutOffset( + Patch.RefDieIdxOrClonedOffset); + }); + } + + if (std::optional<SectionDescriptor *> DebugLocSection = + tryGetSectionDescriptor(DebugSectionKind::DebugLoc)) { + (*DebugLocSection) + ->ListDebugULEB128DieRefPatch.forEach( + [](DebugULEB128DieRefPatch &Patch) { + /// Replace stored DIE indexes with DIE output offsets. + Patch.RefDieIdxOrClonedOffset = + Patch.RefCU.getPointer()->getDieOutOffset( + Patch.RefDieIdxOrClonedOffset); + }); + } + + if (std::optional<SectionDescriptor *> DebugLocListsSection = + tryGetSectionDescriptor(DebugSectionKind::DebugLocLists)) { + (*DebugLocListsSection) + ->ListDebugULEB128DieRefPatch.forEach( + [](DebugULEB128DieRefPatch &Patch) { + /// Replace stored DIE indexes with DIE output offsets. + Patch.RefDieIdxOrClonedOffset = + Patch.RefCU.getPointer()->getDieOutOffset( + Patch.RefDieIdxOrClonedOffset); + }); + } +} + +std::optional<UnitEntryPairTy> CompileUnit::resolveDIEReference( + const DWARFFormValue &RefValue, + ResolveInterCUReferencesMode CanResolveInterCUReferences) { + if (std::optional<DWARFFormValue::UnitOffset> Ref = + *RefValue.getAsRelativeReference()) { + if (Ref->Unit == OrigUnit) { + // Referenced DIE is in current compile unit. + if (std::optional<uint32_t> RefDieIdx = + getDIEIndexForOffset(OrigUnit->getOffset() + Ref->Offset)) + return UnitEntryPairTy{this, OrigUnit->getDebugInfoEntry(*RefDieIdx)}; + } + uint64_t RefDIEOffset = + Ref->Unit ? Ref->Unit->getOffset() + Ref->Offset : Ref->Offset; + if (CompileUnit *RefCU = getUnitFromOffset(RefDIEOffset)) { + if (RefCU == this) { + // Referenced DIE is in current compile unit. + if (std::optional<uint32_t> RefDieIdx = + getDIEIndexForOffset(RefDIEOffset)) + return UnitEntryPairTy{this, getDebugInfoEntry(*RefDieIdx)}; + } else if (CanResolveInterCUReferences) { + // Referenced DIE is in other compile unit. + + // Check whether DIEs are loaded for that compile unit. + enum Stage ReferredCUStage = RefCU->getStage(); + if (ReferredCUStage < Stage::Loaded || ReferredCUStage > Stage::Cloned) + return UnitEntryPairTy{RefCU, nullptr}; + + if (std::optional<uint32_t> RefDieIdx = + RefCU->getDIEIndexForOffset(RefDIEOffset)) + return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)}; + } else + return UnitEntryPairTy{RefCU, nullptr}; + } + } + + return std::nullopt; +} + +std::optional<UnitEntryPairTy> CompileUnit::resolveDIEReference( + const DWARFDebugInfoEntry *DieEntry, dwarf::Attribute Attr, + ResolveInterCUReferencesMode CanResolveInterCUReferences) { + if (std::optional<DWARFFormValue> AttrVal = find(DieEntry, Attr)) + return resolveDIEReference(*AttrVal, CanResolveInterCUReferences); + + return std::nullopt; +} + +void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, + int64_t PcOffset) { + std::lock_guard<std::mutex> Guard(RangesMutex); + + Ranges.insert({FuncLowPc, FuncHighPc}, PcOffset); + if (LowPc) + LowPc = std::min(*LowPc, FuncLowPc + PcOffset); + else + LowPc = FuncLowPc + PcOffset; + this->HighPc = std::max(HighPc, FuncHighPc + PcOffset); +} + +void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) { + std::lock_guard<std::mutex> Guard(LabelsMutex); + Labels.insert({LabelLowPc, PcOffset}); +} + +Error CompileUnit::cloneAndEmitDebugLocations() { + if (getGlobalData().getOptions().UpdateIndexTablesOnly) + return Error::success(); + + if (getOrigUnit().getVersion() < 5) { + emitLocations(DebugSectionKind::DebugLoc); + return Error::success(); + } + + emitLocations(DebugSectionKind::DebugLocLists); + return Error::success(); +} + +void CompileUnit::emitLocations(DebugSectionKind LocationSectionKind) { + SectionDescriptor &DebugInfoSection = + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); + + if (!DebugInfoSection.ListDebugLocPatch.empty()) { + SectionDescriptor &OutLocationSection = + getOrCreateSectionDescriptor(LocationSectionKind); + DWARFUnit &OrigUnit = getOrigUnit(); + + uint64_t OffsetAfterUnitLength = emitLocListHeader(OutLocationSection); + + DebugInfoSection.ListDebugLocPatch.forEach([&](DebugLocPatch &Patch) { + // Get location expressions vector corresponding to the current + // attribute from the source DWARF. + uint64_t InputDebugLocSectionOffset = DebugInfoSection.getIntVal( + Patch.PatchOffset, + DebugInfoSection.getFormParams().getDwarfOffsetByteSize()); + Expected<DWARFLocationExpressionsVector> OriginalLocations = + OrigUnit.findLoclistFromOffset(InputDebugLocSectionOffset); + + if (!OriginalLocations) { + warn(OriginalLocations.takeError()); + return; + } + + LinkedLocationExpressionsVector LinkedLocationExpressions; + for (DWARFLocationExpression &CurExpression : *OriginalLocations) { + LinkedLocationExpressionsWithOffsetPatches LinkedExpression; + + if (CurExpression.Range) { + // Relocate address range. + LinkedExpression.Expression.Range = { + CurExpression.Range->LowPC + Patch.AddrAdjustmentValue, + CurExpression.Range->HighPC + Patch.AddrAdjustmentValue}; + } + + DataExtractor Data(CurExpression.Expr, OrigUnit.isLittleEndian(), + OrigUnit.getAddressByteSize()); + + DWARFExpression InputExpression(Data, OrigUnit.getAddressByteSize(), + OrigUnit.getFormParams().Format); + cloneDieAttrExpression(InputExpression, + LinkedExpression.Expression.Expr, + OutLocationSection, Patch.AddrAdjustmentValue, + LinkedExpression.Patches); + + LinkedLocationExpressions.push_back({LinkedExpression}); + } + + // Emit locations list table fragment corresponding to the CurLocAttr. + DebugInfoSection.apply(Patch.PatchOffset, dwarf::DW_FORM_sec_offset, + OutLocationSection.OS.tell()); + emitLocListFragment(LinkedLocationExpressions, OutLocationSection); + }); + + if (OffsetAfterUnitLength > 0) { + assert(OffsetAfterUnitLength - + OutLocationSection.getFormParams().getDwarfOffsetByteSize() < + OffsetAfterUnitLength); + OutLocationSection.apply( + OffsetAfterUnitLength - + OutLocationSection.getFormParams().getDwarfOffsetByteSize(), + dwarf::DW_FORM_sec_offset, + OutLocationSection.OS.tell() - OffsetAfterUnitLength); + } + } +} + +/// Emit debug locations(.debug_loc, .debug_loclists) header. +uint64_t CompileUnit::emitLocListHeader(SectionDescriptor &OutLocationSection) { + if (getOrigUnit().getVersion() < 5) + return 0; + + // unit_length. + OutLocationSection.emitUnitLength(0xBADDEF); + uint64_t OffsetAfterUnitLength = OutLocationSection.OS.tell(); + + // Version. + OutLocationSection.emitIntVal(5, 2); + + // Address size. + OutLocationSection.emitIntVal(OutLocationSection.getFormParams().AddrSize, 1); + + // Seg_size + OutLocationSection.emitIntVal(0, 1); + + // Offset entry count + OutLocationSection.emitIntVal(0, 4); + + return OffsetAfterUnitLength; +} + +/// Emit debug locations(.debug_loc, .debug_loclists) fragment. +uint64_t CompileUnit::emitLocListFragment( + const LinkedLocationExpressionsVector &LinkedLocationExpression, + SectionDescriptor &OutLocationSection) { + uint64_t OffsetBeforeLocationExpression = 0; + + if (getOrigUnit().getVersion() < 5) { + uint64_t BaseAddress = 0; + if (std::optional<uint64_t> LowPC = getLowPc()) + BaseAddress = *LowPC; + + for (const LinkedLocationExpressionsWithOffsetPatches &LocExpression : + LinkedLocationExpression) { + if (LocExpression.Expression.Range) { + OutLocationSection.emitIntVal( + LocExpression.Expression.Range->LowPC - BaseAddress, + OutLocationSection.getFormParams().AddrSize); + OutLocationSection.emitIntVal( + LocExpression.Expression.Range->HighPC - BaseAddress, + OutLocationSection.getFormParams().AddrSize); + } + + OutLocationSection.emitIntVal(LocExpression.Expression.Expr.size(), 2); + OffsetBeforeLocationExpression = OutLocationSection.OS.tell(); + for (uint64_t *OffsetPtr : LocExpression.Patches) + *OffsetPtr += OffsetBeforeLocationExpression; + + OutLocationSection.OS + << StringRef((const char *)LocExpression.Expression.Expr.data(), + LocExpression.Expression.Expr.size()); + } + + // Emit the terminator entry. + OutLocationSection.emitIntVal(0, + OutLocationSection.getFormParams().AddrSize); + OutLocationSection.emitIntVal(0, + OutLocationSection.getFormParams().AddrSize); + return OffsetBeforeLocationExpression; + } + + std::optional<uint64_t> BaseAddress; + for (const LinkedLocationExpressionsWithOffsetPatches &LocExpression : + LinkedLocationExpression) { + if (LocExpression.Expression.Range) { + // Check whether base address is set. If it is not set yet + // then set current base address and emit base address selection entry. + if (!BaseAddress) { + BaseAddress = LocExpression.Expression.Range->LowPC; + + // Emit base address. + OutLocationSection.emitIntVal(dwarf::DW_LLE_base_addressx, 1); + encodeULEB128(DebugAddrIndexMap.getValueIndex(*BaseAddress), + OutLocationSection.OS); + } + + // Emit type of entry. + OutLocationSection.emitIntVal(dwarf::DW_LLE_offset_pair, 1); + + // Emit start offset relative to base address. + encodeULEB128(LocExpression.Expression.Range->LowPC - *BaseAddress, + OutLocationSection.OS); + + // Emit end offset relative to base address. + encodeULEB128(LocExpression.Expression.Range->HighPC - *BaseAddress, + OutLocationSection.OS); + } else + // Emit type of entry. + OutLocationSection.emitIntVal(dwarf::DW_LLE_default_location, 1); + + encodeULEB128(LocExpression.Expression.Expr.size(), OutLocationSection.OS); + OffsetBeforeLocationExpression = OutLocationSection.OS.tell(); + for (uint64_t *OffsetPtr : LocExpression.Patches) + *OffsetPtr += OffsetBeforeLocationExpression; + + OutLocationSection.OS << StringRef( + (const char *)LocExpression.Expression.Expr.data(), + LocExpression.Expression.Expr.size()); + } + + // Emit the terminator entry. + OutLocationSection.emitIntVal(dwarf::DW_LLE_end_of_list, 1); + return OffsetBeforeLocationExpression; +} + +Error CompileUnit::emitDebugAddrSection() { + if (GlobalData.getOptions().UpdateIndexTablesOnly) + return Error::success(); + + if (getVersion() < 5) + return Error::success(); + + if (DebugAddrIndexMap.empty()) + return Error::success(); + + SectionDescriptor &OutAddrSection = + getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr); + + // Emit section header. + + // Emit length. + OutAddrSection.emitUnitLength(0xBADDEF); + uint64_t OffsetAfterSectionLength = OutAddrSection.OS.tell(); + + // Emit version. + OutAddrSection.emitIntVal(5, 2); + + // Emit address size. + OutAddrSection.emitIntVal(getFormParams().AddrSize, 1); + + // Emit segment size. + OutAddrSection.emitIntVal(0, 1); + + // Emit addresses. + for (uint64_t AddrValue : DebugAddrIndexMap.getValues()) + OutAddrSection.emitIntVal(AddrValue, getFormParams().AddrSize); + + // Patch section length. + OutAddrSection.apply( + OffsetAfterSectionLength - + OutAddrSection.getFormParams().getDwarfOffsetByteSize(), + dwarf::DW_FORM_sec_offset, + OutAddrSection.OS.tell() - OffsetAfterSectionLength); + + return Error::success(); +} + +Error CompileUnit::cloneAndEmitRanges() { + if (getGlobalData().getOptions().UpdateIndexTablesOnly) + return Error::success(); + + // Build set of linked address ranges for unit function ranges. + AddressRanges LinkedFunctionRanges; + for (const AddressRangeValuePair &Range : getFunctionRanges()) + LinkedFunctionRanges.insert( + {Range.Range.start() + Range.Value, Range.Range.end() + Range.Value}); + + emitAranges(LinkedFunctionRanges); + + if (getOrigUnit().getVersion() < 5) { + cloneAndEmitRangeList(DebugSectionKind::DebugRange, LinkedFunctionRanges); + return Error::success(); + } + + cloneAndEmitRangeList(DebugSectionKind::DebugRngLists, LinkedFunctionRanges); + return Error::success(); +} + +void CompileUnit::cloneAndEmitRangeList(DebugSectionKind RngSectionKind, + AddressRanges &LinkedFunctionRanges) { + SectionDescriptor &DebugInfoSection = + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); + SectionDescriptor &OutRangeSection = + getOrCreateSectionDescriptor(RngSectionKind); + + if (!DebugInfoSection.ListDebugRangePatch.empty()) { + std::optional<AddressRangeValuePair> CachedRange; + uint64_t OffsetAfterUnitLength = emitRangeListHeader(OutRangeSection); + + DebugRangePatch *CompileUnitRangePtr = nullptr; + DebugInfoSection.ListDebugRangePatch.forEach([&](DebugRangePatch &Patch) { + if (Patch.IsCompileUnitRanges) { + CompileUnitRangePtr = &Patch; + } else { + // Get ranges from the source DWARF corresponding to the current + // attribute. + AddressRanges LinkedRanges; + uint64_t InputDebugRangesSectionOffset = DebugInfoSection.getIntVal( + Patch.PatchOffset, + DebugInfoSection.getFormParams().getDwarfOffsetByteSize()); + if (Expected<DWARFAddressRangesVector> InputRanges = + getOrigUnit().findRnglistFromOffset( + InputDebugRangesSectionOffset)) { + // Apply relocation adjustment. + for (const auto &Range : *InputRanges) { + if (!CachedRange || !CachedRange->Range.contains(Range.LowPC)) + CachedRange = + getFunctionRanges().getRangeThatContains(Range.LowPC); + + // All range entries should lie in the function range. + if (!CachedRange) { + warn("inconsistent range data."); + continue; + } + + // Store range for emiting. + LinkedRanges.insert({Range.LowPC + CachedRange->Value, + Range.HighPC + CachedRange->Value}); + } + } else { + llvm::consumeError(InputRanges.takeError()); + warn("invalid range list ignored."); + } + + // Emit linked ranges. + DebugInfoSection.apply(Patch.PatchOffset, dwarf::DW_FORM_sec_offset, + OutRangeSection.OS.tell()); + emitRangeListFragment(LinkedRanges, OutRangeSection); + } + }); + + if (CompileUnitRangePtr != nullptr) { + // Emit compile unit ranges last to be binary compatible with classic + // dsymutil. + DebugInfoSection.apply(CompileUnitRangePtr->PatchOffset, + dwarf::DW_FORM_sec_offset, + OutRangeSection.OS.tell()); + emitRangeListFragment(LinkedFunctionRanges, OutRangeSection); + } + + if (OffsetAfterUnitLength > 0) { + assert(OffsetAfterUnitLength - + OutRangeSection.getFormParams().getDwarfOffsetByteSize() < + OffsetAfterUnitLength); + OutRangeSection.apply( + OffsetAfterUnitLength - + OutRangeSection.getFormParams().getDwarfOffsetByteSize(), + dwarf::DW_FORM_sec_offset, + OutRangeSection.OS.tell() - OffsetAfterUnitLength); + } + } +} + +uint64_t CompileUnit::emitRangeListHeader(SectionDescriptor &OutRangeSection) { + if (OutRangeSection.getFormParams().Version < 5) + return 0; + + // unit_length. + OutRangeSection.emitUnitLength(0xBADDEF); + uint64_t OffsetAfterUnitLength = OutRangeSection.OS.tell(); + + // Version. + OutRangeSection.emitIntVal(5, 2); + + // Address size. + OutRangeSection.emitIntVal(OutRangeSection.getFormParams().AddrSize, 1); + + // Seg_size + OutRangeSection.emitIntVal(0, 1); + + // Offset entry count + OutRangeSection.emitIntVal(0, 4); + + return OffsetAfterUnitLength; +} + +void CompileUnit::emitRangeListFragment(const AddressRanges &LinkedRanges, + SectionDescriptor &OutRangeSection) { + if (OutRangeSection.getFormParams().Version < 5) { + // Emit ranges. + uint64_t BaseAddress = 0; + if (std::optional<uint64_t> LowPC = getLowPc()) + BaseAddress = *LowPC; + + for (const AddressRange &Range : LinkedRanges) { + OutRangeSection.emitIntVal(Range.start() - BaseAddress, + OutRangeSection.getFormParams().AddrSize); + OutRangeSection.emitIntVal(Range.end() - BaseAddress, + OutRangeSection.getFormParams().AddrSize); + } + + // Add the terminator entry. + OutRangeSection.emitIntVal(0, OutRangeSection.getFormParams().AddrSize); + OutRangeSection.emitIntVal(0, OutRangeSection.getFormParams().AddrSize); + return; + } + + std::optional<uint64_t> BaseAddress; + for (const AddressRange &Range : LinkedRanges) { + if (!BaseAddress) { + BaseAddress = Range.start(); + + // Emit base address. + OutRangeSection.emitIntVal(dwarf::DW_RLE_base_addressx, 1); + encodeULEB128(getDebugAddrIndex(*BaseAddress), OutRangeSection.OS); + } + + // Emit type of entry. + OutRangeSection.emitIntVal(dwarf::DW_RLE_offset_pair, 1); + + // Emit start offset relative to base address. + encodeULEB128(Range.start() - *BaseAddress, OutRangeSection.OS); + + // Emit end offset relative to base address. + encodeULEB128(Range.end() - *BaseAddress, OutRangeSection.OS); + } + + // Emit the terminator entry. + OutRangeSection.emitIntVal(dwarf::DW_RLE_end_of_list, 1); +} + +void CompileUnit::emitAranges(AddressRanges &LinkedFunctionRanges) { + if (LinkedFunctionRanges.empty()) + return; + + SectionDescriptor &DebugInfoSection = + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); + SectionDescriptor &OutArangesSection = + getOrCreateSectionDescriptor(DebugSectionKind::DebugARanges); + + // Emit Header. + unsigned HeaderSize = + sizeof(int32_t) + // Size of contents (w/o this field + sizeof(int16_t) + // DWARF ARange version number + sizeof(int32_t) + // Offset of CU in the .debug_info section + sizeof(int8_t) + // Pointer Size (in bytes) + sizeof(int8_t); // Segment Size (in bytes) + + unsigned TupleSize = OutArangesSection.getFormParams().AddrSize * 2; + unsigned Padding = offsetToAlignment(HeaderSize, Align(TupleSize)); + + OutArangesSection.emitOffset(0xBADDEF); // Aranges length + uint64_t OffsetAfterArangesLengthField = OutArangesSection.OS.tell(); + + OutArangesSection.emitIntVal(dwarf::DW_ARANGES_VERSION, 2); // Version number + OutArangesSection.notePatch( + DebugOffsetPatch{OutArangesSection.OS.tell(), &DebugInfoSection}); + OutArangesSection.emitOffset(0xBADDEF); // Corresponding unit's offset + OutArangesSection.emitIntVal(OutArangesSection.getFormParams().AddrSize, + 1); // Address size + OutArangesSection.emitIntVal(0, 1); // Segment size + + for (size_t Idx = 0; Idx < Padding; Idx++) + OutArangesSection.emitIntVal(0, 1); // Padding + + // Emit linked ranges. + for (const AddressRange &Range : LinkedFunctionRanges) { + OutArangesSection.emitIntVal(Range.start(), + OutArangesSection.getFormParams().AddrSize); + OutArangesSection.emitIntVal(Range.end() - Range.start(), + OutArangesSection.getFormParams().AddrSize); + } + + // Emit terminator. + OutArangesSection.emitIntVal(0, OutArangesSection.getFormParams().AddrSize); + OutArangesSection.emitIntVal(0, OutArangesSection.getFormParams().AddrSize); + + uint64_t OffsetAfterArangesEnd = OutArangesSection.OS.tell(); + + // Update Aranges lentgh. + OutArangesSection.apply( + OffsetAfterArangesLengthField - + OutArangesSection.getFormParams().getDwarfOffsetByteSize(), + dwarf::DW_FORM_sec_offset, + OffsetAfterArangesEnd - OffsetAfterArangesLengthField); +} + +Error CompileUnit::cloneAndEmitDebugMacro() { + if (getOutUnitDIE() == nullptr) + return Error::success(); + + DWARFUnit &OrigUnit = getOrigUnit(); + DWARFDie OrigUnitDie = OrigUnit.getUnitDIE(); + + // Check for .debug_macro table. + if (std::optional<uint64_t> MacroAttr = + dwarf::toSectionOffset(OrigUnitDie.find(dwarf::DW_AT_macros))) { + if (const DWARFDebugMacro *Table = + getContaingFile().Dwarf->getDebugMacro()) { + emitMacroTableImpl(Table, *MacroAttr, true); + } + } + + // Check for .debug_macinfo table. + if (std::optional<uint64_t> MacroAttr = + dwarf::toSectionOffset(OrigUnitDie.find(dwarf::DW_AT_macro_info))) { + if (const DWARFDebugMacro *Table = + getContaingFile().Dwarf->getDebugMacinfo()) { + emitMacroTableImpl(Table, *MacroAttr, false); + } + } + + return Error::success(); +} + +void CompileUnit::emitMacroTableImpl(const DWARFDebugMacro *MacroTable, + uint64_t OffsetToMacroTable, + bool hasDWARFv5Header) { + SectionDescriptor &OutSection = + hasDWARFv5Header + ? getOrCreateSectionDescriptor(DebugSectionKind::DebugMacro) + : getOrCreateSectionDescriptor(DebugSectionKind::DebugMacinfo); + + bool DefAttributeIsReported = false; + bool UndefAttributeIsReported = false; + bool ImportAttributeIsReported = false; + + for (const DWARFDebugMacro::MacroList &List : MacroTable->MacroLists) { + if (OffsetToMacroTable == List.Offset) { + // Write DWARFv5 header. + if (hasDWARFv5Header) { + // Write header version. + OutSection.emitIntVal(List.Header.Version, sizeof(List.Header.Version)); + + uint8_t Flags = List.Header.Flags; + + // Check for OPCODE_OPERANDS_TABLE. + if (Flags & + DWARFDebugMacro::HeaderFlagMask::MACRO_OPCODE_OPERANDS_TABLE) { + Flags &= + ~DWARFDebugMacro::HeaderFlagMask::MACRO_OPCODE_OPERANDS_TABLE; + warn("opcode_operands_table is not supported yet."); + } + + // Check for DEBUG_LINE_OFFSET. + std::optional<uint64_t> StmtListOffset; + if (Flags & DWARFDebugMacro::HeaderFlagMask::MACRO_DEBUG_LINE_OFFSET) { + // Get offset to the line table from the cloned compile unit. + for (auto &V : getOutUnitDIE()->values()) { + if (V.getAttribute() == dwarf::DW_AT_stmt_list) { + StmtListOffset = V.getDIEInteger().getValue(); + break; + } + } + + if (!StmtListOffset) { + Flags &= ~DWARFDebugMacro::HeaderFlagMask::MACRO_DEBUG_LINE_OFFSET; + warn("couldn`t find line table for macro table."); + } + } + + // Write flags. + OutSection.emitIntVal(Flags, sizeof(Flags)); + + // Write offset to line table. + if (StmtListOffset) { + OutSection.notePatch(DebugOffsetPatch{ + OutSection.OS.tell(), + &getOrCreateSectionDescriptor(DebugSectionKind::DebugLine)}); + // TODO: check that List.Header.getOffsetByteSize() and + // DebugOffsetPatch agree on size. + OutSection.emitIntVal(0xBADDEF, List.Header.getOffsetByteSize()); + } + } + + // Write macro entries. + for (const DWARFDebugMacro::Entry &MacroEntry : List.Macros) { + if (MacroEntry.Type == 0) { + encodeULEB128(MacroEntry.Type, OutSection.OS); + continue; + } + + uint8_t MacroType = MacroEntry.Type; + switch (MacroType) { + default: { + bool HasVendorSpecificExtension = + (!hasDWARFv5Header && + MacroType == dwarf::DW_MACINFO_vendor_ext) || + (hasDWARFv5Header && (MacroType >= dwarf::DW_MACRO_lo_user && + MacroType <= dwarf::DW_MACRO_hi_user)); + + if (HasVendorSpecificExtension) { + // Write macinfo type. + OutSection.emitIntVal(MacroType, 1); + + // Write vendor extension constant. + encodeULEB128(MacroEntry.ExtConstant, OutSection.OS); + + // Write vendor extension string. + OutSection.emitString(dwarf::DW_FORM_string, MacroEntry.ExtStr); + } else + warn("unknown macro type. skip."); + } break; + // debug_macro and debug_macinfo share some common encodings. + // DW_MACRO_define == DW_MACINFO_define + // DW_MACRO_undef == DW_MACINFO_undef + // DW_MACRO_start_file == DW_MACINFO_start_file + // DW_MACRO_end_file == DW_MACINFO_end_file + // For readibility/uniformity we are using DW_MACRO_*. + case dwarf::DW_MACRO_define: + case dwarf::DW_MACRO_undef: { + // Write macinfo type. + OutSection.emitIntVal(MacroType, 1); + + // Write source line. + encodeULEB128(MacroEntry.Line, OutSection.OS); + + // Write macro string. + OutSection.emitString(dwarf::DW_FORM_string, MacroEntry.MacroStr); + } break; + case dwarf::DW_MACRO_define_strp: + case dwarf::DW_MACRO_undef_strp: + case dwarf::DW_MACRO_define_strx: + case dwarf::DW_MACRO_undef_strx: { + // DW_MACRO_*_strx forms are not supported currently. + // Convert to *_strp. + switch (MacroType) { + case dwarf::DW_MACRO_define_strx: { + MacroType = dwarf::DW_MACRO_define_strp; + if (!DefAttributeIsReported) { + warn("DW_MACRO_define_strx unsupported yet. Convert to " + "DW_MACRO_define_strp."); + DefAttributeIsReported = true; + } + } break; + case dwarf::DW_MACRO_undef_strx: { + MacroType = dwarf::DW_MACRO_undef_strp; + if (!UndefAttributeIsReported) { + warn("DW_MACRO_undef_strx unsupported yet. Convert to " + "DW_MACRO_undef_strp."); + UndefAttributeIsReported = true; + } + } break; + default: + // Nothing to do. + break; + } + + // Write macinfo type. + OutSection.emitIntVal(MacroType, 1); + + // Write source line. + encodeULEB128(MacroEntry.Line, OutSection.OS); + + // Write macro string. + OutSection.emitString(dwarf::DW_FORM_strp, MacroEntry.MacroStr); + break; + } + case dwarf::DW_MACRO_start_file: { + // Write macinfo type. + OutSection.emitIntVal(MacroType, 1); + // Write source line. + encodeULEB128(MacroEntry.Line, OutSection.OS); + // Write source file id. + encodeULEB128(MacroEntry.File, OutSection.OS); + } break; + case dwarf::DW_MACRO_end_file: { + // Write macinfo type. + OutSection.emitIntVal(MacroType, 1); + } break; + case dwarf::DW_MACRO_import: + case dwarf::DW_MACRO_import_sup: { + if (!ImportAttributeIsReported) { + warn("DW_MACRO_import and DW_MACRO_import_sup are unsupported " + "yet. remove."); + ImportAttributeIsReported = true; + } + } break; + } + } + + return; + } + } +} + +void CompileUnit::cloneDieAttrExpression( + const DWARFExpression &InputExpression, + SmallVectorImpl<uint8_t> &OutputExpression, SectionDescriptor &Section, + std::optional<int64_t> VarAddressAdjustment, + OffsetsPtrVector &PatchesOffsets) { + using Encoding = DWARFExpression::Operation::Encoding; + + DWARFUnit &OrigUnit = getOrigUnit(); + uint8_t OrigAddressByteSize = OrigUnit.getAddressByteSize(); + + uint64_t OpOffset = 0; + for (auto &Op : InputExpression) { + auto Desc = Op.getDescription(); + // DW_OP_const_type is variable-length and has 3 + // operands. Thus far we only support 2. + if ((Desc.Op.size() == 2 && Desc.Op[0] == Encoding::BaseTypeRef) || + (Desc.Op.size() == 2 && Desc.Op[1] == Encoding::BaseTypeRef && + Desc.Op[0] != Encoding::Size1)) + warn("unsupported DW_OP encoding."); + + if ((Desc.Op.size() == 1 && Desc.Op[0] == Encoding::BaseTypeRef) || + (Desc.Op.size() == 2 && Desc.Op[1] == Encoding::BaseTypeRef && + Desc.Op[0] == Encoding::Size1)) { + // This code assumes that the other non-typeref operand fits into 1 byte. + assert(OpOffset < Op.getEndOffset()); + uint32_t ULEBsize = Op.getEndOffset() - OpOffset - 1; + assert(ULEBsize <= 16); + + // Copy over the operation. + assert(!Op.getSubCode() && "SubOps not yet supported"); + OutputExpression.push_back(Op.getCode()); + uint64_t RefOffset; + if (Desc.Op.size() == 1) { + RefOffset = Op.getRawOperand(0); + } else { + OutputExpression.push_back(Op.getRawOperand(0)); + RefOffset = Op.getRawOperand(1); + } + uint8_t ULEB[16]; + uint32_t Offset = 0; + unsigned RealSize = 0; + // Look up the base type. For DW_OP_convert, the operand may be 0 to + // instead indicate the generic type. The same holds for + // DW_OP_reinterpret, which is currently not supported. + if (RefOffset > 0 || Op.getCode() != dwarf::DW_OP_convert) { + RefOffset += OrigUnit.getOffset(); + uint32_t RefDieIdx = 0; + if (std::optional<uint32_t> Idx = + OrigUnit.getDIEIndexForOffset(RefOffset)) + RefDieIdx = *Idx; + + // Use fixed size for ULEB128 data, since we need to update that size + // later with the proper offsets. Use 5 for DWARF32, 9 for DWARF64. + ULEBsize = getFormParams().getDwarfOffsetByteSize() + 1; + + RealSize = encodeULEB128(0xBADDEF, ULEB, ULEBsize); + + Section.notePatchWithOffsetUpdate( + DebugULEB128DieRefPatch(OutputExpression.size(), this, this, + RefDieIdx), + PatchesOffsets); + } else + RealSize = encodeULEB128(Offset, ULEB, ULEBsize); + + if (RealSize > ULEBsize) { + // Emit the generic type as a fallback. + RealSize = encodeULEB128(0, ULEB, ULEBsize); + warn("base type ref doesn't fit."); + } + assert(RealSize == ULEBsize && "padding failed"); + ArrayRef<uint8_t> ULEBbytes(ULEB, ULEBsize); + OutputExpression.append(ULEBbytes.begin(), ULEBbytes.end()); + } else if (!getGlobalData().getOptions().UpdateIndexTablesOnly && + Op.getCode() == dwarf::DW_OP_addrx) { + if (std::optional<object::SectionedAddress> SA = + OrigUnit.getAddrOffsetSectionItem(Op.getRawOperand(0))) { + // DWARFLinker does not use addrx forms since it generates relocated + // addresses. Replace DW_OP_addrx with DW_OP_addr here. + // Argument of DW_OP_addrx should be relocated here as it is not + // processed by applyValidRelocs. + OutputExpression.push_back(dwarf::DW_OP_addr); + uint64_t LinkedAddress = + SA->Address + (VarAddressAdjustment ? *VarAddressAdjustment : 0); + if (getEndianness() != llvm::endianness::native) + sys::swapByteOrder(LinkedAddress); + ArrayRef<uint8_t> AddressBytes( + reinterpret_cast<const uint8_t *>(&LinkedAddress), + OrigAddressByteSize); + OutputExpression.append(AddressBytes.begin(), AddressBytes.end()); + } else + warn("cann't read DW_OP_addrx operand."); + } else if (!getGlobalData().getOptions().UpdateIndexTablesOnly && + Op.getCode() == dwarf::DW_OP_constx) { + if (std::optional<object::SectionedAddress> SA = + OrigUnit.getAddrOffsetSectionItem(Op.getRawOperand(0))) { + // DWARFLinker does not use constx forms since it generates relocated + // addresses. Replace DW_OP_constx with DW_OP_const[*]u here. + // Argument of DW_OP_constx should be relocated here as it is not + // processed by applyValidRelocs. + std::optional<uint8_t> OutOperandKind; + switch (OrigAddressByteSize) { + case 2: + OutOperandKind = dwarf::DW_OP_const2u; + break; + case 4: + OutOperandKind = dwarf::DW_OP_const4u; + break; + case 8: + OutOperandKind = dwarf::DW_OP_const8u; + break; + default: + warn( + formatv(("unsupported address size: {0}."), OrigAddressByteSize)); + break; + } + + if (OutOperandKind) { + OutputExpression.push_back(*OutOperandKind); + uint64_t LinkedAddress = + SA->Address + (VarAddressAdjustment ? *VarAddressAdjustment : 0); + if (getEndianness() != llvm::endianness::native) + sys::swapByteOrder(LinkedAddress); + ArrayRef<uint8_t> AddressBytes( + reinterpret_cast<const uint8_t *>(&LinkedAddress), + OrigAddressByteSize); + OutputExpression.append(AddressBytes.begin(), AddressBytes.end()); + } + } else + warn("cann't read DW_OP_constx operand."); + } else { + // Copy over everything else unmodified. + StringRef Bytes = + InputExpression.getData().slice(OpOffset, Op.getEndOffset()); + OutputExpression.append(Bytes.begin(), Bytes.end()); + } + OpOffset = Op.getEndOffset(); + } +} + +Error CompileUnit::cloneAndEmit(std::optional<Triple> TargetTriple, + TypeUnit *ArtificialTypeUnit) { + BumpPtrAllocator Allocator; + + DWARFDie OrigUnitDIE = getOrigUnit().getUnitDIE(); + if (!OrigUnitDIE.isValid()) + return Error::success(); + + TypeEntry *RootEntry = nullptr; + if (ArtificialTypeUnit) + RootEntry = ArtificialTypeUnit->getTypePool().getRoot(); + + // Clone input DIE entry recursively. + std::pair<DIE *, TypeEntry *> OutCUDie = cloneDIE( + OrigUnitDIE.getDebugInfoEntry(), RootEntry, getDebugInfoHeaderSize(), + std::nullopt, std::nullopt, Allocator, ArtificialTypeUnit); + setOutUnitDIE(OutCUDie.first); + + if (getGlobalData().getOptions().NoOutput || (OutCUDie.first == nullptr)) + return Error::success(); + + assert(TargetTriple.has_value()); + if (Error Err = cloneAndEmitLineTable(*TargetTriple)) + return Err; + + if (Error Err = cloneAndEmitDebugMacro()) + return Err; + + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); + if (Error Err = emitDebugInfo(*TargetTriple)) + return Err; + + // ASSUMPTION: .debug_info section should already be emitted at this point. + // cloneAndEmitRanges & cloneAndEmitDebugLocations use .debug_info section + // data. + + if (Error Err = cloneAndEmitRanges()) + return Err; + + if (Error Err = cloneAndEmitDebugLocations()) + return Err; + + if (Error Err = emitDebugAddrSection()) + return Err; + + // Generate Pub accelerator tables. + if (llvm::is_contained(GlobalData.getOptions().AccelTables, + DWARFLinker::AccelTableKind::Pub)) + emitPubAccelerators(); + + if (Error Err = emitDebugStringOffsetSection()) + return Err; + + return emitAbbreviations(); +} + +std::pair<DIE *, TypeEntry *> CompileUnit::cloneDIE( + const DWARFDebugInfoEntry *InputDieEntry, TypeEntry *ClonedParentTypeDIE, + uint64_t OutOffset, std::optional<int64_t> FuncAddressAdjustment, + std::optional<int64_t> VarAddressAdjustment, BumpPtrAllocator &Allocator, + TypeUnit *ArtificialTypeUnit) { + uint32_t InputDieIdx = getDIEIndex(InputDieEntry); + CompileUnit::DIEInfo &Info = getDIEInfo(InputDieIdx); + + bool NeedToClonePlainDIE = Info.needToKeepInPlainDwarf(); + bool NeedToCloneTypeDIE = + (InputDieEntry->getTag() != dwarf::DW_TAG_compile_unit) && + Info.needToPlaceInTypeTable(); + std::pair<DIE *, TypeEntry *> ClonedDIE; + + DIEGenerator PlainDIEGenerator(Allocator, *this); + + if (NeedToClonePlainDIE) + // Create a cloned DIE which would be placed into the cloned version + // of input compile unit. + ClonedDIE.first = createPlainDIEandCloneAttributes( + InputDieEntry, PlainDIEGenerator, OutOffset, FuncAddressAdjustment, + VarAddressAdjustment); + if (NeedToCloneTypeDIE) { + // Create a cloned DIE which would be placed into the artificial type + // unit. + assert(ArtificialTypeUnit != nullptr); + DIEGenerator TypeDIEGenerator( + ArtificialTypeUnit->getTypePool().getThreadLocalAllocator(), *this); + + ClonedDIE.second = createTypeDIEandCloneAttributes( + InputDieEntry, TypeDIEGenerator, ClonedParentTypeDIE, + ArtificialTypeUnit); + } + TypeEntry *TypeParentForChild = + ClonedDIE.second ? ClonedDIE.second : ClonedParentTypeDIE; + + bool HasPlainChildrenToClone = + (ClonedDIE.first && Info.getKeepPlainChildren()); + + bool HasTypeChildrenToClone = + ((ClonedDIE.second || + InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) && + Info.getKeepTypeChildren()); + + // Recursively clone children. + if (HasPlainChildrenToClone || HasTypeChildrenToClone) { + for (const DWARFDebugInfoEntry *CurChild = + getFirstChildEntry(InputDieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = getSiblingEntry(CurChild)) { + std::pair<DIE *, TypeEntry *> ClonedChild = cloneDIE( + CurChild, TypeParentForChild, OutOffset, FuncAddressAdjustment, + VarAddressAdjustment, Allocator, ArtificialTypeUnit); + + if (ClonedChild.first) { + OutOffset = + ClonedChild.first->getOffset() + ClonedChild.first->getSize(); + PlainDIEGenerator.addChild(ClonedChild.first); + } + } + assert(ClonedDIE.first == nullptr || + HasPlainChildrenToClone == ClonedDIE.first->hasChildren()); + + // Account for the end of children marker. + if (HasPlainChildrenToClone) + OutOffset += sizeof(int8_t); + } + + // Update our size. + if (ClonedDIE.first != nullptr) + ClonedDIE.first->setSize(OutOffset - ClonedDIE.first->getOffset()); + + return ClonedDIE; +} + +DIE *CompileUnit::createPlainDIEandCloneAttributes( + const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &PlainDIEGenerator, + uint64_t &OutOffset, std::optional<int64_t> &FuncAddressAdjustment, + std::optional<int64_t> &VarAddressAdjustment) { + uint32_t InputDieIdx = getDIEIndex(InputDieEntry); + CompileUnit::DIEInfo &Info = getDIEInfo(InputDieIdx); + DIE *ClonedDIE = nullptr; + bool HasLocationExpressionAddress = false; + if (InputDieEntry->getTag() == dwarf::DW_TAG_subprogram) { + // Get relocation adjustment value for the current function. + FuncAddressAdjustment = + getContaingFile().Addresses->getSubprogramRelocAdjustment( + getDIE(InputDieEntry)); + } else if (InputDieEntry->getTag() == dwarf::DW_TAG_label) { + // Get relocation adjustment value for the current label. + std::optional<uint64_t> lowPC = + dwarf::toAddress(find(InputDieEntry, dwarf::DW_AT_low_pc)); + if (lowPC) { + LabelMapTy::iterator It = Labels.find(*lowPC); + if (It != Labels.end()) + FuncAddressAdjustment = It->second; + } + } else if (InputDieEntry->getTag() == dwarf::DW_TAG_variable) { + // Get relocation adjustment value for the current variable. + std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment = + getContaingFile().Addresses->getVariableRelocAdjustment( + getDIE(InputDieEntry)); + + HasLocationExpressionAddress = LocExprAddrAndRelocAdjustment.first; + if (LocExprAddrAndRelocAdjustment.first && + LocExprAddrAndRelocAdjustment.second) + VarAddressAdjustment = *LocExprAddrAndRelocAdjustment.second; + } + + ClonedDIE = PlainDIEGenerator.createDIE(InputDieEntry->getTag(), OutOffset); + + // Offset to the DIE would be used after output DIE tree is deleted. + // Thus we need to remember DIE offset separately. + rememberDieOutOffset(InputDieIdx, OutOffset); + + // Clone Attributes. + DIEAttributeCloner AttributesCloner(ClonedDIE, *this, this, InputDieEntry, + PlainDIEGenerator, FuncAddressAdjustment, + VarAddressAdjustment, + HasLocationExpressionAddress); + AttributesCloner.clone(); + + // Remember accelerator info. + AcceleratorRecordsSaver AccelRecordsSaver(getGlobalData(), *this, this); + AccelRecordsSaver.save(InputDieEntry, ClonedDIE, AttributesCloner.AttrInfo, + nullptr); + + OutOffset = + AttributesCloner.finalizeAbbreviations(Info.getKeepPlainChildren()); + + return ClonedDIE; +} + +/// Allocates output DIE for the specified \p TypeDescriptor. +DIE *CompileUnit::allocateTypeDie(TypeEntryBody *TypeDescriptor, + DIEGenerator &TypeDIEGenerator, + dwarf::Tag DieTag, bool IsDeclaration, + bool IsParentDeclaration) { + DIE *DefinitionDie = TypeDescriptor->Die; + // Do not allocate any new DIE if definition DIE is already met. + if (DefinitionDie) + return nullptr; + + DIE *DeclarationDie = TypeDescriptor->DeclarationDie; + bool OldParentIsDeclaration = TypeDescriptor->ParentIsDeclaration; + + if (IsDeclaration && !DeclarationDie) { + // Alocate declaration DIE. + DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0); + if (TypeDescriptor->DeclarationDie.compare_exchange_weak(DeclarationDie, + NewDie)) + return NewDie; + } else if (IsDeclaration && !IsParentDeclaration && OldParentIsDeclaration) { + // Overwrite existing declaration DIE if it's parent is also an declaration + // while parent of current declaration DIE is a definition. + if (TypeDescriptor->ParentIsDeclaration.compare_exchange_weak( + OldParentIsDeclaration, false)) { + DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0); + TypeDescriptor->DeclarationDie = NewDie; + return NewDie; + } + } else if (!IsDeclaration && IsParentDeclaration && !DeclarationDie) { + // Alocate declaration DIE since parent of current DIE is marked as + // declaration. + DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0); + if (TypeDescriptor->DeclarationDie.compare_exchange_weak(DeclarationDie, + NewDie)) + return NewDie; + } else if (!IsDeclaration && !IsParentDeclaration) { + // Allocate definition DIE. + DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0); + if (TypeDescriptor->Die.compare_exchange_weak(DefinitionDie, NewDie)) { + TypeDescriptor->ParentIsDeclaration = false; + return NewDie; + } + } + + return nullptr; +} + +TypeEntry *CompileUnit::createTypeDIEandCloneAttributes( + const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &TypeDIEGenerator, + TypeEntry *ClonedParentTypeDIE, TypeUnit *ArtificialTypeUnit) { + assert(ArtificialTypeUnit != nullptr); + uint32_t InputDieIdx = getDIEIndex(InputDieEntry); + + TypeEntry *Entry = getDieTypeEntry(InputDieIdx); + assert(Entry != nullptr); + assert(ClonedParentTypeDIE != nullptr); + TypeEntryBody *EntryBody = + ArtificialTypeUnit->getTypePool().getOrCreateTypeEntryBody( + Entry, ClonedParentTypeDIE); + assert(EntryBody); + + bool IsDeclaration = + dwarf::toUnsigned(find(InputDieEntry, dwarf::DW_AT_declaration), 0); + + bool ParentIsDeclaration = false; + if (std::optional<uint32_t> ParentIdx = InputDieEntry->getParentIdx()) + ParentIsDeclaration = + dwarf::toUnsigned(find(*ParentIdx, dwarf::DW_AT_declaration), 0); + + DIE *OutDIE = + allocateTypeDie(EntryBody, TypeDIEGenerator, InputDieEntry->getTag(), + IsDeclaration, ParentIsDeclaration); + + if (OutDIE != nullptr) { + assert(ArtificialTypeUnit != nullptr); + ArtificialTypeUnit->getSectionDescriptor(DebugSectionKind::DebugInfo); + + DIEAttributeCloner AttributesCloner(OutDIE, *this, ArtificialTypeUnit, + InputDieEntry, TypeDIEGenerator, + std::nullopt, std::nullopt, false); + AttributesCloner.clone(); + + // Remember accelerator info. + AcceleratorRecordsSaver AccelRecordsSaver(getGlobalData(), *this, + ArtificialTypeUnit); + AccelRecordsSaver.save(InputDieEntry, OutDIE, AttributesCloner.AttrInfo, + Entry); + + // if AttributesCloner.getOutOffset() == 0 then we need to add + // 1 to avoid assertion for zero size. We will subtract it back later. + OutDIE->setSize(AttributesCloner.getOutOffset() + 1); + } + + return Entry; +} + +Error CompileUnit::cloneAndEmitLineTable(Triple &TargetTriple) { + const DWARFDebugLine::LineTable *InputLineTable = + getContaingFile().Dwarf->getLineTableForUnit(&getOrigUnit()); + if (InputLineTable == nullptr) { + if (getOrigUnit().getUnitDIE().find(dwarf::DW_AT_stmt_list)) + warn("cann't load line table."); + return Error::success(); + } + + DWARFDebugLine::LineTable OutLineTable; + + // Set Line Table header. + OutLineTable.Prologue = InputLineTable->Prologue; + OutLineTable.Prologue.FormParams.AddrSize = getFormParams().AddrSize; + + // Set Line Table Rows. + if (getGlobalData().getOptions().UpdateIndexTablesOnly) { + OutLineTable.Rows = InputLineTable->Rows; + // If all the line table contains is a DW_LNE_end_sequence, clear the line + // table rows, it will be inserted again in the DWARFStreamer. + if (OutLineTable.Rows.size() == 1 && OutLineTable.Rows[0].EndSequence) + OutLineTable.Rows.clear(); + + OutLineTable.Sequences = InputLineTable->Sequences; + } else { + // This vector is the output line table. + std::vector<DWARFDebugLine::Row> NewRows; + NewRows.reserve(InputLineTable->Rows.size()); + + // Current sequence of rows being extracted, before being inserted + // in NewRows. + std::vector<DWARFDebugLine::Row> Seq; + + const auto &FunctionRanges = getFunctionRanges(); + std::optional<AddressRangeValuePair> CurrRange; + + // FIXME: This logic is meant to generate exactly the same output as + // Darwin's classic dsymutil. There is a nicer way to implement this + // by simply putting all the relocated line info in NewRows and simply + // sorting NewRows before passing it to emitLineTableForUnit. This + // should be correct as sequences for a function should stay + // together in the sorted output. There are a few corner cases that + // look suspicious though, and that required to implement the logic + // this way. Revisit that once initial validation is finished. + + // Iterate over the object file line info and extract the sequences + // that correspond to linked functions. + for (DWARFDebugLine::Row Row : InputLineTable->Rows) { + // Check whether we stepped out of the range. The range is + // half-open, but consider accept the end address of the range if + // it is marked as end_sequence in the input (because in that + // case, the relocation offset is accurate and that entry won't + // serve as the start of another function). + if (!CurrRange || !CurrRange->Range.contains(Row.Address.Address)) { + // We just stepped out of a known range. Insert a end_sequence + // corresponding to the end of the range. + uint64_t StopAddress = + CurrRange ? CurrRange->Range.end() + CurrRange->Value : -1ULL; + CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address); + if (StopAddress != -1ULL && !Seq.empty()) { + // Insert end sequence row with the computed end address, but + // the same line as the previous one. + auto NextLine = Seq.back(); + NextLine.Address.Address = StopAddress; + NextLine.EndSequence = 1; + NextLine.PrologueEnd = 0; + NextLine.BasicBlock = 0; + NextLine.EpilogueBegin = 0; + Seq.push_back(NextLine); + insertLineSequence(Seq, NewRows); + } + + if (!CurrRange) + continue; + } + + // Ignore empty sequences. + if (Row.EndSequence && Seq.empty()) + continue; + + // Relocate row address and add it to the current sequence. + Row.Address.Address += CurrRange->Value; + Seq.emplace_back(Row); + + if (Row.EndSequence) + insertLineSequence(Seq, NewRows); + } + + OutLineTable.Rows = std::move(NewRows); + } + + return emitDebugLine(TargetTriple, OutLineTable); +} + +void CompileUnit::insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq, + std::vector<DWARFDebugLine::Row> &Rows) { + if (Seq.empty()) + return; + + if (!Rows.empty() && Rows.back().Address < Seq.front().Address) { + llvm::append_range(Rows, Seq); + Seq.clear(); + return; + } + + object::SectionedAddress Front = Seq.front().Address; + auto InsertPoint = partition_point( + Rows, [=](const DWARFDebugLine::Row &O) { return O.Address < Front; }); + + // FIXME: this only removes the unneeded end_sequence if the + // sequences have been inserted in order. Using a global sort like + // described in cloneAndEmitLineTable() and delaying the end_sequene + // elimination to DebugLineEmitter::emit() we can get rid of all of them. + if (InsertPoint != Rows.end() && InsertPoint->Address == Front && + InsertPoint->EndSequence) { + *InsertPoint = Seq.front(); + Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end()); + } else { + Rows.insert(InsertPoint, Seq.begin(), Seq.end()); + } + + Seq.clear(); +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() { + llvm::errs() << "{"; + llvm::errs() << " Placement: "; + switch (getPlacement()) { + case NotSet: + llvm::errs() << "NotSet"; + break; + case TypeTable: + llvm::errs() << "TypeTable"; + break; + case PlainDwarf: + llvm::errs() << "PlainDwarf"; + break; + case Both: + llvm::errs() << "Both"; + break; + } + + llvm::errs() << " Keep: " << getKeep(); + llvm::errs() << " KeepPlainChildren: " << getKeepPlainChildren(); + llvm::errs() << " KeepTypeChildren: " << getKeepTypeChildren(); + llvm::errs() << " IsInMouduleScope: " << getIsInMouduleScope(); + llvm::errs() << " IsInFunctionScope: " << getIsInFunctionScope(); + llvm::errs() << " IsInAnonNamespaceScope: " << getIsInAnonNamespaceScope(); + llvm::errs() << " ODRAvailable: " << getODRAvailable(); + llvm::errs() << " TrackLiveness: " << getTrackLiveness(); + llvm::errs() << "}\n"; +} +#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + +std::optional<std::pair<StringRef, StringRef>> +CompileUnit::getDirAndFilenameFromLineTable( + const DWARFFormValue &FileIdxValue) { + uint64_t FileIdx; + if (std::optional<uint64_t> Val = FileIdxValue.getAsUnsignedConstant()) + FileIdx = *Val; + else if (std::optional<int64_t> Val = FileIdxValue.getAsSignedConstant()) + FileIdx = *Val; + else if (std::optional<uint64_t> Val = FileIdxValue.getAsSectionOffset()) + FileIdx = *Val; + else + return std::nullopt; + + return getDirAndFilenameFromLineTable(FileIdx); +} + +static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) { + // Debug info can contain paths from any OS, not necessarily + // an OS we're currently running on. Moreover different compilation units can + // be compiled on different operating systems and linked together later. + return sys::path::is_absolute(Path, sys::path::Style::posix) || + sys::path::is_absolute(Path, sys::path::Style::windows); +} + +std::optional<std::pair<StringRef, StringRef>> +CompileUnit::getDirAndFilenameFromLineTable(uint64_t FileIdx) { + FileNamesCache::iterator FileData = FileNames.find(FileIdx); + if (FileData != FileNames.end()) + return std::make_pair(StringRef(FileData->second.first), + StringRef(FileData->second.second)); + + if (const DWARFDebugLine::LineTable *LineTable = + getOrigUnit().getContext().getLineTableForUnit(&getOrigUnit())) { + if (LineTable->hasFileAtIndex(FileIdx)) { + + const llvm::DWARFDebugLine::FileNameEntry &Entry = + LineTable->Prologue.getFileNameEntry(FileIdx); + + Expected<const char *> Name = Entry.Name.getAsCString(); + if (!Name) { + warn(Name.takeError()); + return std::nullopt; + } + + std::string FileName = *Name; + if (isPathAbsoluteOnWindowsOrPosix(FileName)) { + FileNamesCache::iterator FileData = + FileNames + .insert(std::make_pair( + FileIdx, + std::make_pair(std::string(""), std::move(FileName)))) + .first; + return std::make_pair(StringRef(FileData->second.first), + StringRef(FileData->second.second)); + } + + SmallString<256> FilePath; + StringRef IncludeDir; + // Be defensive about the contents of Entry. + if (getVersion() >= 5) { + // DirIdx 0 is the compilation directory, so don't include it for + // relative names. + if ((Entry.DirIdx != 0) && + Entry.DirIdx < LineTable->Prologue.IncludeDirectories.size()) { + Expected<const char *> DirName = + LineTable->Prologue.IncludeDirectories[Entry.DirIdx] + .getAsCString(); + if (DirName) + IncludeDir = *DirName; + else { + warn(DirName.takeError()); + return std::nullopt; + } + } + } else { + if (0 < Entry.DirIdx && + Entry.DirIdx <= LineTable->Prologue.IncludeDirectories.size()) { + Expected<const char *> DirName = + LineTable->Prologue.IncludeDirectories[Entry.DirIdx - 1] + .getAsCString(); + if (DirName) + IncludeDir = *DirName; + else { + warn(DirName.takeError()); + return std::nullopt; + } + } + } + + StringRef CompDir = getOrigUnit().getCompilationDir(); + + if (!CompDir.empty() && !isPathAbsoluteOnWindowsOrPosix(IncludeDir)) { + sys::path::append(FilePath, sys::path::Style::native, CompDir); + } + + sys::path::append(FilePath, sys::path::Style::native, IncludeDir); + + FileNamesCache::iterator FileData = + FileNames + .insert( + std::make_pair(FileIdx, std::make_pair(std::string(FilePath), + std::move(FileName)))) + .first; + return std::make_pair(StringRef(FileData->second.first), + StringRef(FileData->second.second)); + } + } + + return std::nullopt; +} + +#define MAX_REFERENCIES_DEPTH 1000 +UnitEntryPairTy UnitEntryPairTy::getNamespaceOrigin() { + UnitEntryPairTy CUDiePair(*this); + std::optional<UnitEntryPairTy> RefDiePair; + int refDepth = 0; + do { + RefDiePair = CUDiePair.CU->resolveDIEReference( + CUDiePair.DieEntry, dwarf::DW_AT_extension, + ResolveInterCUReferencesMode::Resolve); + if (!RefDiePair || !RefDiePair->DieEntry) + return CUDiePair; + + CUDiePair = *RefDiePair; + } while (refDepth++ < MAX_REFERENCIES_DEPTH); + + return CUDiePair; +} + +std::optional<UnitEntryPairTy> UnitEntryPairTy::getParent() { + if (std::optional<uint32_t> ParentIdx = DieEntry->getParentIdx()) + return UnitEntryPairTy{CU, CU->getDebugInfoEntry(*ParentIdx)}; + + return std::nullopt; +} + +CompileUnit::OutputUnitVariantPtr::OutputUnitVariantPtr(CompileUnit *U) + : Ptr(U) { + assert(U != nullptr); +} + +CompileUnit::OutputUnitVariantPtr::OutputUnitVariantPtr(TypeUnit *U) : Ptr(U) { + assert(U != nullptr); +} + +DwarfUnit *CompileUnit::OutputUnitVariantPtr::operator->() { + if (isCompileUnit()) + return getAsCompileUnit(); + else + return getAsTypeUnit(); +} + +bool CompileUnit::OutputUnitVariantPtr::isCompileUnit() { + return Ptr.is<CompileUnit *>(); +} + +bool CompileUnit::OutputUnitVariantPtr::isTypeUnit() { + return Ptr.is<TypeUnit *>(); +} + +CompileUnit *CompileUnit::OutputUnitVariantPtr::getAsCompileUnit() { + return Ptr.get<CompileUnit *>(); +} + +TypeUnit *CompileUnit::OutputUnitVariantPtr::getAsTypeUnit() { + return Ptr.get<TypeUnit *>(); +} + +bool CompileUnit::resolveDependenciesAndMarkLiveness( + bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) { + if (!Dependencies.get()) + Dependencies.reset(new DependencyTracker(*this)); + + return Dependencies->resolveDependenciesAndMarkLiveness( + InterCUProcessingStarted, HasNewInterconnectedCUs); +} + +bool CompileUnit::updateDependenciesCompleteness() { + assert(Dependencies.get()); + + return Dependencies.get()->updateDependenciesCompleteness(); +} + +void CompileUnit::verifyDependencies() { + assert(Dependencies.get()); + + Dependencies.get()->verifyKeepChain(); +} + +ArrayRef<dwarf::Attribute> dwarf_linker::parallel::getODRAttributes() { + static dwarf::Attribute ODRAttributes[] = { + dwarf::DW_AT_type, dwarf::DW_AT_specification, + dwarf::DW_AT_abstract_origin, dwarf::DW_AT_import}; + + return ODRAttributes; +} |
