summaryrefslogtreecommitdiffstats
path: root/llvm/tools
diff options
context:
space:
mode:
authorEric Christopher <echristo@gmail.com>2019-12-19 13:24:54 -0800
committerEric Christopher <echristo@gmail.com>2019-12-19 13:29:02 -0800
commit3075cd5c9fcc313701443a869e2d3a189311e919 (patch)
tree4c0831e12305e5205009cf72d72b2fe0edf3b992 /llvm/tools
parent918d393972237fe2f9c0f4c7cd14ed4ec4ba706a (diff)
downloadbcm5719-llvm-3075cd5c9fcc313701443a869e2d3a189311e919.tar.gz
bcm5719-llvm-3075cd5c9fcc313701443a869e2d3a189311e919.zip
Temporarily Revert "[Dsymutil][Debuginfo][NFC] Refactor dsymutil to separate DWARF optimizing part 2."
as it causes a layering violation/dependency cycle: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp -> llvm/DebugInfo/DWARF/DWARFExpression.h llvm/include/llvm/DebugInfo/DWARF/DWARFOptimizer.h -> llvm/CodeGen/NonRelocatableStringpool.h This reverts commit abc7f6800df8a1f40e1e2c9ccce826abb0208284.
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/dsymutil/CMakeLists.txt2
-rw-r--r--llvm/tools/dsymutil/CompileUnit.cpp146
-rw-r--r--llvm/tools/dsymutil/CompileUnit.h331
-rw-r--r--llvm/tools/dsymutil/DeclContext.cpp210
-rw-r--r--llvm/tools/dsymutil/DeclContext.h171
-rw-r--r--llvm/tools/dsymutil/DwarfLinker.cpp52
-rw-r--r--llvm/tools/dsymutil/DwarfLinker.h99
-rw-r--r--llvm/tools/dsymutil/DwarfStreamer.cpp2
-rw-r--r--llvm/tools/dsymutil/DwarfStreamer.h2
9 files changed, 933 insertions, 82 deletions
diff --git a/llvm/tools/dsymutil/CMakeLists.txt b/llvm/tools/dsymutil/CMakeLists.txt
index e21215b2417..b8466baa634 100644
--- a/llvm/tools/dsymutil/CMakeLists.txt
+++ b/llvm/tools/dsymutil/CMakeLists.txt
@@ -22,7 +22,9 @@ 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
new file mode 100644
index 00000000000..036c61a6b92
--- /dev/null
+++ b/llvm/tools/dsymutil/CompileUnit.cpp
@@ -0,0 +1,146 @@
+//===- 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
new file mode 100644
index 00000000000..e0f5d3bc65b
--- /dev/null
+++ b/llvm/tools/dsymutil/CompileUnit.h
@@ -0,0 +1,331 @@
+//===- 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
new file mode 100644
index 00000000000..1c33b672c26
--- /dev/null
+++ b/llvm/tools/dsymutil/DeclContext.cpp
@@ -0,0 +1,210 @@
+//===- 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
new file mode 100644
index 00000000000..36ef5094408
--- /dev/null
+++ b/llvm/tools/dsymutil/DeclContext.h
@@ -0,0 +1,171 @@
+//===- 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 521d3635dab..64acab69843 100644
--- a/llvm/tools/dsymutil/DwarfLinker.cpp
+++ b/llvm/tools/dsymutil/DwarfLinker.cpp
@@ -9,6 +9,7 @@
#include "DwarfLinker.h"
#include "BinaryHolder.h"
#include "DebugMap.h"
+#include "DeclContext.h"
#include "DwarfStreamer.h"
#include "MachOUtils.h"
#include "dsymutil.h"
@@ -44,7 +45,6 @@
#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,6 +374,30 @@ 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) {
@@ -536,7 +560,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::hasValidRelocationAt(
+bool DwarfLinker::RelocationManager::hasValidRelocation(
uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) {
assert(NextValidReloc == 0 ||
StartOffset > ValidRelocs[NextValidReloc - 1].Offset);
@@ -627,8 +651,7 @@ 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.hasValidRelocationAt(LocationOffset, LocationEndOffset,
- MyInfo) ||
+ if (!RelocMgr.hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) ||
(Flags & TF_InFunctionScope))
return Flags;
@@ -666,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.hasValidRelocationAt(LowPcOffset, LowPcEndOffset, MyInfo))
+ !RelocMgr.hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo))
return Flags;
if (Options.Verbose) {
@@ -701,7 +724,7 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE(
}
// Replace the debug map range with a more accurate one.
- Ranges[*LowPc] = ObjFileAddressRange(*HighPc, MyInfo.AddrAdjust);
+ Ranges[*LowPc] = DebugMapObjectRange(*HighPc, MyInfo.AddrAdjust);
Unit.addFunctionRange(*LowPc, *HighPc, MyInfo.AddrAdjust);
return Flags;
}
@@ -1628,8 +1651,7 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
Data =
DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
// Modify the copy with relocated addresses.
- if (RelocMgr.areRelocationsResolved() &&
- RelocMgr.applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) {
+ if (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
@@ -2371,7 +2393,7 @@ Error DwarfLinker::loadClangModule(
// Setup access to the debug info.
auto DwarfContext = DWARFContext::create(*ErrOrObj);
- RelocationManager RelocMgr(*this, *ErrOrObj, DMO);
+ RelocationManager RelocMgr(*this);
for (const auto &CU : DwarfContext->compile_units()) {
updateDwarfVersion(CU->getVersion());
@@ -2752,7 +2774,8 @@ bool DwarfLinker::link(const DebugMap &Map) {
// Look for relocations that correspond to debug map entries.
if (LLVM_LIKELY(!Options.Update) &&
- !LinkContext.RelocMgr->hasValidRelocs()) {
+ !LinkContext.RelocMgr.findValidRelocsInDebugInfo(
+ *LinkContext.ObjectFile, LinkContext.DMO)) {
if (Options.Verbose)
outs() << "No valid relocations found. Skipping.\n";
@@ -2869,7 +2892,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);
@@ -2878,9 +2901,10 @@ 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.
- if (LinkContext.RelocMgr->hasValidRelocs() || LLVM_UNLIKELY(Options.Update))
- DIECloner(*this, *LinkContext.RelocMgr, DIEAlloc,
- LinkContext.CompileUnits, Options)
+ LinkContext.RelocMgr.resetValidRelocs();
+ 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 748377f802b..b8d8e9d02e3 100644
--- a/llvm/tools/dsymutil/DwarfLinker.h
+++ b/llvm/tools/dsymutil/DwarfLinker.h
@@ -10,17 +10,33 @@
#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.
@@ -73,7 +89,7 @@ private:
OffsetsStringPool &StringPool);
/// Keeps track of relocations.
- class RelocationManager : public AddressesMap {
+ class RelocationManager {
struct ValidReloc {
uint64_t Offset;
uint32_t Size;
@@ -101,50 +117,13 @@ private:
/// cheap lookup during the root DIE selection and during DIE cloning.
unsigned NextValidReloc = 0;
- RangesTy AddressRanges;
-
public:
- 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();
- }
+ RelocationManager(DwarfLinker &Linker) : Linker(Linker) {}
- virtual bool areRelocationsResolved() const override { return true; }
+ bool hasValidRelocs() const { return !ValidRelocs.empty(); }
- bool hasValidRelocs(bool resetRelocsPtr = true) override {
- if (resetRelocsPtr)
- NextValidReloc = 0;
- return !ValidRelocs.empty();
- }
+ /// Reset the NextValidReloc counter.
+ void resetValidRelocs() { NextValidReloc = 0; }
/// \defgroup FindValidRelocations Translate debug map into a list
/// of relevant relocations
@@ -162,43 +141,32 @@ private:
const DebugMapObject &DMO);
/// @}
- bool hasValidRelocationAt(uint64_t StartOffset, uint64_t EndOffset,
- CompileUnit::DIEInfo &Info) override;
+ bool hasValidRelocation(uint64_t StartOffset, uint64_t EndOffset,
+ CompileUnit::DIEInfo &Info);
bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
- bool IsLittleEndian) override;
-
- RangesTy &getValidAddressRanges() override { return AddressRanges; }
-
- void clear() override {
- AddressRanges.clear();
- ValidRelocs.clear();
- NextValidReloc = 0;
- }
+ bool IsLittleEndian);
};
/// Keeps track of data associated with one object during linking.
struct LinkContext {
- DwarfLinker &Linker;
DebugMapObject &DMO;
- const object::ObjectFile *ObjectFile = nullptr;
- std::unique_ptr<RelocationManager> RelocMgr;
+ const object::ObjectFile *ObjectFile;
+ RelocationManager RelocMgr;
std::unique_ptr<DWARFContext> DwarfContext;
RangesTy Ranges;
UnitListTy CompileUnits;
LinkContext(const DebugMap &Map, DwarfLinker &Linker, DebugMapObject &DMO)
- : Linker(Linker), DMO(DMO) {
+ : DMO(DMO), RelocMgr(Linker) {
// Swift ASTs are not object files.
if (DMO.getType() == MachO::N_AST) {
ObjectFile = nullptr;
return;
}
- if (auto ErrOrObj = Linker.loadObject(DMO, Map)) {
- ObjectFile = &*ErrOrObj;
- DwarfContext = DWARFContext::create(*ObjectFile);
- RelocMgr.reset(new RelocationManager(Linker, *ObjectFile, DMO));
- }
+ auto ErrOrObj = Linker.loadObject(DMO, Map);
+ ObjectFile = ErrOrObj ? &*ErrOrObj : nullptr;
+ DwarfContext = ObjectFile ? DWARFContext::create(*ObjectFile) : nullptr;
}
/// Clear part of the context that's no longer needed when we're done with
@@ -207,7 +175,6 @@ 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 33dc9fc850b..8747aee458f 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 85e3d48b758..baf215ac131 100644
--- a/llvm/tools/dsymutil/DwarfStreamer.h
+++ b/llvm/tools/dsymutil/DwarfStreamer.h
@@ -9,6 +9,7 @@
#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"
@@ -16,7 +17,6 @@
#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"
OpenPOWER on IntegriCloud