diff options
author | Alexey Lapshin <a.v.lapshin@mail.ru> | 2019-12-20 19:23:31 +0300 |
---|---|---|
committer | Alexey Lapshin <a.v.lapshin@mail.ru> | 2020-01-08 14:15:31 +0300 |
commit | 1cf11a4c67a15ab5493ef424c898accf49012caa (patch) | |
tree | 725e9007d55d84e3ad27af22222ebbcda6ef6043 /llvm/tools | |
parent | 96d2d96b03ff590867cd6578eb7f6d32770cbbf0 (diff) | |
download | bcm5719-llvm-1cf11a4c67a15ab5493ef424c898accf49012caa.tar.gz bcm5719-llvm-1cf11a4c67a15ab5493ef424c898accf49012caa.zip |
[Dsymutil][Debuginfo][NFC] Reland: Refactor dsymutil to separate DWARF optimizing part. #2.
Summary:
This patch relands D71271. The problem with D71271 is that it has cyclic dependency:
CodeGen->AsmPrinter->DebugInfoDWARF->CodeGen. To avoid cyclic dependency this patch
puts implementation for DWARFOptimizer into separate library: lib/DWARFLinker.
Thus the difference between this patch and D71271 is in that DWARFOptimizer renamed into
DWARFLinker and it`s files are put into lib/DWARFLinker.
Reviewers: JDevlieghere, friss, dblaikie, aprantl
Reviewed By: JDevlieghere
Subscribers: thegameg, merge_guards_bot, probinson, mgorny, hiraditya, llvm-commits
Tags: #llvm, #debug-info
Differential Revision: https://reviews.llvm.org/D71839
Diffstat (limited to 'llvm/tools')
-rw-r--r-- | llvm/tools/dsymutil/CMakeLists.txt | 5 | ||||
-rw-r--r-- | llvm/tools/dsymutil/CompileUnit.cpp | 146 | ||||
-rw-r--r-- | llvm/tools/dsymutil/CompileUnit.h | 331 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DeclContext.cpp | 210 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DeclContext.h | 171 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfLinkerForBinary.cpp (renamed from llvm/tools/dsymutil/DwarfLinker.cpp) | 254 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfLinkerForBinary.h (renamed from llvm/tools/dsymutil/DwarfLinker.h) | 118 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfStreamer.cpp | 2 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfStreamer.h | 2 | ||||
-rw-r--r-- | llvm/tools/dsymutil/LLVMBuild.txt | 2 |
10 files changed, 193 insertions, 1048 deletions
diff --git a/llvm/tools/dsymutil/CMakeLists.txt b/llvm/tools/dsymutil/CMakeLists.txt index b8466baa634..fecd8a61ad0 100644 --- a/llvm/tools/dsymutil/CMakeLists.txt +++ b/llvm/tools/dsymutil/CMakeLists.txt @@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS AllTargetsInfos AsmPrinter DebugInfoDWARF + DWARFLinker MC Object CodeGen @@ -22,10 +23,8 @@ add_llvm_tool(dsymutil dsymutil.cpp BinaryHolder.cpp CFBundle.cpp - CompileUnit.cpp DebugMap.cpp - DeclContext.cpp - DwarfLinker.cpp + DwarfLinkerForBinary.cpp DwarfStreamer.cpp MachODebugMapParser.cpp MachOUtils.cpp diff --git a/llvm/tools/dsymutil/CompileUnit.cpp b/llvm/tools/dsymutil/CompileUnit.cpp deleted file mode 100644 index 036c61a6b92..00000000000 --- a/llvm/tools/dsymutil/CompileUnit.cpp +++ /dev/null @@ -1,146 +0,0 @@ -//===- tools/dsymutil/CompileUnit.h - Dwarf compile unit ------------------===// -// -// 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 "CompileUnit.h" -#include "DeclContext.h" - -namespace llvm { -namespace dsymutil { - -/// Check if the DIE at \p Idx is in the scope of a function. -static bool inFunctionScope(CompileUnit &U, unsigned Idx) { - while (Idx) { - if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram) - return true; - Idx = U.getInfo(Idx).ParentIdx; - } - return false; -} - -uint16_t CompileUnit::getLanguage() { - if (!Language) { - DWARFDie CU = getOrigUnit().getUnitDIE(); - Language = dwarf::toUnsigned(CU.find(dwarf::DW_AT_language), 0); - } - return Language; -} - -void CompileUnit::markEverythingAsKept() { - unsigned Idx = 0; - - setHasInterestingContent(); - - for (auto &I : Info) { - // Mark everything that wasn't explicit marked for pruning. - I.Keep = !I.Prune; - auto DIE = OrigUnit.getDIEAtIndex(Idx++); - - // Try to guess which DIEs must go to the accelerator tables. We do that - // just for variables, because functions will be handled depending on - // whether they carry a DW_AT_low_pc attribute or not. - if (DIE.getTag() != dwarf::DW_TAG_variable && - DIE.getTag() != dwarf::DW_TAG_constant) - continue; - - Optional<DWARFFormValue> Value; - if (!(Value = DIE.find(dwarf::DW_AT_location))) { - if ((Value = DIE.find(dwarf::DW_AT_const_value)) && - !inFunctionScope(*this, I.ParentIdx)) - I.InDebugMap = true; - continue; - } - if (auto Block = Value->getAsBlock()) { - if (Block->size() > OrigUnit.getAddressByteSize() && - (*Block)[0] == dwarf::DW_OP_addr) - I.InDebugMap = true; - } - } -} - -uint64_t CompileUnit::computeNextUnitOffset() { - NextUnitOffset = StartOffset; - if (NewUnit) { - NextUnitOffset += 11 /* Header size */; - NextUnitOffset += NewUnit->getUnitDie().getSize(); - } - return NextUnitOffset; -} - -/// Keep track of a forward cross-cu reference from this unit -/// to \p Die that lives in \p RefUnit. -void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit, - DeclContext *Ctxt, PatchLocation Attr) { - ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr); -} - -void CompileUnit::fixupForwardReferences() { - for (const auto &Ref : ForwardDIEReferences) { - DIE *RefDie; - const CompileUnit *RefUnit; - PatchLocation Attr; - DeclContext *Ctxt; - std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref; - if (Ctxt && Ctxt->getCanonicalDIEOffset()) - Attr.set(Ctxt->getCanonicalDIEOffset()); - else - Attr.set(RefDie->getOffset() + RefUnit->getStartOffset()); - } -} - -void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) { - Labels.insert({LabelLowPc, PcOffset}); -} - -void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, - int64_t PcOffset) { - // Don't add empty ranges to the interval map. They are a problem because - // the interval map expects half open intervals. This is safe because they - // are empty anyway. - if (FuncHighPc != FuncLowPc) - Ranges.insert(FuncLowPc, FuncHighPc, PcOffset); - this->LowPc = std::min(LowPc, FuncLowPc + PcOffset); - this->HighPc = std::max(HighPc, FuncHighPc + PcOffset); -} - -void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) { - if (Die.getTag() != dwarf::DW_TAG_compile_unit) - RangeAttributes.push_back(Attr); - else - UnitRangeAttribute = Attr; -} - -void CompileUnit::noteLocationAttribute(PatchLocation Attr, int64_t PcOffset) { - LocationAttributes.emplace_back(Attr, PcOffset); -} - -void CompileUnit::addNamespaceAccelerator(const DIE *Die, - DwarfStringPoolEntryRef Name) { - Namespaces.emplace_back(Name, Die); -} - -void CompileUnit::addObjCAccelerator(const DIE *Die, - DwarfStringPoolEntryRef Name, - bool SkipPubSection) { - ObjC.emplace_back(Name, Die, SkipPubSection); -} - -void CompileUnit::addNameAccelerator(const DIE *Die, - DwarfStringPoolEntryRef Name, - bool SkipPubSection) { - Pubnames.emplace_back(Name, Die, SkipPubSection); -} - -void CompileUnit::addTypeAccelerator(const DIE *Die, - DwarfStringPoolEntryRef Name, - bool ObjcClassImplementation, - uint32_t QualifiedNameHash) { - Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation); -} - -} // namespace dsymutil -} // namespace llvm diff --git a/llvm/tools/dsymutil/CompileUnit.h b/llvm/tools/dsymutil/CompileUnit.h deleted file mode 100644 index e0f5d3bc65b..00000000000 --- a/llvm/tools/dsymutil/CompileUnit.h +++ /dev/null @@ -1,331 +0,0 @@ -//===- tools/dsymutil/CompileUnit.h - Dwarf debug info linker ---*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_DSYMUTIL_COMPILEUNIT_H -#define LLVM_TOOLS_DSYMUTIL_COMPILEUNIT_H - -#include "llvm/ADT/IntervalMap.h" -#include "llvm/CodeGen/DIE.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" - -namespace llvm { -namespace dsymutil { - -class DeclContext; - -template <typename KeyT, typename ValT> -using HalfOpenIntervalMap = - IntervalMap<KeyT, ValT, IntervalMapImpl::NodeSizer<KeyT, ValT>::LeafSize, - IntervalMapHalfOpenInfo<KeyT>>; - -using FunctionIntervals = HalfOpenIntervalMap<uint64_t, int64_t>; - -// FIXME: Delete this structure. -struct PatchLocation { - DIE::value_iterator I; - - PatchLocation() = default; - PatchLocation(DIE::value_iterator I) : I(I) {} - - void set(uint64_t New) const { - assert(I); - const auto &Old = *I; - assert(Old.getType() == DIEValue::isInteger); - *I = DIEValue(Old.getAttribute(), Old.getForm(), DIEInteger(New)); - } - - uint64_t get() const { - assert(I); - return I->getDIEInteger().getValue(); - } -}; - -/// Stores all information relating to a compile unit, be it in its original -/// instance in the object file to its brand new cloned and linked DIE tree. -class CompileUnit { -public: - /// Information gathered about a DIE in the object file. - struct DIEInfo { - /// Address offset to apply to the described entity. - int64_t AddrAdjust; - - /// ODR Declaration context. - DeclContext *Ctxt; - - /// Cloned version of that DIE. - DIE *Clone; - - /// The index of this DIE's parent. - uint32_t ParentIdx; - - /// Is the DIE part of the linked output? - bool Keep : 1; - - /// Was this DIE's entity found in the map? - bool InDebugMap : 1; - - /// Is this a pure forward declaration we can strip? - bool Prune : 1; - - /// Does DIE transitively refer an incomplete decl? - bool Incomplete : 1; - }; - - CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR, - StringRef ClangModuleName) - : OrigUnit(OrigUnit), ID(ID), Ranges(RangeAlloc), - ClangModuleName(ClangModuleName) { - Info.resize(OrigUnit.getNumDIEs()); - - auto CUDie = OrigUnit.getUnitDIE(false); - if (!CUDie) { - HasODR = false; - return; - } - if (auto Lang = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language))) - HasODR = CanUseODR && (*Lang == dwarf::DW_LANG_C_plus_plus || - *Lang == dwarf::DW_LANG_C_plus_plus_03 || - *Lang == dwarf::DW_LANG_C_plus_plus_11 || - *Lang == dwarf::DW_LANG_C_plus_plus_14 || - *Lang == dwarf::DW_LANG_ObjC_plus_plus); - else - HasODR = false; - } - - DWARFUnit &getOrigUnit() const { return OrigUnit; } - - unsigned getUniqueID() const { return ID; } - - void createOutputDIE() { - NewUnit.emplace(OrigUnit.getVersion(), OrigUnit.getAddressByteSize(), - OrigUnit.getUnitDIE().getTag()); - } - - DIE *getOutputUnitDIE() const { - if (NewUnit) - return &const_cast<BasicDIEUnit &>(*NewUnit).getUnitDie(); - return nullptr; - } - - bool hasODR() const { return HasODR; } - bool isClangModule() const { return !ClangModuleName.empty(); } - uint16_t getLanguage(); - - const std::string &getClangModuleName() const { return ClangModuleName; } - - DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; } - const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; } - - uint64_t getStartOffset() const { return StartOffset; } - uint64_t getNextUnitOffset() const { return NextUnitOffset; } - void setStartOffset(uint64_t DebugInfoSize) { StartOffset = DebugInfoSize; } - - uint64_t getLowPc() const { return LowPc; } - uint64_t getHighPc() const { return HighPc; } - bool hasLabelAt(uint64_t Addr) const { return Labels.count(Addr); } - - Optional<PatchLocation> getUnitRangesAttribute() const { - return UnitRangeAttribute; - } - - const FunctionIntervals &getFunctionRanges() const { return Ranges; } - - const std::vector<PatchLocation> &getRangesAttributes() const { - return RangeAttributes; - } - - const std::vector<std::pair<PatchLocation, int64_t>> & - getLocationAttributes() const { - return LocationAttributes; - } - - void setHasInterestingContent() { HasInterestingContent = true; } - bool hasInterestingContent() { return HasInterestingContent; } - - /// Mark every DIE in this unit as kept. This function also - /// marks variables as InDebugMap so that they appear in the - /// reconstructed accelerator tables. - void markEverythingAsKept(); - - /// Compute the end offset for this unit. Must be called after the CU's DIEs - /// have been cloned. \returns the next unit offset (which is also the - /// current debug_info section size). - uint64_t computeNextUnitOffset(); - - /// Keep track of a forward reference to DIE \p Die in \p RefUnit by \p - /// Attr. The attribute should be fixed up later to point to the absolute - /// offset of \p Die in the debug_info section or to the canonical offset of - /// \p Ctxt if it is non-null. - void noteForwardReference(DIE *Die, const CompileUnit *RefUnit, - DeclContext *Ctxt, PatchLocation Attr); - - /// Apply all fixups recorded by noteForwardReference(). - void fixupForwardReferences(); - - /// Add the low_pc of a label that is relocated by applying - /// offset \p PCOffset. - void addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset); - - /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying - /// offset \p PCOffset. - void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset); - - /// Keep track of a DW_AT_range attribute that we will need to patch up later. - void noteRangeAttribute(const DIE &Die, PatchLocation Attr); - - /// Keep track of a location attribute pointing to a location list in the - /// debug_loc section. - void noteLocationAttribute(PatchLocation Attr, int64_t PcOffset); - - /// Add a name accelerator entry for \a Die with \a Name. - void addNamespaceAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name); - - /// Add a name accelerator entry for \a Die with \a Name. - void addNameAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, - bool SkipPubnamesSection = false); - - /// Add various accelerator entries for \p Die with \p Name which is stored - /// in the string table at \p Offset. \p Name must be an Objective-C - /// selector. - void addObjCAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, - bool SkipPubnamesSection = false); - - /// Add a type accelerator entry for \p Die with \p Name which is stored in - /// the string table at \p Offset. - void addTypeAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, - bool ObjcClassImplementation, - uint32_t QualifiedNameHash); - - struct AccelInfo { - /// Name of the entry. - DwarfStringPoolEntryRef Name; - - /// DIE this entry describes. - const DIE *Die; - - /// Hash of the fully qualified name. - uint32_t QualifiedNameHash; - - /// Emit this entry only in the apple_* sections. - bool SkipPubSection; - - /// Is this an ObjC class implementation? - bool ObjcClassImplementation; - - AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die, - bool SkipPubSection = false) - : Name(Name), Die(Die), SkipPubSection(SkipPubSection) {} - - AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die, - uint32_t QualifiedNameHash, bool ObjCClassIsImplementation) - : Name(Name), Die(Die), QualifiedNameHash(QualifiedNameHash), - SkipPubSection(false), - ObjcClassImplementation(ObjCClassIsImplementation) {} - }; - - const std::vector<AccelInfo> &getPubnames() const { return Pubnames; } - const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; } - const std::vector<AccelInfo> &getNamespaces() const { return Namespaces; } - const std::vector<AccelInfo> &getObjC() const { return ObjC; } - - /// Get the full path for file \a FileNum in the line table - StringRef getResolvedPath(unsigned FileNum) { - if (FileNum >= ResolvedPaths.size()) - return StringRef(); - return ResolvedPaths[FileNum]; - } - - /// Set the fully resolved path for the line-table's file \a FileNum - /// to \a Path. - void setResolvedPath(unsigned FileNum, StringRef Path) { - if (ResolvedPaths.size() <= FileNum) - ResolvedPaths.resize(FileNum + 1); - ResolvedPaths[FileNum] = Path; - } - - MCSymbol *getLabelBegin() { return LabelBegin; } - void setLabelBegin(MCSymbol *S) { LabelBegin = S; } - -private: - DWARFUnit &OrigUnit; - unsigned ID; - std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index. - Optional<BasicDIEUnit> NewUnit; - MCSymbol *LabelBegin = nullptr; - - uint64_t StartOffset; - uint64_t NextUnitOffset; - - uint64_t LowPc = std::numeric_limits<uint64_t>::max(); - uint64_t HighPc = 0; - - /// A list of attributes to fixup with the absolute offset of - /// a DIE in the debug_info section. - /// - /// The offsets for the attributes in this array couldn't be set while - /// cloning because for cross-cu forward references the target DIE's offset - /// isn't known you emit the reference attribute. - std::vector< - std::tuple<DIE *, const CompileUnit *, DeclContext *, PatchLocation>> - ForwardDIEReferences; - - FunctionIntervals::Allocator RangeAlloc; - - /// The ranges in that interval map are the PC ranges for - /// functions in this unit, associated with the PC offset to apply - /// to the addresses to get the linked address. - FunctionIntervals Ranges; - - /// The DW_AT_low_pc of each DW_TAG_label. - SmallDenseMap<uint64_t, uint64_t, 1> Labels; - - /// DW_AT_ranges attributes to patch after we have gathered - /// all the unit's function addresses. - /// @{ - std::vector<PatchLocation> RangeAttributes; - Optional<PatchLocation> UnitRangeAttribute; - /// @} - - /// Location attributes that need to be transferred from the - /// original debug_loc section to the liked one. They are stored - /// along with the PC offset that is to be applied to their - /// function's address. - std::vector<std::pair<PatchLocation, int64_t>> LocationAttributes; - - /// Accelerator entries for the unit, both for the pub* - /// sections and the apple* ones. - /// @{ - std::vector<AccelInfo> Pubnames; - std::vector<AccelInfo> Pubtypes; - std::vector<AccelInfo> Namespaces; - std::vector<AccelInfo> ObjC; - /// @} - - /// Cached resolved paths from the line table. - /// Note, the StringRefs here point in to the intern (uniquing) string pool. - /// This means that a StringRef returned here doesn't need to then be uniqued - /// for the purposes of getting a unique address for each string. - std::vector<StringRef> ResolvedPaths; - - /// Is this unit subject to the ODR rule? - bool HasODR; - - /// Did a DIE actually contain a valid reloc? - bool HasInterestingContent; - - /// The DW_AT_language of this unit. - uint16_t Language = 0; - - /// If this is a Clang module, this holds the module's name. - std::string ClangModuleName; -}; - -} // end namespace dsymutil -} // end namespace llvm - -#endif // LLVM_TOOLS_DSYMUTIL_COMPILEUNIT_H diff --git a/llvm/tools/dsymutil/DeclContext.cpp b/llvm/tools/dsymutil/DeclContext.cpp deleted file mode 100644 index 1c33b672c26..00000000000 --- a/llvm/tools/dsymutil/DeclContext.cpp +++ /dev/null @@ -1,210 +0,0 @@ -//===- tools/dsymutil/DeclContext.cpp - Declaration context ---------------===// -// -// 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 "DeclContext.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" - -namespace llvm { -namespace dsymutil { - -/// Set the last DIE/CU a context was seen in and, possibly invalidate the -/// context if it is ambiguous. -/// -/// In the current implementation, we don't handle overloaded functions well, -/// because the argument types are not taken into account when computing the -/// DeclContext tree. -/// -/// Some of this is mitigated byt using mangled names that do contain the -/// arguments types, but sometimes (e.g. with function templates) we don't have -/// that. In that case, just do not unique anything that refers to the contexts -/// we are not able to distinguish. -/// -/// If a context that is not a namespace appears twice in the same CU, we know -/// it is ambiguous. Make it invalid. -bool DeclContext::setLastSeenDIE(CompileUnit &U, const DWARFDie &Die) { - if (LastSeenCompileUnitID == U.getUniqueID()) { - DWARFUnit &OrigUnit = U.getOrigUnit(); - uint32_t FirstIdx = OrigUnit.getDIEIndex(LastSeenDIE); - U.getInfo(FirstIdx).Ctxt = nullptr; - return false; - } - - LastSeenCompileUnitID = U.getUniqueID(); - LastSeenDIE = Die; - return true; -} - -PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext( - DeclContext &Context, const DWARFDie &DIE, CompileUnit &U, - UniquingStringPool &StringPool, bool InClangModule) { - unsigned Tag = DIE.getTag(); - - // FIXME: dsymutil-classic compat: We should bail out here if we - // have a specification or an abstract_origin. We will get the - // parent context wrong here. - - switch (Tag) { - default: - // By default stop gathering child contexts. - return PointerIntPair<DeclContext *, 1>(nullptr); - case dwarf::DW_TAG_module: - break; - case dwarf::DW_TAG_compile_unit: - return PointerIntPair<DeclContext *, 1>(&Context); - case dwarf::DW_TAG_subprogram: - // Do not unique anything inside CU local functions. - if ((Context.getTag() == dwarf::DW_TAG_namespace || - Context.getTag() == dwarf::DW_TAG_compile_unit) && - !dwarf::toUnsigned(DIE.find(dwarf::DW_AT_external), 0)) - return PointerIntPair<DeclContext *, 1>(nullptr); - LLVM_FALLTHROUGH; - case dwarf::DW_TAG_member: - case dwarf::DW_TAG_namespace: - case dwarf::DW_TAG_structure_type: - case dwarf::DW_TAG_class_type: - case dwarf::DW_TAG_union_type: - case dwarf::DW_TAG_enumeration_type: - case dwarf::DW_TAG_typedef: - // Artificial things might be ambiguous, because they might be created on - // demand. For example implicitly defined constructors are ambiguous - // because of the way we identify contexts, and they won't be generated - // every time everywhere. - if (dwarf::toUnsigned(DIE.find(dwarf::DW_AT_artificial), 0)) - return PointerIntPair<DeclContext *, 1>(nullptr); - break; - } - - const char *Name = DIE.getName(DINameKind::LinkageName); - const char *ShortName = DIE.getName(DINameKind::ShortName); - StringRef NameRef; - StringRef ShortNameRef; - StringRef FileRef; - - if (Name) - NameRef = StringPool.internString(Name); - else if (Tag == dwarf::DW_TAG_namespace) - // FIXME: For dsymutil-classic compatibility. I think uniquing within - // anonymous namespaces is wrong. There is no ODR guarantee there. - NameRef = StringPool.internString("(anonymous namespace)"); - - if (ShortName && ShortName != Name) - ShortNameRef = StringPool.internString(ShortName); - else - ShortNameRef = NameRef; - - if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type && - Tag != dwarf::DW_TAG_union_type && - Tag != dwarf::DW_TAG_enumeration_type && NameRef.empty()) - return PointerIntPair<DeclContext *, 1>(nullptr); - - unsigned Line = 0; - unsigned ByteSize = std::numeric_limits<uint32_t>::max(); - - if (!InClangModule) { - // Gather some discriminating data about the DeclContext we will be - // creating: File, line number and byte size. This shouldn't be necessary, - // because the ODR is just about names, but given that we do some - // approximations with overloaded functions and anonymous namespaces, use - // these additional data points to make the process safer. - // - // This is disabled for clang modules, because forward declarations of - // module-defined types do not have a file and line. - ByteSize = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_byte_size), - std::numeric_limits<uint64_t>::max()); - if (Tag != dwarf::DW_TAG_namespace || !Name) { - if (unsigned FileNum = - dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_file), 0)) { - if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit( - &U.getOrigUnit())) { - // FIXME: dsymutil-classic compatibility. I'd rather not - // unique anything in anonymous namespaces, but if we do, then - // verify that the file and line correspond. - if (!Name && Tag == dwarf::DW_TAG_namespace) - FileNum = 1; - - if (LT->hasFileAtIndex(FileNum)) { - Line = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_line), 0); - // Cache the resolved paths based on the index in the line table, - // because calling realpath is expansive. - StringRef ResolvedPath = U.getResolvedPath(FileNum); - if (!ResolvedPath.empty()) { - FileRef = ResolvedPath; - } else { - std::string File; - bool FoundFileName = LT->getFileNameByIndex( - FileNum, U.getOrigUnit().getCompilationDir(), - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, - File); - (void)FoundFileName; - assert(FoundFileName && "Must get file name from line table"); - // Second level of caching, this time based on the file's parent - // path. - FileRef = PathResolver.resolve(File, StringPool); - U.setResolvedPath(FileNum, FileRef); - } - } - } - } - } - } - - if (!Line && NameRef.empty()) - return PointerIntPair<DeclContext *, 1>(nullptr); - - // We hash NameRef, which is the mangled name, in order to get most - // overloaded functions resolve correctly. - // - // Strictly speaking, hashing the Tag is only necessary for a - // DW_TAG_module, to prevent uniquing of a module and a namespace - // with the same name. - // - // FIXME: dsymutil-classic won't unique the same type presented - // once as a struct and once as a class. Using the Tag in the fully - // qualified name hash to get the same effect. - unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameRef); - - // FIXME: dsymutil-classic compatibility: when we don't have a name, - // use the filename. - if (Tag == dwarf::DW_TAG_namespace && NameRef == "(anonymous namespace)") - Hash = hash_combine(Hash, FileRef); - - // Now look if this context already exists. - DeclContext Key(Hash, Line, ByteSize, Tag, NameRef, FileRef, Context); - auto ContextIter = Contexts.find(&Key); - - if (ContextIter == Contexts.end()) { - // The context wasn't found. - bool Inserted; - DeclContext *NewContext = - new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, NameRef, FileRef, - Context, DIE, U.getUniqueID()); - std::tie(ContextIter, Inserted) = Contexts.insert(NewContext); - assert(Inserted && "Failed to insert DeclContext"); - (void)Inserted; - } else if (Tag != dwarf::DW_TAG_namespace && - !(*ContextIter)->setLastSeenDIE(U, DIE)) { - // The context was found, but it is ambiguous with another context - // in the same file. Mark it invalid. - return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1); - } - - assert(ContextIter != Contexts.end()); - // FIXME: dsymutil-classic compatibility. Union types aren't - // uniques, but their children might be. - if ((Tag == dwarf::DW_TAG_subprogram && - Context.getTag() != dwarf::DW_TAG_structure_type && - Context.getTag() != dwarf::DW_TAG_class_type) || - (Tag == dwarf::DW_TAG_union_type)) - return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1); - - return PointerIntPair<DeclContext *, 1>(*ContextIter); -} -} // namespace dsymutil -} // namespace llvm diff --git a/llvm/tools/dsymutil/DeclContext.h b/llvm/tools/dsymutil/DeclContext.h deleted file mode 100644 index 36ef5094408..00000000000 --- a/llvm/tools/dsymutil/DeclContext.h +++ /dev/null @@ -1,171 +0,0 @@ -//===- tools/dsymutil/DeclContext.h - Dwarf debug info linker ---*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H -#define LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H - -#include "CompileUnit.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseMapInfo.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/CodeGen/NonRelocatableStringpool.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" -#include "llvm/Support/Path.h" - -namespace llvm { -namespace dsymutil { - -struct DeclMapInfo; - -/// Small helper that resolves and caches file paths. This helps reduce the -/// number of calls to realpath which is expensive. We assume the input are -/// files, and cache the realpath of their parent. This way we can quickly -/// resolve different files under the same path. -class CachedPathResolver { -public: - /// Resolve a path by calling realpath and cache its result. The returned - /// StringRef is interned in the given \p StringPool. - StringRef resolve(std::string Path, NonRelocatableStringpool &StringPool) { - StringRef FileName = sys::path::filename(Path); - SmallString<256> ParentPath = sys::path::parent_path(Path); - - // If the ParentPath has not yet been resolved, resolve and cache it for - // future look-ups. - if (!ResolvedPaths.count(ParentPath)) { - SmallString<256> RealPath; - sys::fs::real_path(ParentPath, RealPath); - ResolvedPaths.insert({ParentPath, StringRef(RealPath).str()}); - } - - // Join the file name again with the resolved path. - SmallString<256> ResolvedPath(ResolvedPaths[ParentPath]); - sys::path::append(ResolvedPath, FileName); - return StringPool.internString(ResolvedPath); - } - -private: - StringMap<std::string> ResolvedPaths; -}; - -/// A DeclContext is a named program scope that is used for ODR uniquing of -/// types. -/// -/// The set of DeclContext for the ODR-subject parts of a Dwarf link is -/// expanded (and uniqued) with each new object file processed. We need to -/// determine the context of each DIE in an linked object file to see if the -/// corresponding type has already been emitted. -/// -/// The contexts are conceptually organized as a tree (eg. a function scope is -/// contained in a namespace scope that contains other scopes), but -/// storing/accessing them in an actual tree is too inefficient: we need to be -/// able to very quickly query a context for a given child context by name. -/// Storing a StringMap in each DeclContext would be too space inefficient. -/// -/// The solution here is to give each DeclContext a link to its parent (this -/// allows to walk up the tree), but to query the existence of a specific -/// DeclContext using a separate DenseMap keyed on the hash of the fully -/// qualified name of the context. -class DeclContext { -public: - using Map = DenseSet<DeclContext *, DeclMapInfo>; - - DeclContext() : DefinedInClangModule(0), Parent(*this) {} - - DeclContext(unsigned Hash, uint32_t Line, uint32_t ByteSize, uint16_t Tag, - StringRef Name, StringRef File, const DeclContext &Parent, - DWARFDie LastSeenDIE = DWARFDie(), unsigned CUId = 0) - : QualifiedNameHash(Hash), Line(Line), ByteSize(ByteSize), Tag(Tag), - DefinedInClangModule(0), Name(Name), File(File), Parent(Parent), - LastSeenDIE(LastSeenDIE), LastSeenCompileUnitID(CUId) {} - - uint32_t getQualifiedNameHash() const { return QualifiedNameHash; } - - bool setLastSeenDIE(CompileUnit &U, const DWARFDie &Die); - - uint32_t getCanonicalDIEOffset() const { return CanonicalDIEOffset; } - void setCanonicalDIEOffset(uint32_t Offset) { CanonicalDIEOffset = Offset; } - - bool isDefinedInClangModule() const { return DefinedInClangModule; } - void setDefinedInClangModule(bool Val) { DefinedInClangModule = Val; } - - uint16_t getTag() const { return Tag; } - StringRef getName() const { return Name; } - -private: - friend DeclMapInfo; - - unsigned QualifiedNameHash = 0; - uint32_t Line = 0; - uint32_t ByteSize = 0; - uint16_t Tag = dwarf::DW_TAG_compile_unit; - unsigned DefinedInClangModule : 1; - StringRef Name; - StringRef File; - const DeclContext &Parent; - DWARFDie LastSeenDIE; - uint32_t LastSeenCompileUnitID = 0; - uint32_t CanonicalDIEOffset = 0; -}; - -/// This class gives a tree-like API to the DenseMap that stores the -/// DeclContext objects. It holds the BumpPtrAllocator where these objects will -/// be allocated. -class DeclContextTree { -public: - /// Get the child of \a Context described by \a DIE in \a Unit. The - /// required strings will be interned in \a StringPool. - /// \returns The child DeclContext along with one bit that is set if - /// this context is invalid. - /// - /// An invalid context means it shouldn't be considered for uniquing, but its - /// not returning null, because some children of that context might be - /// uniquing candidates. - /// - /// FIXME: The invalid bit along the return value is to emulate some - /// dsymutil-classic functionality. - PointerIntPair<DeclContext *, 1> - getChildDeclContext(DeclContext &Context, const DWARFDie &DIE, - CompileUnit &Unit, UniquingStringPool &StringPool, - bool InClangModule); - - DeclContext &getRoot() { return Root; } - -private: - BumpPtrAllocator Allocator; - DeclContext Root; - DeclContext::Map Contexts; - - /// Cache resolved paths from the line table. - CachedPathResolver PathResolver; -}; - -/// Info type for the DenseMap storing the DeclContext pointers. -struct DeclMapInfo : private DenseMapInfo<DeclContext *> { - using DenseMapInfo<DeclContext *>::getEmptyKey; - using DenseMapInfo<DeclContext *>::getTombstoneKey; - - static unsigned getHashValue(const DeclContext *Ctxt) { - return Ctxt->QualifiedNameHash; - } - - static bool isEqual(const DeclContext *LHS, const DeclContext *RHS) { - if (RHS == getEmptyKey() || RHS == getTombstoneKey()) - return RHS == LHS; - return LHS->QualifiedNameHash == RHS->QualifiedNameHash && - LHS->Line == RHS->Line && LHS->ByteSize == RHS->ByteSize && - LHS->Name.data() == RHS->Name.data() && - LHS->File.data() == RHS->File.data() && - LHS->Parent.QualifiedNameHash == RHS->Parent.QualifiedNameHash; - } -}; - -} // end namespace dsymutil -} // end namespace llvm - -#endif // LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp index 53f6b2899b0..b42fc1a1d50 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp @@ -1,4 +1,4 @@ -//===- tools/dsymutil/DwarfLinker.cpp - Dwarf debug info linker -----------===// +//===- tools/dsymutil/DwarfLinkerForBinary.cpp ----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,10 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "DwarfLinker.h" +#include "DwarfLinkerForBinary.h" #include "BinaryHolder.h" #include "DebugMap.h" -#include "DeclContext.h" #include "DwarfStreamer.h" #include "MachOUtils.h" #include "dsymutil.h" @@ -37,6 +36,7 @@ #include "llvm/CodeGen/DIE.h" #include "llvm/CodeGen/NonRelocatableStringpool.h" #include "llvm/Config/config.h" +#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" @@ -119,7 +119,7 @@ static CompileUnit *getUnitForOffset(const UnitListTy &Units, uint64_t Offset) { /// Resolve the DIE attribute reference that has been extracted in \p RefValue. /// The resulting DIE might be in another CompileUnit which is stored into \p /// ReferencedCU. \returns null if resolving fails for any reason. -static DWARFDie resolveDIEReference(const DwarfLinker &Linker, +static DWARFDie resolveDIEReference(const DwarfLinkerForBinary &Linker, const DebugMapObject &DMO, const UnitListTy &Units, const DWARFFormValue &RefValue, @@ -188,7 +188,8 @@ static bool isTypeTag(uint16_t Tag) { return false; } -static Error remarksErrorHandler(const DebugMapObject &DMO, DwarfLinker &Linker, +static Error remarksErrorHandler(const DebugMapObject &DMO, + DwarfLinkerForBinary &Linker, std::unique_ptr<FileError> FE) { bool IsArchive = DMO.getObjectFilename().endswith(")"); // Don't report errors for missing remark files from static @@ -212,10 +213,10 @@ static Error remarksErrorHandler(const DebugMapObject &DMO, DwarfLinker &Linker, return createFileError(FE->getFileName(), std::move(NewE)); } -bool DwarfLinker::DIECloner::getDIENames(const DWARFDie &Die, - AttributesInfo &Info, - OffsetsStringPool &StringPool, - bool StripTemplate) { +bool DwarfLinkerForBinary::DIECloner::getDIENames(const DWARFDie &Die, + AttributesInfo &Info, + OffsetsStringPool &StringPool, + bool StripTemplate) { // This function will be called on DIEs having low_pcs and // ranges. As getting the name might be more expansive, filter out // blocks directly. @@ -244,8 +245,9 @@ bool DwarfLinker::DIECloner::getDIENames(const DWARFDie &Die, /// Report a warning to the user, optionally including information about a /// specific \p DIE related to the warning. -void DwarfLinker::reportWarning(const Twine &Warning, const DebugMapObject &DMO, - const DWARFDie *DIE) const { +void DwarfLinkerForBinary::reportWarning(const Twine &Warning, + const DebugMapObject &DMO, + const DWARFDie *DIE) const { StringRef Context = DMO.getObjectFilename(); warn(Warning, Context); @@ -260,8 +262,8 @@ void DwarfLinker::reportWarning(const Twine &Warning, const DebugMapObject &DMO, DIE->dump(errs(), 6 /* Indent */, DumpOpts); } -bool DwarfLinker::createStreamer(const Triple &TheTriple, - raw_fd_ostream &OutFile) { +bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple, + raw_fd_ostream &OutFile) { if (Options.NoOutput) return true; @@ -397,34 +399,9 @@ static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) { llvm_unreachable("Invalid Tag"); } -void DwarfLinker::startDebugObject(LinkContext &Context) { - // Iterate over the debug map entries and put all the ones that are - // functions (because they have a size) into the Ranges map. This map is - // very similar to the FunctionRanges that are stored in each unit, with 2 - // notable differences: - // - // 1. Obviously this one is global, while the other ones are per-unit. - // - // 2. This one contains not only the functions described in the DIE - // tree, but also the ones that are only in the debug map. - // - // The latter information is required to reproduce dsymutil's logic while - // linking line tables. The cases where this information matters look like - // bugs that need to be investigated, but for now we need to reproduce - // dsymutil's behavior. - // FIXME: Once we understood exactly if that information is needed, - // maybe totally remove this (or try to use it to do a real - // -gline-tables-only on Darwin. - for (const auto &Entry : Context.DMO.symbols()) { - const auto &Mapping = Entry.getValue(); - if (Mapping.Size && Mapping.ObjectAddress) - Context.Ranges[*Mapping.ObjectAddress] = DebugMapObjectRange( - *Mapping.ObjectAddress + Mapping.Size, - int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress); - } -} +void DwarfLinkerForBinary::startDebugObject(LinkContext &Context) {} -void DwarfLinker::endDebugObject(LinkContext &Context) { +void DwarfLinkerForBinary::endDebugObject(LinkContext &Context) { Context.Clear(); for (auto I = DIEBlocks.begin(), E = DIEBlocks.end(); I != E; ++I) @@ -460,7 +437,7 @@ static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) { /// Iterate over the relocations of the given \p Section and /// store the ones that correspond to debug map entries into the /// ValidRelocs array. -void DwarfLinker::RelocationManager::findValidRelocsMachO( +void DwarfLinkerForBinary::RelocationManager::findValidRelocsMachO( const object::SectionRef &Section, const object::MachOObjectFile &Obj, const DebugMapObject &DMO) { Expected<StringRef> ContentsOrErr = Section.getContents(); @@ -534,7 +511,7 @@ void DwarfLinker::RelocationManager::findValidRelocsMachO( /// Dispatch the valid relocation finding logic to the /// appropriate handler depending on the object file format. -bool DwarfLinker::RelocationManager::findValidRelocs( +bool DwarfLinkerForBinary::RelocationManager::findValidRelocs( const object::SectionRef &Section, const object::ObjectFile &Obj, const DebugMapObject &DMO) { // Dispatch to the right handler depending on the file type. @@ -560,7 +537,7 @@ bool DwarfLinker::RelocationManager::findValidRelocs( /// link by indicating which DIEs refer to symbols present in the /// linked binary. /// \returns whether there are any valid relocations in the debug info. -bool DwarfLinker::RelocationManager::findValidRelocsInDebugInfo( +bool DwarfLinkerForBinary::RelocationManager::findValidRelocsInDebugInfo( const object::ObjectFile &Obj, const DebugMapObject &DMO) { // Find the debug_info section. for (const object::SectionRef &Section : Obj.sections()) { @@ -584,7 +561,7 @@ bool DwarfLinker::RelocationManager::findValidRelocsInDebugInfo( /// This function must be called with offsets in strictly ascending /// order because it never looks back at relocations it already 'went past'. /// \returns true and sets Info.InDebugMap if it is the case. -bool DwarfLinker::RelocationManager::hasValidRelocation( +bool DwarfLinkerForBinary::RelocationManager::hasValidRelocationAt( uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) { assert(NextValidReloc == 0 || StartOffset > ValidRelocs[NextValidReloc - 1].Offset); @@ -645,11 +622,9 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx, /// Check if a variable describing DIE should be kept. /// \returns updated TraversalFlags. -unsigned DwarfLinker::shouldKeepVariableDIE(RelocationManager &RelocMgr, - const DWARFDie &DIE, - CompileUnit &Unit, - CompileUnit::DIEInfo &MyInfo, - unsigned Flags) { +unsigned DwarfLinkerForBinary::shouldKeepVariableDIE( + RelocationManager &RelocMgr, const DWARFDie &DIE, CompileUnit &Unit, + CompileUnit::DIEInfo &MyInfo, unsigned Flags) { const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); // Global variables with constant value can always be kept. @@ -675,7 +650,8 @@ unsigned DwarfLinker::shouldKeepVariableDIE(RelocationManager &RelocMgr, // always check if the variable has a valid relocation, so that the // DIEInfo is filled. However, we don't want a static variable in a // function to force us to keep the enclosing function. - if (!RelocMgr.hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) || + if (!RelocMgr.hasValidRelocationAt(LocationOffset, LocationEndOffset, + MyInfo) || (Flags & TF_InFunctionScope)) return Flags; @@ -692,7 +668,7 @@ unsigned DwarfLinker::shouldKeepVariableDIE(RelocationManager &RelocMgr, /// Check if a function describing DIE should be kept. /// \returns updated TraversalFlags. -unsigned DwarfLinker::shouldKeepSubprogramDIE( +unsigned DwarfLinkerForBinary::shouldKeepSubprogramDIE( RelocationManager &RelocMgr, RangesTy &Ranges, const DWARFDie &DIE, const DebugMapObject &DMO, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags) { @@ -713,7 +689,7 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE( auto LowPc = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc)); assert(LowPc.hasValue() && "low_pc attribute is not an address."); if (!LowPc || - !RelocMgr.hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo)) + !RelocMgr.hasValidRelocationAt(LowPcOffset, LowPcEndOffset, MyInfo)) return Flags; if (Options.Verbose) { @@ -748,19 +724,17 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE( } // Replace the debug map range with a more accurate one. - Ranges[*LowPc] = DebugMapObjectRange(*HighPc, MyInfo.AddrAdjust); + Ranges[*LowPc] = ObjFileAddressRange(*HighPc, MyInfo.AddrAdjust); Unit.addFunctionRange(*LowPc, *HighPc, MyInfo.AddrAdjust); return Flags; } /// Check if a DIE should be kept. /// \returns updated TraversalFlags. -unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr, - RangesTy &Ranges, const DWARFDie &DIE, - const DebugMapObject &DMO, - CompileUnit &Unit, - CompileUnit::DIEInfo &MyInfo, - unsigned Flags) { +unsigned DwarfLinkerForBinary::shouldKeepDIE( + RelocationManager &RelocMgr, RangesTy &Ranges, const DWARFDie &DIE, + const DebugMapObject &DMO, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, + unsigned Flags) { switch (DIE.getTag()) { case dwarf::DW_TAG_constant: case dwarf::DW_TAG_variable: @@ -885,11 +859,11 @@ static void lookForChildDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, // the parent chain). There are however a set of DIE types for which we want // to ignore that directive and still walk their children. if (dieNeedsChildrenToBeMeaningful(Die.getTag())) - Flags &= ~DwarfLinker::TF_ParentWalk; + Flags &= ~DwarfLinkerForBinary::TF_ParentWalk; // We're finished if this DIE has no children or we're walking the parent // chain. - if (!Die.hasChildren() || (Flags & DwarfLinker::TF_ParentWalk)) + if (!Die.hasChildren() || (Flags & DwarfLinkerForBinary::TF_ParentWalk)) return; // Add children in reverse order to the worklist to effectively process them @@ -908,12 +882,12 @@ static void lookForChildDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, /// Look at DIEs referenced by the given DIE and decide whether they should be /// kept. All DIEs referenced though attributes should be kept. static void lookForRefDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, - unsigned Flags, DwarfLinker &Linker, + unsigned Flags, DwarfLinkerForBinary &Linker, const UnitListTy &Units, const DebugMapObject &DMO, SmallVectorImpl<WorklistItem> &Worklist) { - bool UseOdr = (Flags & DwarfLinker::TF_DependencyWalk) - ? (Flags & DwarfLinker::TF_ODR) + bool UseOdr = (Flags & DwarfLinkerForBinary::TF_DependencyWalk) + ? (Flags & DwarfLinkerForBinary::TF_ODR) : CU.hasODR(); DWARFUnit &Unit = CU.getOrigUnit(); DWARFDataExtractor Data = Unit.getDebugInfoExtractor(); @@ -962,7 +936,7 @@ static void lookForRefDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, } } - unsigned ODRFlag = UseOdr ? DwarfLinker::TF_ODR : 0; + unsigned ODRFlag = UseOdr ? DwarfLinkerForBinary::TF_ODR : 0; // Add referenced DIEs in reverse order to the worklist to effectively // process them in order. @@ -974,8 +948,9 @@ static void lookForRefDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, Worklist.emplace_back(Die, CU, WorklistItemType::UpdateRefIncompleteness, &Info); Worklist.emplace_back(P.first, P.second, - DwarfLinker::TF_Keep | - DwarfLinker::TF_DependencyWalk | ODRFlag); + DwarfLinkerForBinary::TF_Keep | + DwarfLinkerForBinary::TF_DependencyWalk | + ODRFlag); } } @@ -1018,11 +993,12 @@ static void lookForParentDIEsToKeep(unsigned AncestorIdx, CompileUnit &CU, /// UpdateRefIncompleteness). /// /// The return value indicates whether the DIE is incomplete. -void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, - RangesTy &Ranges, const UnitListTy &Units, - const DWARFDie &Die, - const DebugMapObject &DMO, CompileUnit &Cu, - unsigned Flags) { +void DwarfLinkerForBinary::lookForDIEsToKeep(RelocationManager &RelocMgr, + RangesTy &Ranges, + const UnitListTy &Units, + const DWARFDie &Die, + const DebugMapObject &DMO, + CompileUnit &Cu, unsigned Flags) { // LIFO work list. SmallVector<WorklistItem, 4> Worklist; Worklist.emplace_back(Die, Cu, Flags); @@ -1113,7 +1089,7 @@ void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, /// thus the FoldingSet we use to unique DIEAbbrevs cannot refer to /// the instances hold by the DIEs. When we encounter an abbreviation /// that we don't know, we create a permanent copy of it. -void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) { +void DwarfLinkerForBinary::assignAbbrev(DIEAbbrev &Abbrev) { // Check the set for priors. FoldingSetNodeID ID; Abbrev.Profile(ID); @@ -1137,7 +1113,7 @@ void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) { } } -unsigned DwarfLinker::DIECloner::cloneStringAttribute( +unsigned DwarfLinkerForBinary::DIECloner::cloneStringAttribute( DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val, const DWARFUnit &U, OffsetsStringPool &StringPool, AttributesInfo &Info) { // Switch everything to out of line strings. @@ -1157,7 +1133,7 @@ unsigned DwarfLinker::DIECloner::cloneStringAttribute( return 4; } -unsigned DwarfLinker::DIECloner::cloneDieReferenceAttribute( +unsigned DwarfLinkerForBinary::DIECloner::cloneDieReferenceAttribute( DIE &Die, const DWARFDie &InputDIE, AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val, const DebugMapObject &DMO, CompileUnit &Unit) { @@ -1228,7 +1204,7 @@ unsigned DwarfLinker::DIECloner::cloneDieReferenceAttribute( return AttrSize; } -void DwarfLinker::DIECloner::cloneExpression( +void DwarfLinkerForBinary::DIECloner::cloneExpression( DataExtractor &Data, DWARFExpression Expression, const DebugMapObject &DMO, CompileUnit &Unit, SmallVectorImpl<uint8_t> &OutputBuffer) { using Encoding = DWARFExpression::Operation::Encoding; @@ -1288,7 +1264,7 @@ void DwarfLinker::DIECloner::cloneExpression( } } -unsigned DwarfLinker::DIECloner::cloneBlockAttribute( +unsigned DwarfLinkerForBinary::DIECloner::cloneBlockAttribute( DIE &Die, const DebugMapObject &DMO, CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, bool IsLittleEndian) { @@ -1346,7 +1322,7 @@ unsigned DwarfLinker::DIECloner::cloneBlockAttribute( return AttrSize; } -unsigned DwarfLinker::DIECloner::cloneAddressAttribute( +unsigned DwarfLinkerForBinary::DIECloner::cloneAddressAttribute( DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val, const CompileUnit &Unit, AttributesInfo &Info) { uint64_t Addr = *Val.getAsAddress(); @@ -1394,7 +1370,7 @@ unsigned DwarfLinker::DIECloner::cloneAddressAttribute( return Unit.getOrigUnit().getAddressByteSize(); } -unsigned DwarfLinker::DIECloner::cloneScalarAttribute( +unsigned DwarfLinkerForBinary::DIECloner::cloneScalarAttribute( DIE &Die, const DWARFDie &InputDIE, const DebugMapObject &DMO, CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, AttributesInfo &Info) { @@ -1451,7 +1427,7 @@ unsigned DwarfLinker::DIECloner::cloneScalarAttribute( // location list. // FIXME: use DWARFAttribute::mayHaveLocationDescription(). else if (AttrSpec.Attr == dwarf::DW_AT_location || - AttrSpec.Attr == dwarf::DW_AT_frame_base) + AttrSpec.Attr == dwarf::DW_AT_frame_base) Unit.noteLocationAttribute(Patch, Info.PCOffset); else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value) Info.IsDeclaration = true; @@ -1462,7 +1438,7 @@ unsigned DwarfLinker::DIECloner::cloneScalarAttribute( /// Clone \p InputDIE's attribute described by \p AttrSpec with /// value \p Val, and add it to \p Die. /// \returns the size of the cloned attribute. -unsigned DwarfLinker::DIECloner::cloneAttribute( +unsigned DwarfLinkerForBinary::DIECloner::cloneAttribute( DIE &Die, const DWARFDie &InputDIE, const DebugMapObject &DMO, CompileUnit &Unit, OffsetsStringPool &StringPool, const DWARFFormValue &Val, const AttributeSpec AttrSpec, unsigned AttrSize, AttributesInfo &Info, @@ -1517,7 +1493,7 @@ unsigned DwarfLinker::DIECloner::cloneAttribute( /// monotonic \p BaseOffset values. /// /// \returns whether any reloc has been applied. -bool DwarfLinker::RelocationManager::applyValidRelocs( +bool DwarfLinkerForBinary::RelocationManager::applyValidRelocs( MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) { assert((NextValidReloc == 0 || BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) && @@ -1558,11 +1534,9 @@ static bool isObjCSelector(StringRef Name) { (Name[1] == '['); } -void DwarfLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit, - const DIE *Die, - DwarfStringPoolEntryRef Name, - OffsetsStringPool &StringPool, - bool SkipPubSection) { +void DwarfLinkerForBinary::DIECloner::addObjCAccelerator( + CompileUnit &Unit, const DIE *Die, DwarfStringPoolEntryRef Name, + OffsetsStringPool &StringPool, bool SkipPubSection) { assert(isObjCSelector(Name.getString()) && "not an objc selector"); // Objective C method or class function. // "- [Class(Category) selector :withArg ...]" @@ -1624,7 +1598,7 @@ shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, } } -DIE *DwarfLinker::DIECloner::cloneDIE( +DIE *DwarfLinkerForBinary::DIECloner::cloneDIE( const DWARFDie &InputDIE, const DebugMapObject &DMO, CompileUnit &Unit, OffsetsStringPool &StringPool, int64_t PCOffset, uint32_t OutOffset, unsigned Flags, bool IsLittleEndian, DIE *Die) { @@ -1675,7 +1649,8 @@ DIE *DwarfLinker::DIECloner::cloneDIE( Data = DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize()); // Modify the copy with relocated addresses. - if (RelocMgr.applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) { + if (RelocMgr.areRelocationsResolved() && + RelocMgr.applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) { // If we applied relocations, we store the value of high_pc that was // potentially stored in the input DIE. If high_pc is an address // (Dwarf version == 2), then it might have been relocated to a @@ -1793,7 +1768,7 @@ DIE *DwarfLinker::DIECloner::cloneDIE( if (HasChildren) NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes); // Assign a permanent abbrev number - Linker.AssignAbbrev(NewAbbrev); + Linker.assignAbbrev(NewAbbrev); Die->setAbbrevNumber(NewAbbrev.getNumber()); // Add the size of the abbreviation number to the output offset. @@ -1824,9 +1799,9 @@ DIE *DwarfLinker::DIECloner::cloneDIE( /// Patch the input object file relevant debug_ranges entries /// and emit them in the output file. Update the relevant attributes /// to point at the new entries. -void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit, - DWARFContext &OrigDwarf, - const DebugMapObject &DMO) const { +void DwarfLinkerForBinary::patchRangesForUnit(const CompileUnit &Unit, + DWARFContext &OrigDwarf, + const DebugMapObject &DMO) const { DWARFDebugRangeList RangeList; const auto &FunctionRanges = Unit.getFunctionRanges(); unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); @@ -1879,7 +1854,7 @@ void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit, /// FIXME: this could actually be done right in patchRangesForUnit, /// but for the sake of initial bit-for-bit compatibility with legacy /// dsymutil, we have to do it in a delayed pass. -void DwarfLinker::generateUnitRanges(CompileUnit &Unit) const { +void DwarfLinkerForBinary::generateUnitRanges(CompileUnit &Unit) const { auto Attr = Unit.getUnitRangesAttribute(); if (Attr) Attr->set(Streamer->getRangesSectionSize()); @@ -1931,10 +1906,10 @@ static void patchStmtList(DIE &Die, DIEInteger Offset) { /// Extract the line table for \p Unit from \p OrigDwarf, and /// recreate a relocated version of these for the address ranges that /// are present in the binary. -void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit, - DWARFContext &OrigDwarf, - RangesTy &Ranges, - const DebugMapObject &DMO) { +void DwarfLinkerForBinary::patchLineTableForUnit(CompileUnit &Unit, + DWARFContext &OrigDwarf, + RangesTy &Ranges, + const DebugMapObject &DMO) { DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE(); auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list)); if (!StmtList) @@ -2071,7 +2046,7 @@ void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit, } } -void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) { +void DwarfLinkerForBinary::emitAcceleratorEntriesForUnit(CompileUnit &Unit) { switch (Options.TheAccelTableKind) { case AccelTableKind::Apple: emitAppleAcceleratorEntriesForUnit(Unit); @@ -2085,7 +2060,8 @@ void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) { } } -void DwarfLinker::emitAppleAcceleratorEntriesForUnit(CompileUnit &Unit) { +void DwarfLinkerForBinary::emitAppleAcceleratorEntriesForUnit( + CompileUnit &Unit) { // Add namespaces. for (const auto &Namespace : Unit.getNamespaces()) AppleNamespaces.addName(Namespace.Name, @@ -2114,7 +2090,8 @@ void DwarfLinker::emitAppleAcceleratorEntriesForUnit(CompileUnit &Unit) { AppleObjc.addName(ObjC.Name, ObjC.Die->getOffset() + Unit.getStartOffset()); } -void DwarfLinker::emitDwarfAcceleratorEntriesForUnit(CompileUnit &Unit) { +void DwarfLinkerForBinary::emitDwarfAcceleratorEntriesForUnit( + CompileUnit &Unit) { for (const auto &Namespace : Unit.getNamespaces()) DebugNames.addName(Namespace.Name, Namespace.Die->getOffset(), Namespace.Die->getTag(), Unit.getUniqueID()); @@ -2132,10 +2109,10 @@ void DwarfLinker::emitDwarfAcceleratorEntriesForUnit(CompileUnit &Unit) { /// This is actually pretty easy as the data of the CIEs and FDEs can /// be considered as black boxes and moved as is. The only thing to do /// is to patch the addresses in the headers. -void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO, - RangesTy &Ranges, - DWARFContext &OrigDwarf, - unsigned AddrSize) { +void DwarfLinkerForBinary::patchFrameInfoForObject(const DebugMapObject &DMO, + RangesTy &Ranges, + DWARFContext &OrigDwarf, + unsigned AddrSize) { StringRef FrameData = OrigDwarf.getDWARFObj().getFrameSection().Data; if (FrameData.empty()) return; @@ -2212,25 +2189,24 @@ void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO, } } -void DwarfLinker::DIECloner::copyAbbrev( - const DWARFAbbreviationDeclaration &Abbrev, bool hasODR) { +void DwarfLinkerForBinary::DIECloner::copyAbbrev( + const DWARFAbbreviationDeclaration &Abbrev, bool HasODR) { DIEAbbrev Copy(dwarf::Tag(Abbrev.getTag()), dwarf::Form(Abbrev.hasChildren())); for (const auto &Attr : Abbrev.attributes()) { uint16_t Form = Attr.Form; - if (hasODR && isODRAttribute(Attr.Attr)) + if (HasODR && isODRAttribute(Attr.Attr)) Form = dwarf::DW_FORM_ref_addr; Copy.AddAttribute(dwarf::Attribute(Attr.Attr), dwarf::Form(Form)); } - Linker.AssignAbbrev(Copy); + Linker.assignAbbrev(Copy); } -uint32_t -DwarfLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U, - const DebugMapObject &DMO, - int ChildRecurseDepth) { +uint32_t DwarfLinkerForBinary::DIECloner::hashFullyQualifiedName( + DWARFDie DIE, CompileUnit &U, const DebugMapObject &DMO, + int ChildRecurseDepth) { const char *Name = nullptr; DWARFUnit *OrigUnit = &U.getOrigUnit(); CompileUnit *CU = &U; @@ -2281,7 +2257,7 @@ static uint64_t getDwoId(const DWARFDie &CUDie, const DWARFUnit &Unit) { return 0; } -bool DwarfLinker::registerModuleReference( +bool DwarfLinkerForBinary::registerModuleReference( DWARFDie CUDie, const DWARFUnit &Unit, DebugMap &ModuleMap, const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool, UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts, @@ -2339,7 +2315,8 @@ bool DwarfLinker::registerModuleReference( } ErrorOr<const object::ObjectFile &> -DwarfLinker::loadObject(const DebugMapObject &Obj, const DebugMap &Map) { +DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj, + const DebugMap &Map) { auto ObjectEntry = BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp()); if (!ObjectEntry) { @@ -2360,7 +2337,7 @@ DwarfLinker::loadObject(const DebugMapObject &Obj, const DebugMap &Map) { return *Object; } -Error DwarfLinker::loadClangModule( +Error DwarfLinkerForBinary::loadClangModule( DWARFDie CUDie, StringRef Filename, StringRef ModuleName, uint64_t DwoId, DebugMap &ModuleMap, const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool, UniquingStringPool &UniquingStringPool, @@ -2417,7 +2394,7 @@ Error DwarfLinker::loadClangModule( // Setup access to the debug info. auto DwarfContext = DWARFContext::create(*ErrOrObj); - RelocationManager RelocMgr(*this); + RelocationManager RelocMgr(*this, *ErrOrObj, DMO); for (const auto &CU : DwarfContext->compile_units()) { updateDwarfVersion(CU->getVersion()); @@ -2454,7 +2431,7 @@ Error DwarfLinker::loadClangModule( // Add this module. Unit = std::make_unique<CompileUnit>(*CU, UnitID++, !Options.NoODR, - ModuleName); + ModuleName); Unit->setHasInterestingContent(); analyzeContextInfo(CUDie, 0, *Unit, &ODRContexts.getRoot(), UniquingStringPool, ODRContexts, ModulesEndOffset, @@ -2481,7 +2458,7 @@ Error DwarfLinker::loadClangModule( return Error::success(); } -void DwarfLinker::DIECloner::cloneAllCompileUnits( +void DwarfLinkerForBinary::DIECloner::cloneAllCompileUnits( DWARFContext &DwarfContext, const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool, bool IsLittleEndian) { if (!Linker.Streamer) @@ -2550,7 +2527,7 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits( } } -void DwarfLinker::updateAccelKind(DWARFContext &Dwarf) { +void DwarfLinkerForBinary::updateAccelKind(DWARFContext &Dwarf) { if (Options.TheAccelTableKind != AccelTableKind::Default) return; @@ -2564,15 +2541,14 @@ void DwarfLinker::updateAccelKind(DWARFContext &Dwarf) { AtLeastOneAppleAccelTable = true; } - if (!AtLeastOneDwarfAccelTable && - !DwarfObj.getNamesSection().Data.empty()) { + if (!AtLeastOneDwarfAccelTable && !DwarfObj.getNamesSection().Data.empty()) { AtLeastOneDwarfAccelTable = true; } } -bool DwarfLinker::emitPaperTrailWarnings(const DebugMapObject &DMO, - const DebugMap &Map, - OffsetsStringPool &StringPool) { +bool DwarfLinkerForBinary::emitPaperTrailWarnings( + const DebugMapObject &DMO, const DebugMap &Map, + OffsetsStringPool &StringPool) { if (DMO.getWarnings().empty() || !DMO.empty()) return false; @@ -2606,13 +2582,13 @@ bool DwarfLinker::emitPaperTrailWarnings(const DebugMapObject &DMO, DMO.getWarnings().size() * (4 + 1 + 4) + 1 /* End of children */; DIEAbbrev Abbrev = CUDie->generateAbbrev(); - AssignAbbrev(Abbrev); + assignAbbrev(Abbrev); CUDie->setAbbrevNumber(Abbrev.getNumber()); Size += getULEB128Size(Abbrev.getNumber()); // Abbreviation ordering needed for classic compatibility. for (auto &Child : CUDie->children()) { Abbrev = Child.generateAbbrev(); - AssignAbbrev(Abbrev); + assignAbbrev(Abbrev); Child.setAbbrevNumber(Abbrev.getNumber()); Size += getULEB128Size(Abbrev.getNumber()); } @@ -2657,17 +2633,15 @@ static Error copySwiftInterfaces( // copy_file attempts an APFS clone first, so this should be cheap. if ((EC = sys::fs::copy_file(InterfaceFile, Path.str()))) - warn(Twine("cannot copy parseable Swift interface ") + - InterfaceFile + ": " + - toString(errorCodeToError(EC))); + warn(Twine("cannot copy parseable Swift interface ") + InterfaceFile + + ": " + toString(errorCodeToError(EC))); Path.resize(BaseLength); } return Error::success(); } static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath, - StringRef ArchName, - const remarks::RemarkLinker &RL) { + StringRef ArchName, const remarks::RemarkLinker &RL) { // Make sure we don't create the directories and the file if there is nothing // to serialize. if (RL.empty()) @@ -2701,7 +2675,7 @@ static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath, return Error::success(); } -bool DwarfLinker::link(const DebugMap &Map) { +bool DwarfLinkerForBinary::link(const DebugMap &Map) { if (!createStreamer(Map.getTriple(), OutFile)) return false; @@ -2798,8 +2772,7 @@ bool DwarfLinker::link(const DebugMap &Map) { // Look for relocations that correspond to debug map entries. if (LLVM_LIKELY(!Options.Update) && - !LinkContext.RelocMgr.findValidRelocsInDebugInfo( - *LinkContext.ObjectFile, LinkContext.DMO)) { + !LinkContext.RelocMgr->hasValidRelocs()) { if (Options.Verbose) outs() << "No valid relocations found. Skipping.\n"; @@ -2916,7 +2889,7 @@ bool DwarfLinker::link(const DebugMap &Map) { Streamer->copyInvariantDebugSection(*LinkContext.ObjectFile); } else { for (auto &CurrentUnit : LinkContext.CompileUnits) - lookForDIEsToKeep(LinkContext.RelocMgr, LinkContext.Ranges, + lookForDIEsToKeep(*LinkContext.RelocMgr, LinkContext.Ranges, LinkContext.CompileUnits, CurrentUnit->getOrigUnit().getUnitDIE(), LinkContext.DMO, *CurrentUnit, 0); @@ -2925,10 +2898,9 @@ bool DwarfLinker::link(const DebugMap &Map) { // The calls to applyValidRelocs inside cloneDIE will walk the reloc // array again (in the same way findValidRelocsInDebugInfo() did). We // need to reset the NextValidReloc index to the beginning. - LinkContext.RelocMgr.resetValidRelocs(); - if (LinkContext.RelocMgr.hasValidRelocs() || LLVM_UNLIKELY(Options.Update)) - DIECloner(*this, LinkContext.RelocMgr, DIEAlloc, LinkContext.CompileUnits, - Options) + if (LinkContext.RelocMgr->hasValidRelocs() || LLVM_UNLIKELY(Options.Update)) + DIECloner(*this, *LinkContext.RelocMgr, DIEAlloc, + LinkContext.CompileUnits, Options) .cloneAllCompileUnits(*LinkContext.DwarfContext, LinkContext.DMO, LinkContext.Ranges, OffsetsStringPool, LinkContext.DwarfContext->isLittleEndian()); @@ -3074,7 +3046,7 @@ bool DwarfLinker::link(const DebugMap &Map) { bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, const DebugMap &DM, LinkOptions Options) { - DwarfLinker Linker(OutFile, BinHolder, std::move(Options)); + DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options)); return Linker.link(DM); } diff --git a/llvm/tools/dsymutil/DwarfLinker.h b/llvm/tools/dsymutil/DwarfLinkerForBinary.h index b8d8e9d02e3..133e28e7fea 100644 --- a/llvm/tools/dsymutil/DwarfLinker.h +++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.h @@ -1,4 +1,4 @@ -//===- tools/dsymutil/DwarfLinker.h - Dwarf debug info linker ---*- C++ -*-===// +//===- tools/dsymutil/DwarfLinkerForBinary.h --------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,33 +10,17 @@ #define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H #include "BinaryHolder.h" -#include "CompileUnit.h" #include "DebugMap.h" -#include "DeclContext.h" #include "DwarfStreamer.h" #include "LinkUtils.h" +#include "llvm/DWARFLinker/DWARFLinker.h" +#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" +#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" namespace llvm { namespace dsymutil { -/// Partial address range for debug map objects. Besides an offset, only the -/// HighPC is stored. The structure is stored in a map where the LowPC is the -/// key. -struct DebugMapObjectRange { - /// Function HighPC. - uint64_t HighPC; - /// Offset to apply to the linked address. - int64_t Offset; - - DebugMapObjectRange(uint64_t EndPC, int64_t Offset) - : HighPC(EndPC), Offset(Offset) {} - - DebugMapObjectRange() : HighPC(0), Offset(0) {} -}; - -/// Map LowPC to DebugMapObjectRange. -using RangesTy = std::map<uint64_t, DebugMapObjectRange>; using UnitListTy = std::vector<std::unique_ptr<CompileUnit>>; /// The core of the Dwarf linking logic. @@ -53,10 +37,10 @@ using UnitListTy = std::vector<std::unique_ptr<CompileUnit>>; /// a function, the location for a variable). These relocations are /// called ValidRelocs in the DwarfLinker and are gathered as a very /// first step when we start processing a DebugMapObject. -class DwarfLinker { +class DwarfLinkerForBinary { public: - DwarfLinker(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, - LinkOptions Options) + DwarfLinkerForBinary(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, + LinkOptions Options) : OutFile(OutFile), BinHolder(BinHolder), Options(std::move(Options)) {} /// Link the contents of the DebugMap. @@ -74,6 +58,7 @@ public: TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents. TF_SkipPC = 1 << 5, ///< Skip all location attributes. }; + private: /// Remembers the oldest and newest DWARF version we've seen in a unit. void updateDwarfVersion(unsigned Version) { @@ -89,7 +74,7 @@ private: OffsetsStringPool &StringPool); /// Keeps track of relocations. - class RelocationManager { + class RelocationManager : public AddressesMap { struct ValidReloc { uint64_t Offset; uint32_t Size; @@ -105,7 +90,7 @@ private: } }; - const DwarfLinker &Linker; + const DwarfLinkerForBinary &Linker; /// The valid relocations for the current DebugMapObject. /// This vector is sorted by relocation offset. @@ -117,13 +102,48 @@ private: /// cheap lookup during the root DIE selection and during DIE cloning. unsigned NextValidReloc = 0; + RangesTy AddressRanges; + public: - RelocationManager(DwarfLinker &Linker) : Linker(Linker) {} + RelocationManager(DwarfLinkerForBinary &Linker, + const object::ObjectFile &Obj, const DebugMapObject &DMO) + : Linker(Linker) { + findValidRelocsInDebugInfo(Obj, DMO); + + // Iterate over the debug map entries and put all the ones that are + // functions (because they have a size) into the Ranges map. This map is + // very similar to the FunctionRanges that are stored in each unit, with 2 + // notable differences: + // + // 1. Obviously this one is global, while the other ones are per-unit. + // + // 2. This one contains not only the functions described in the DIE + // tree, but also the ones that are only in the debug map. + // + // The latter information is required to reproduce dsymutil's logic while + // linking line tables. The cases where this information matters look like + // bugs that need to be investigated, but for now we need to reproduce + // dsymutil's behavior. + // FIXME: Once we understood exactly if that information is needed, + // maybe totally remove this (or try to use it to do a real + // -gline-tables-only on Darwin. + for (const auto &Entry : DMO.symbols()) { + const auto &Mapping = Entry.getValue(); + if (Mapping.Size && Mapping.ObjectAddress) + AddressRanges[*Mapping.ObjectAddress] = ObjFileAddressRange( + *Mapping.ObjectAddress + Mapping.Size, + int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress); + } + } + virtual ~RelocationManager() override { clear(); } - bool hasValidRelocs() const { return !ValidRelocs.empty(); } + virtual bool areRelocationsResolved() const override { return true; } - /// Reset the NextValidReloc counter. - void resetValidRelocs() { NextValidReloc = 0; } + bool hasValidRelocs(bool ResetRelocsPtr = true) override { + if (ResetRelocsPtr) + NextValidReloc = 0; + return !ValidRelocs.empty(); + } /// \defgroup FindValidRelocations Translate debug map into a list /// of relevant relocations @@ -141,32 +161,44 @@ private: const DebugMapObject &DMO); /// @} - bool hasValidRelocation(uint64_t StartOffset, uint64_t EndOffset, - CompileUnit::DIEInfo &Info); + bool hasValidRelocationAt(uint64_t StartOffset, uint64_t EndOffset, + CompileUnit::DIEInfo &Info) override; bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset, - bool IsLittleEndian); + bool IsLittleEndian) override; + + RangesTy &getValidAddressRanges() override { return AddressRanges; } + + void clear() override { + AddressRanges.clear(); + ValidRelocs.clear(); + NextValidReloc = 0; + } }; /// Keeps track of data associated with one object during linking. struct LinkContext { + DwarfLinkerForBinary &Linker; DebugMapObject &DMO; - const object::ObjectFile *ObjectFile; - RelocationManager RelocMgr; + const object::ObjectFile *ObjectFile = nullptr; + std::unique_ptr<RelocationManager> RelocMgr; std::unique_ptr<DWARFContext> DwarfContext; RangesTy Ranges; UnitListTy CompileUnits; - LinkContext(const DebugMap &Map, DwarfLinker &Linker, DebugMapObject &DMO) - : DMO(DMO), RelocMgr(Linker) { + LinkContext(const DebugMap &Map, DwarfLinkerForBinary &Linker, + DebugMapObject &DMO) + : Linker(Linker), DMO(DMO) { // Swift ASTs are not object files. if (DMO.getType() == MachO::N_AST) { ObjectFile = nullptr; return; } - auto ErrOrObj = Linker.loadObject(DMO, Map); - ObjectFile = ErrOrObj ? &*ErrOrObj : nullptr; - DwarfContext = ObjectFile ? DWARFContext::create(*ObjectFile) : nullptr; + if (auto ErrOrObj = Linker.loadObject(DMO, Map)) { + ObjectFile = &*ErrOrObj; + DwarfContext = DWARFContext::create(*ObjectFile); + RelocMgr.reset(new RelocationManager(Linker, *ObjectFile, DMO)); + } } /// Clear part of the context that's no longer needed when we're done with @@ -175,6 +207,7 @@ private: DwarfContext.reset(nullptr); CompileUnits.clear(); Ranges.clear(); + RelocMgr->clear(); } }; @@ -224,7 +257,6 @@ private: unsigned &UnitID, bool IsLittleEndian, unsigned Indent = 0, bool Quiet = false); - /// Mark the passed DIE as well as all the ones it depends on as kept. void keepDIEAndDependencies(RelocationManager &RelocMgr, RangesTy &Ranges, const UnitListTy &Units, const DWARFDie &DIE, @@ -258,7 +290,7 @@ private: /// @{ class DIECloner { - DwarfLinker &Linker; + DwarfLinkerForBinary &Linker; RelocationManager &RelocMgr; /// Allocator used for all the DIEValue objects. @@ -268,7 +300,7 @@ private: LinkOptions Options; public: - DIECloner(DwarfLinker &Linker, RelocationManager &RelocMgr, + DIECloner(DwarfLinkerForBinary &Linker, RelocationManager &RelocMgr, BumpPtrAllocator &DIEAlloc, std::vector<std::unique_ptr<CompileUnit>> &CompileUnits, LinkOptions &Options) @@ -409,7 +441,7 @@ private: }; /// Assign an abbreviation number to \p Abbrev - void AssignAbbrev(DIEAbbrev &Abbrev); + void assignAbbrev(DIEAbbrev &Abbrev); /// Compute and emit debug_ranges section for \p Unit, and /// patch the attributes referencing it. diff --git a/llvm/tools/dsymutil/DwarfStreamer.cpp b/llvm/tools/dsymutil/DwarfStreamer.cpp index 8747aee458f..54cec3c4f68 100644 --- a/llvm/tools/dsymutil/DwarfStreamer.cpp +++ b/llvm/tools/dsymutil/DwarfStreamer.cpp @@ -7,10 +7,10 @@ //===----------------------------------------------------------------------===// #include "DwarfStreamer.h" -#include "CompileUnit.h" #include "LinkUtils.h" #include "MachOUtils.h" #include "llvm/ADT/Triple.h" +#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/MCTargetOptionsCommandFlags.inc" diff --git a/llvm/tools/dsymutil/DwarfStreamer.h b/llvm/tools/dsymutil/DwarfStreamer.h index baf215ac131..8479970a4f7 100644 --- a/llvm/tools/dsymutil/DwarfStreamer.h +++ b/llvm/tools/dsymutil/DwarfStreamer.h @@ -9,12 +9,12 @@ #ifndef LLVM_TOOLS_DSYMUTIL_DWARFSTREAMER_H #define LLVM_TOOLS_DSYMUTIL_DWARFSTREAMER_H -#include "CompileUnit.h" #include "DebugMap.h" #include "LinkUtils.h" #include "llvm/CodeGen/AccelTable.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/NonRelocatableStringpool.h" +#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/MC/MCAsmBackend.h" diff --git a/llvm/tools/dsymutil/LLVMBuild.txt b/llvm/tools/dsymutil/LLVMBuild.txt index 61bc07b81d3..819d3c4b30d 100644 --- a/llvm/tools/dsymutil/LLVMBuild.txt +++ b/llvm/tools/dsymutil/LLVMBuild.txt @@ -18,4 +18,4 @@ type = Tool name = dsymutil parent = Tools -required_libraries = AsmPrinter DebugInfoDWARF MC Object CodeGen Support all-targets +required_libraries = AsmPrinter DebugInfoDWARF DWARFLinker MC Object CodeGen Support all-targets |