diff options
author | Alexey Lapshin <a.v.lapshin@mail.ru> | 2019-12-08 01:37:53 +0300 |
---|---|---|
committer | Alexey Lapshin <a.v.lapshin@mail.ru> | 2019-12-19 15:41:48 +0300 |
commit | abc7f6800df8a1f40e1e2c9ccce826abb0208284 (patch) | |
tree | 79a527c3eef37db531326b979889fe5ec0294ff1 /llvm/tools | |
parent | a59cc5e128f09ec5048c142cafaadea279406eba (diff) | |
download | bcm5719-llvm-abc7f6800df8a1f40e1e2c9ccce826abb0208284.tar.gz bcm5719-llvm-abc7f6800df8a1f40e1e2c9ccce826abb0208284.zip |
[Dsymutil][Debuginfo][NFC] Refactor dsymutil to separate DWARF optimizing part 2.
That patch is extracted from the D70709. It moves CompileUnit, DeclContext
into llvm/DebugInfo/DWARF. It also adds new file DWARFOptimizer with
AddressesMap class. AddressesMap generalizes functionality
from RelocationManager.
Differential Revision: https://reviews.llvm.org/D71271
Diffstat (limited to 'llvm/tools')
-rw-r--r-- | llvm/tools/dsymutil/CMakeLists.txt | 2 | ||||
-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/DwarfLinker.cpp | 52 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfLinker.h | 99 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfStreamer.cpp | 2 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfStreamer.h | 2 |
9 files changed, 82 insertions, 933 deletions
diff --git a/llvm/tools/dsymutil/CMakeLists.txt b/llvm/tools/dsymutil/CMakeLists.txt index b8466baa634..e21215b2417 100644 --- a/llvm/tools/dsymutil/CMakeLists.txt +++ b/llvm/tools/dsymutil/CMakeLists.txt @@ -22,9 +22,7 @@ add_llvm_tool(dsymutil dsymutil.cpp BinaryHolder.cpp CFBundle.cpp - CompileUnit.cpp DebugMap.cpp - DeclContext.cpp DwarfLinker.cpp DwarfStreamer.cpp MachODebugMapParser.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/DwarfLinker.cpp index 64acab69843..521d3635dab 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -9,7 +9,6 @@ #include "DwarfLinker.h" #include "BinaryHolder.h" #include "DebugMap.h" -#include "DeclContext.h" #include "DwarfStreamer.h" #include "MachOUtils.h" #include "dsymutil.h" @@ -45,6 +44,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFOptDeclContext.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/MC/MCAsmBackend.h" @@ -374,30 +374,6 @@ static bool dieNeedsChildrenToBeMeaningful(uint32_t 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 DwarfLinker::endDebugObject(LinkContext &Context) { @@ -560,7 +536,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 DwarfLinker::RelocationManager::hasValidRelocationAt( uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) { assert(NextValidReloc == 0 || StartOffset > ValidRelocs[NextValidReloc - 1].Offset); @@ -651,7 +627,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; @@ -689,7 +666,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) { @@ -724,7 +701,7 @@ 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; } @@ -1651,7 +1628,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 @@ -2393,7 +2371,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()); @@ -2774,8 +2752,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"; @@ -2892,7 +2869,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); @@ -2901,10 +2878,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()); diff --git a/llvm/tools/dsymutil/DwarfLinker.h b/llvm/tools/dsymutil/DwarfLinker.h index b8d8e9d02e3..748377f802b 100644 --- a/llvm/tools/dsymutil/DwarfLinker.h +++ b/llvm/tools/dsymutil/DwarfLinker.h @@ -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/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFOptCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFOptDeclContext.h" +#include "llvm/DebugInfo/DWARF/DWARFOptimizer.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. @@ -89,7 +73,7 @@ private: OffsetsStringPool &StringPool); /// Keeps track of relocations. - class RelocationManager { + class RelocationManager : public AddressesMap { struct ValidReloc { uint64_t Offset; uint32_t Size; @@ -117,13 +101,50 @@ private: /// cheap lookup during the root DIE selection and during DIE cloning. unsigned NextValidReloc = 0; + RangesTy AddressRanges; + public: - RelocationManager(DwarfLinker &Linker) : Linker(Linker) {} + RelocationManager(DwarfLinker &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 +162,43 @@ 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 { + DwarfLinker &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) { + : 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(); } }; diff --git a/llvm/tools/dsymutil/DwarfStreamer.cpp b/llvm/tools/dsymutil/DwarfStreamer.cpp index 8747aee458f..33dc9fc850b 100644 --- a/llvm/tools/dsymutil/DwarfStreamer.cpp +++ b/llvm/tools/dsymutil/DwarfStreamer.cpp @@ -7,11 +7,11 @@ //===----------------------------------------------------------------------===// #include "DwarfStreamer.h" -#include "CompileUnit.h" #include "LinkUtils.h" #include "MachOUtils.h" #include "llvm/ADT/Triple.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFOptCompileUnit.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/MCTargetOptionsCommandFlags.inc" #include "llvm/Support/LEB128.h" diff --git a/llvm/tools/dsymutil/DwarfStreamer.h b/llvm/tools/dsymutil/DwarfStreamer.h index baf215ac131..85e3d48b758 100644 --- a/llvm/tools/dsymutil/DwarfStreamer.h +++ b/llvm/tools/dsymutil/DwarfStreamer.h @@ -9,7 +9,6 @@ #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" @@ -17,6 +16,7 @@ #include "llvm/CodeGen/NonRelocatableStringpool.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFOptCompileUnit.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeEmitter.h" |