dsymutil.cpp
BinaryHolder.cpp
CFBundle.cpp
+ CompileUnit.cpp
DebugMap.cpp
+ DeclContext.cpp
DwarfLinker.cpp
+ DwarfStreamer.cpp
MachODebugMapParser.cpp
MachOUtils.cpp
NonRelocatableStringpool.cpp
--- /dev/null
+//===- tools/dsymutil/CompileUnit.h - Dwarf compile unit ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#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;
+}
+
+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 + 11 /* Header size */;
+ // The root DIE might be null, meaning that the Unit had nothing to
+ // contribute to the linked output. In that case, we will emit the
+ // unit header without any actual DIE.
+ if (NewUnit)
+ 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) {
+ 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
--- /dev/null
+//===- tools/dsymutil/CompileUnit.h - Dwarf debug info linker ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+
+#ifndef LLVM_TOOLS_DSYMUTIL_COMPILEUNIT_H
+#define LLVM_TOOLS_DSYMUTIL_COMPILEUNIT_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(); }
+ 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;
+ }
+
+private:
+ DWARFUnit &OrigUnit;
+ unsigned ID;
+ std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
+ Optional<BasicDIEUnit> NewUnit;
+
+ 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;
+
+ /// 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
//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//
//
-// The LLVM Linker
+// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//=- tools/dsymutil/DebugMap.h - Generic debug map representation -*- C++ -*-=//
//
-// The LLVM Linker
+// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
--- /dev/null
+//===- tools/dsymutil/DeclContext.cpp - Declaration context ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#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
--- /dev/null
+//===- tools/dsymutil/DeclContext.h - Dwarf debug info linker ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CompileUnit.h"
+#include "NonRelocatableStringpool.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/Support/Path.h"
+
+#ifndef LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H
+#define LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_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
//===- tools/dsymutil/DwarfLinker.cpp - Dwarf debug info linker -----------===//
//
-// The LLVM Linker
+// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include "DwarfLinker.h"
#include "BinaryHolder.h"
#include "DebugMap.h"
+#include "DeclContext.h"
+#include "DwarfStreamer.h"
#include "MachOUtils.h"
#include "NonRelocatableStringpool.h"
#include "dsymutil.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptions.h"
-#include "llvm/MC/MCTargetOptionsCommandFlags.inc"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/SymbolicFile.h"
namespace llvm {
namespace dsymutil {
-namespace {
-
-/// Helper for making strong types.
-template <typename T, typename S> class StrongType : public T {
-public:
- template <typename... Args>
- explicit StrongType(Args... A) : T(std::forward<Args>(A)...) {}
-};
-
-/// It's very easy to introduce bugs by passing the wrong string pool. By using
-/// strong types the interface enforces that the right kind of pool is used.
-struct UniqueTag {};
-struct OffsetsTag {};
-using UniquingStringPool = StrongType<NonRelocatableStringpool, UniqueTag>;
-using OffsetsStringPool = StrongType<NonRelocatableStringpool, OffsetsTag>;
-
-/// 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;
-};
-
-/// Retrieve the section named \a SecName in \a Obj.
-///
-/// To accommodate for platform discrepancies, the name passed should be
-/// (for example) 'debug_info' to match either '__debug_info' or '.debug_info'.
-/// This function will strip the initial platform-specific characters.
-static Optional<object::SectionRef>
-getSectionByName(const object::ObjectFile &Obj, StringRef SecName) {
- for (const object::SectionRef &Section : Obj.sections()) {
- StringRef SectionName;
- Section.getName(SectionName);
- SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
- if (SectionName != SecName)
- continue;
- return Section;
- }
- return None;
-}
-
-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();
- }
-};
-
-class CompileUnit;
-struct DeclMapInfo;
-
-/// 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 {
- 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;
-
-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; }
-};
-
-/// 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;
- }
-};
-
-/// This class gives a tree-like API to the DenseMap that stores the
-/// DeclContext objects. It also holds the BumpPtrAllocator where
-/// these objects will be allocated.
-class DeclContextTree {
- BumpPtrAllocator Allocator;
- DeclContext Root;
- DeclContext::Map Contexts;
-
- /// Cache resolved paths from the line table.
- CachedPathResolver PathResolver;
-
-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; }
-};
-
-/// 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(); }
- 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;
- }
-
-private:
- DWARFUnit &OrigUnit;
- unsigned ID;
- std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
- Optional<BasicDIEUnit> NewUnit;
-
- 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;
-
- /// If this is a Clang module, this holds the module's name.
- std::string ClangModuleName;
-};
-
-/// 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;
-}
-} // namespace
-
-void warn(Twine Warning, Twine Context) {
- WithColor::warning() << Warning + "\n";
- if (!Context.isTriviallyEmpty())
- WithColor::note() << Twine("while processing ") + Context + "\n";
-}
-
-bool error(Twine Error, Twine Context) {
- WithColor::error() << Error + "\n";
- if (!Context.isTriviallyEmpty())
- WithColor::note() << Twine("while processing ") + Context + "\n";
- return false;
-}
-
-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 + 11 /* Header size */;
- // The root DIE might be null, meaning that the Unit had nothing to
- // contribute to the linked output. In that case, we will emit the
- // unit header without any actual DIE.
- if (NewUnit)
- 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) {
- 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 {
-
-/// The Dwarf streaming logic
-///
-/// All interactions with the MC layer that is used to build the debug
-/// information binary representation are handled in this class.
-class DwarfStreamer {
- /// \defgroup MCObjects MC layer objects constructed by the streamer
- /// @{
- std::unique_ptr<MCRegisterInfo> MRI;
- std::unique_ptr<MCAsmInfo> MAI;
- std::unique_ptr<MCObjectFileInfo> MOFI;
- std::unique_ptr<MCContext> MC;
- MCAsmBackend *MAB; // Owned by MCStreamer
- std::unique_ptr<MCInstrInfo> MII;
- std::unique_ptr<MCSubtargetInfo> MSTI;
- MCCodeEmitter *MCE; // Owned by MCStreamer
- MCStreamer *MS; // Owned by AsmPrinter
- std::unique_ptr<TargetMachine> TM;
- std::unique_ptr<AsmPrinter> Asm;
- /// @}
-
- /// The file we stream the linked Dwarf to.
- raw_fd_ostream &OutFile;
-
- uint32_t RangesSectionSize;
- uint32_t LocSectionSize;
- uint32_t LineSectionSize;
- uint32_t FrameSectionSize;
-
- /// Emit the pubnames or pubtypes section contribution for \p
- /// Unit into \p Sec. The data is provided in \p Names.
- void emitPubSectionForUnit(MCSection *Sec, StringRef Name,
- const CompileUnit &Unit,
- const std::vector<CompileUnit::AccelInfo> &Names);
-
-public:
- DwarfStreamer(raw_fd_ostream &OutFile) : OutFile(OutFile) {}
- bool init(Triple TheTriple);
-
- /// Dump the file to the disk.
- bool finish(const DebugMap &);
-
- AsmPrinter &getAsmPrinter() const { return *Asm; }
-
- /// Set the current output section to debug_info and change
- /// the MC Dwarf version to \p DwarfVersion.
- void switchToDebugInfoSection(unsigned DwarfVersion);
-
- /// Emit the compilation unit header for \p Unit in the
- /// debug_info section.
- ///
- /// As a side effect, this also switches the current Dwarf version
- /// of the MC layer to the one of U.getOrigUnit().
- void emitCompileUnitHeader(CompileUnit &Unit);
-
- /// Recursively emit the DIE tree rooted at \p Die.
- void emitDIE(DIE &Die);
-
- /// Emit the abbreviation table \p Abbrevs to the debug_abbrev section.
- void emitAbbrevs(const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs,
- unsigned DwarfVersion);
-
- /// Emit the string table described by \p Pool.
- void emitStrings(const NonRelocatableStringpool &Pool);
-
- /// Emit the swift_ast section stored in \p Buffer.
- void emitSwiftAST(StringRef Buffer);
-
- /// Emit debug_ranges for \p FuncRange by translating the
- /// original \p Entries.
- void emitRangesEntries(
- int64_t UnitPcOffset, uint64_t OrigLowPc,
- const FunctionIntervals::const_iterator &FuncRange,
- const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries,
- unsigned AddressSize);
-
- /// Emit debug_aranges entries for \p Unit and if \p DoRangesSection is true,
- /// also emit the debug_ranges entries for the DW_TAG_compile_unit's
- /// DW_AT_ranges attribute.
- void emitUnitRangesEntries(CompileUnit &Unit, bool DoRangesSection);
-
- uint32_t getRangesSectionSize() const { return RangesSectionSize; }
-
- /// Emit the debug_loc contribution for \p Unit by copying the entries from
- /// \p Dwarf and offsetting them. Update the location attributes to point to
- /// the new entries.
- void emitLocationsForUnit(const CompileUnit &Unit, DWARFContext &Dwarf);
-
- /// Emit the line table described in \p Rows into the debug_line section.
- void emitLineTableForUnit(MCDwarfLineTableParams Params,
- StringRef PrologueBytes, unsigned MinInstLength,
- std::vector<DWARFDebugLine::Row> &Rows,
- unsigned AdddressSize);
-
- /// Copy over the debug sections that are not modified when updating.
- void copyInvariantDebugSection(const object::ObjectFile &Obj, LinkOptions &);
-
- uint32_t getLineSectionSize() const { return LineSectionSize; }
-
- /// Emit the .debug_pubnames contribution for \p Unit.
- void emitPubNamesForUnit(const CompileUnit &Unit);
-
- /// Emit the .debug_pubtypes contribution for \p Unit.
- void emitPubTypesForUnit(const CompileUnit &Unit);
-
- /// Emit a CIE.
- void emitCIE(StringRef CIEBytes);
-
- /// Emit an FDE with data \p Bytes.
- void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint32_t Address,
- StringRef Bytes);
-
- /// Emit Apple namespaces accelerator table.
- void emitAppleNamespaces(AccelTable<AppleAccelTableStaticOffsetData> &Table);
-
- /// Emit Apple names accelerator table.
- void emitAppleNames(AccelTable<AppleAccelTableStaticOffsetData> &Table);
-
- /// Emit Apple Objective-C accelerator table.
- void emitAppleObjc(AccelTable<AppleAccelTableStaticOffsetData> &Table);
-
- /// Emit Apple type accelerator table.
- void emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> &Table);
-
- uint32_t getFrameSectionSize() const { return FrameSectionSize; }
-};
-
-} // end anonymous namespace
-
-bool DwarfStreamer::init(Triple TheTriple) {
- std::string ErrorStr;
- std::string TripleName;
- StringRef Context = "dwarf streamer init";
-
- // Get the target.
- const Target *TheTarget =
- TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
- if (!TheTarget)
- return error(ErrorStr, Context);
- TripleName = TheTriple.getTriple();
-
- // Create all the MC Objects.
- MRI.reset(TheTarget->createMCRegInfo(TripleName));
- if (!MRI)
- return error(Twine("no register info for target ") + TripleName, Context);
-
- MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName));
- if (!MAI)
- return error("no asm info for target " + TripleName, Context);
-
- MOFI.reset(new MCObjectFileInfo);
- MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get()));
- MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, *MC);
-
- MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
- if (!MSTI)
- return error("no subtarget info for target " + TripleName, Context);
-
- MCTargetOptions Options;
- MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, Options);
- if (!MAB)
- return error("no asm backend for target " + TripleName, Context);
-
- MII.reset(TheTarget->createMCInstrInfo());
- if (!MII)
- return error("no instr info info for target " + TripleName, Context);
-
- MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC);
- if (!MCE)
- return error("no code emitter for target " + TripleName, Context);
-
- MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
- MS = TheTarget->createMCObjectStreamer(
- TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
- MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE),
- *MSTI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible,
- /*DWARFMustBeAtTheEnd*/ false);
- if (!MS)
- return error("no object streamer for target " + TripleName, Context);
-
- // Finally create the AsmPrinter we'll use to emit the DIEs.
- TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
- None));
- if (!TM)
- return error("no target machine for target " + TripleName, Context);
-
- Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
- if (!Asm)
- return error("no asm printer for target " + TripleName, Context);
-
- RangesSectionSize = 0;
- LocSectionSize = 0;
- LineSectionSize = 0;
- FrameSectionSize = 0;
-
- return true;
-}
-
-bool DwarfStreamer::finish(const DebugMap &DM) {
- bool Result = true;
- if (DM.getTriple().isOSDarwin() && !DM.getBinaryPath().empty())
- Result = MachOUtils::generateDsymCompanion(DM, *MS, OutFile);
- else
- MS->Finish();
- return Result;
-}
-
-void DwarfStreamer::switchToDebugInfoSection(unsigned DwarfVersion) {
- MS->SwitchSection(MOFI->getDwarfInfoSection());
- MC->setDwarfVersion(DwarfVersion);
-}
-
-/// Emit the compilation unit header for \p Unit in the debug_info section.
-///
-/// A Dwarf section header is encoded as:
-/// uint32_t Unit length (omitting this field)
-/// uint16_t Version
-/// uint32_t Abbreviation table offset
-/// uint8_t Address size
-///
-/// Leading to a total of 11 bytes.
-void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) {
- unsigned Version = Unit.getOrigUnit().getVersion();
- switchToDebugInfoSection(Version);
-
- // Emit size of content not including length itself. The size has already
- // been computed in CompileUnit::computeOffsets(). Subtract 4 to that size to
- // account for the length field.
- Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset() - 4);
- Asm->emitInt16(Version);
- // We share one abbreviations table across all units so it's always at the
- // start of the section.
- Asm->emitInt32(0);
- Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize());
-}
-
-/// Emit the \p Abbrevs array as the shared abbreviation table
-/// for the linked Dwarf file.
-void DwarfStreamer::emitAbbrevs(
- const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs,
- unsigned DwarfVersion) {
- MS->SwitchSection(MOFI->getDwarfAbbrevSection());
- MC->setDwarfVersion(DwarfVersion);
- Asm->emitDwarfAbbrevs(Abbrevs);
-}
-
-/// Recursively emit the DIE tree rooted at \p Die.
-void DwarfStreamer::emitDIE(DIE &Die) {
- MS->SwitchSection(MOFI->getDwarfInfoSection());
- Asm->emitDwarfDIE(Die);
-}
-
-/// Emit the debug_str section stored in \p Pool.
-void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
- Asm->OutStreamer->SwitchSection(MOFI->getDwarfStrSection());
- std::vector<DwarfStringPoolEntryRef> Entries = Pool.getEntries();
- for (auto Entry : Entries) {
- if (Entry.getIndex() == -1U)
- break;
- // Emit the string itself.
- Asm->OutStreamer->EmitBytes(Entry.getString());
- // Emit a null terminator.
- Asm->emitInt8(0);
- }
-}
-
-void DwarfStreamer::emitAppleNamespaces(
- AccelTable<AppleAccelTableStaticOffsetData> &Table) {
- Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamespaceSection());
- auto *SectionBegin = Asm->createTempSymbol("namespac_begin");
- Asm->OutStreamer->EmitLabel(SectionBegin);
- emitAppleAccelTable(Asm.get(), Table, "namespac", SectionBegin);
-}
-
-void DwarfStreamer::emitAppleNames(
- AccelTable<AppleAccelTableStaticOffsetData> &Table) {
- Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamesSection());
- auto *SectionBegin = Asm->createTempSymbol("names_begin");
- Asm->OutStreamer->EmitLabel(SectionBegin);
- emitAppleAccelTable(Asm.get(), Table, "names", SectionBegin);
-}
-
-void DwarfStreamer::emitAppleObjc(
- AccelTable<AppleAccelTableStaticOffsetData> &Table) {
- Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelObjCSection());
- auto *SectionBegin = Asm->createTempSymbol("objc_begin");
- Asm->OutStreamer->EmitLabel(SectionBegin);
- emitAppleAccelTable(Asm.get(), Table, "objc", SectionBegin);
-}
-
-void DwarfStreamer::emitAppleTypes(
- AccelTable<AppleAccelTableStaticTypeData> &Table) {
- Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelTypesSection());
- auto *SectionBegin = Asm->createTempSymbol("types_begin");
- Asm->OutStreamer->EmitLabel(SectionBegin);
- emitAppleAccelTable(Asm.get(), Table, "types", SectionBegin);
-}
-
-/// Emit the swift_ast section stored in \p Buffers.
-void DwarfStreamer::emitSwiftAST(StringRef Buffer) {
- MCSection *SwiftASTSection = MOFI->getDwarfSwiftASTSection();
- SwiftASTSection->setAlignment(1 << 5);
- MS->SwitchSection(SwiftASTSection);
- MS->EmitBytes(Buffer);
-}
-
-/// Emit the debug_range section contents for \p FuncRange by
-/// translating the original \p Entries. The debug_range section
-/// format is totally trivial, consisting just of pairs of address
-/// sized addresses describing the ranges.
-void DwarfStreamer::emitRangesEntries(
- int64_t UnitPcOffset, uint64_t OrigLowPc,
- const FunctionIntervals::const_iterator &FuncRange,
- const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries,
- unsigned AddressSize) {
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
-
- // Offset each range by the right amount.
- int64_t PcOffset = Entries.empty() ? 0 : FuncRange.value() + UnitPcOffset;
- for (const auto &Range : Entries) {
- if (Range.isBaseAddressSelectionEntry(AddressSize)) {
- warn("unsupported base address selection operation",
- "emitting debug_ranges");
- break;
- }
- // Do not emit empty ranges.
- if (Range.StartAddress == Range.EndAddress)
- continue;
-
- // All range entries should lie in the function range.
- if (!(Range.StartAddress + OrigLowPc >= FuncRange.start() &&
- Range.EndAddress + OrigLowPc <= FuncRange.stop()))
- warn("inconsistent range data.", "emitting debug_ranges");
- MS->EmitIntValue(Range.StartAddress + PcOffset, AddressSize);
- MS->EmitIntValue(Range.EndAddress + PcOffset, AddressSize);
- RangesSectionSize += 2 * AddressSize;
- }
-
- // Add the terminator entry.
- MS->EmitIntValue(0, AddressSize);
- MS->EmitIntValue(0, AddressSize);
- RangesSectionSize += 2 * AddressSize;
-}
-
-/// Emit the debug_aranges contribution of a unit and
-/// if \p DoDebugRanges is true the debug_range contents for a
-/// compile_unit level DW_AT_ranges attribute (Which are basically the
-/// same thing with a different base address).
-/// Just aggregate all the ranges gathered inside that unit.
-void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit,
- bool DoDebugRanges) {
- unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
- // Gather the ranges in a vector, so that we can simplify them. The
- // IntervalMap will have coalesced the non-linked ranges, but here
- // we want to coalesce the linked addresses.
- std::vector<std::pair<uint64_t, uint64_t>> Ranges;
- const auto &FunctionRanges = Unit.getFunctionRanges();
- for (auto Range = FunctionRanges.begin(), End = FunctionRanges.end();
- Range != End; ++Range)
- Ranges.push_back(std::make_pair(Range.start() + Range.value(),
- Range.stop() + Range.value()));
-
- // The object addresses where sorted, but again, the linked
- // addresses might end up in a different order.
- llvm::sort(Ranges.begin(), Ranges.end());
-
- if (!Ranges.empty()) {
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection());
-
- MCSymbol *BeginLabel = Asm->createTempSymbol("Barange");
- MCSymbol *EndLabel = Asm->createTempSymbol("Earange");
-
- unsigned HeaderSize =
- sizeof(int32_t) + // Size of contents (w/o this field
- sizeof(int16_t) + // DWARF ARange version number
- sizeof(int32_t) + // Offset of CU in the .debug_info section
- sizeof(int8_t) + // Pointer Size (in bytes)
- sizeof(int8_t); // Segment Size (in bytes)
-
- unsigned TupleSize = AddressSize * 2;
- unsigned Padding = OffsetToAlignment(HeaderSize, TupleSize);
-
- Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Arange length
- Asm->OutStreamer->EmitLabel(BeginLabel);
- Asm->emitInt16(dwarf::DW_ARANGES_VERSION); // Version number
- Asm->emitInt32(Unit.getStartOffset()); // Corresponding unit's offset
- Asm->emitInt8(AddressSize); // Address size
- Asm->emitInt8(0); // Segment size
-
- Asm->OutStreamer->emitFill(Padding, 0x0);
-
- for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End;
- ++Range) {
- uint64_t RangeStart = Range->first;
- MS->EmitIntValue(RangeStart, AddressSize);
- while ((Range + 1) != End && Range->second == (Range + 1)->first)
- ++Range;
- MS->EmitIntValue(Range->second - RangeStart, AddressSize);
- }
-
- // Emit terminator
- Asm->OutStreamer->EmitIntValue(0, AddressSize);
- Asm->OutStreamer->EmitIntValue(0, AddressSize);
- Asm->OutStreamer->EmitLabel(EndLabel);
- }
-
- if (!DoDebugRanges)
- return;
-
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
- // Offset each range by the right amount.
- int64_t PcOffset = -Unit.getLowPc();
- // Emit coalesced ranges.
- for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) {
- MS->EmitIntValue(Range->first + PcOffset, AddressSize);
- while (Range + 1 != End && Range->second == (Range + 1)->first)
- ++Range;
- MS->EmitIntValue(Range->second + PcOffset, AddressSize);
- RangesSectionSize += 2 * AddressSize;
- }
-
- // Add the terminator entry.
- MS->EmitIntValue(0, AddressSize);
- MS->EmitIntValue(0, AddressSize);
- RangesSectionSize += 2 * AddressSize;
-}
-
-/// Emit location lists for \p Unit and update attributes to point to the new
-/// entries.
-void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
- DWARFContext &Dwarf) {
- const auto &Attributes = Unit.getLocationAttributes();
-
- if (Attributes.empty())
- return;
-
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection());
-
- unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
- const DWARFSection &InputSec = Dwarf.getDWARFObj().getLocSection();
- DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize);
- DWARFUnit &OrigUnit = Unit.getOrigUnit();
- auto OrigUnitDie = OrigUnit.getUnitDIE(false);
- int64_t UnitPcOffset = 0;
- if (auto OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc)))
- UnitPcOffset = int64_t(*OrigLowPc) - Unit.getLowPc();
-
- for (const auto &Attr : Attributes) {
- uint32_t Offset = Attr.first.get();
- Attr.first.set(LocSectionSize);
- // This is the quantity to add to the old location address to get
- // the correct address for the new one.
- int64_t LocPcOffset = Attr.second + UnitPcOffset;
- while (Data.isValidOffset(Offset)) {
- uint64_t Low = Data.getUnsigned(&Offset, AddressSize);
- uint64_t High = Data.getUnsigned(&Offset, AddressSize);
- LocSectionSize += 2 * AddressSize;
- if (Low == 0 && High == 0) {
- Asm->OutStreamer->EmitIntValue(0, AddressSize);
- Asm->OutStreamer->EmitIntValue(0, AddressSize);
- break;
- }
- Asm->OutStreamer->EmitIntValue(Low + LocPcOffset, AddressSize);
- Asm->OutStreamer->EmitIntValue(High + LocPcOffset, AddressSize);
- uint64_t Length = Data.getU16(&Offset);
- Asm->OutStreamer->EmitIntValue(Length, 2);
- // Just copy the bytes over.
- Asm->OutStreamer->EmitBytes(
- StringRef(InputSec.Data.substr(Offset, Length)));
- Offset += Length;
- LocSectionSize += Length + 2;
- }
- }
-}
-
-void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
- StringRef PrologueBytes,
- unsigned MinInstLength,
- std::vector<DWARFDebugLine::Row> &Rows,
- unsigned PointerSize) {
- // Switch to the section where the table will be emitted into.
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
- MCSymbol *LineStartSym = MC->createTempSymbol();
- MCSymbol *LineEndSym = MC->createTempSymbol();
-
- // The first 4 bytes is the total length of the information for this
- // compilation unit (not including these 4 bytes for the length).
- Asm->EmitLabelDifference(LineEndSym, LineStartSym, 4);
- Asm->OutStreamer->EmitLabel(LineStartSym);
- // Copy Prologue.
- MS->EmitBytes(PrologueBytes);
- LineSectionSize += PrologueBytes.size() + 4;
-
- SmallString<128> EncodingBuffer;
- raw_svector_ostream EncodingOS(EncodingBuffer);
-
- if (Rows.empty()) {
- // We only have the dummy entry, dsymutil emits an entry with a 0
- // address in that case.
- MCDwarfLineAddr::Encode(*MC, Params, std::numeric_limits<int64_t>::max(), 0,
- EncodingOS);
- MS->EmitBytes(EncodingOS.str());
- LineSectionSize += EncodingBuffer.size();
- MS->EmitLabel(LineEndSym);
- return;
- }
-
- // Line table state machine fields
- unsigned FileNum = 1;
- unsigned LastLine = 1;
- unsigned Column = 0;
- unsigned IsStatement = 1;
- unsigned Isa = 0;
- uint64_t Address = -1ULL;
-
- unsigned RowsSinceLastSequence = 0;
-
- for (unsigned Idx = 0; Idx < Rows.size(); ++Idx) {
- auto &Row = Rows[Idx];
-
- int64_t AddressDelta;
- if (Address == -1ULL) {
- MS->EmitIntValue(dwarf::DW_LNS_extended_op, 1);
- MS->EmitULEB128IntValue(PointerSize + 1);
- MS->EmitIntValue(dwarf::DW_LNE_set_address, 1);
- MS->EmitIntValue(Row.Address, PointerSize);
- LineSectionSize += 2 + PointerSize + getULEB128Size(PointerSize + 1);
- AddressDelta = 0;
- } else {
- AddressDelta = (Row.Address - Address) / MinInstLength;
- }
-
- // FIXME: code copied and transformed from MCDwarf.cpp::EmitDwarfLineTable.
- // We should find a way to share this code, but the current compatibility
- // requirement with classic dsymutil makes it hard. Revisit that once this
- // requirement is dropped.
-
- if (FileNum != Row.File) {
- FileNum = Row.File;
- MS->EmitIntValue(dwarf::DW_LNS_set_file, 1);
- MS->EmitULEB128IntValue(FileNum);
- LineSectionSize += 1 + getULEB128Size(FileNum);
- }
- if (Column != Row.Column) {
- Column = Row.Column;
- MS->EmitIntValue(dwarf::DW_LNS_set_column, 1);
- MS->EmitULEB128IntValue(Column);
- LineSectionSize += 1 + getULEB128Size(Column);
- }
-
- // FIXME: We should handle the discriminator here, but dsymutil doesn't
- // consider it, thus ignore it for now.
-
- if (Isa != Row.Isa) {
- Isa = Row.Isa;
- MS->EmitIntValue(dwarf::DW_LNS_set_isa, 1);
- MS->EmitULEB128IntValue(Isa);
- LineSectionSize += 1 + getULEB128Size(Isa);
- }
- if (IsStatement != Row.IsStmt) {
- IsStatement = Row.IsStmt;
- MS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1);
- LineSectionSize += 1;
- }
- if (Row.BasicBlock) {
- MS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1);
- LineSectionSize += 1;
- }
-
- if (Row.PrologueEnd) {
- MS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1);
- LineSectionSize += 1;
- }
-
- if (Row.EpilogueBegin) {
- MS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1);
- LineSectionSize += 1;
- }
-
- int64_t LineDelta = int64_t(Row.Line) - LastLine;
- if (!Row.EndSequence) {
- MCDwarfLineAddr::Encode(*MC, Params, LineDelta, AddressDelta, EncodingOS);
- MS->EmitBytes(EncodingOS.str());
- LineSectionSize += EncodingBuffer.size();
- EncodingBuffer.resize(0);
- Address = Row.Address;
- LastLine = Row.Line;
- RowsSinceLastSequence++;
- } else {
- if (LineDelta) {
- MS->EmitIntValue(dwarf::DW_LNS_advance_line, 1);
- MS->EmitSLEB128IntValue(LineDelta);
- LineSectionSize += 1 + getSLEB128Size(LineDelta);
- }
- if (AddressDelta) {
- MS->EmitIntValue(dwarf::DW_LNS_advance_pc, 1);
- MS->EmitULEB128IntValue(AddressDelta);
- LineSectionSize += 1 + getULEB128Size(AddressDelta);
- }
- MCDwarfLineAddr::Encode(*MC, Params, std::numeric_limits<int64_t>::max(),
- 0, EncodingOS);
- MS->EmitBytes(EncodingOS.str());
- LineSectionSize += EncodingBuffer.size();
- EncodingBuffer.resize(0);
- Address = -1ULL;
- LastLine = FileNum = IsStatement = 1;
- RowsSinceLastSequence = Column = Isa = 0;
- }
- }
-
- if (RowsSinceLastSequence) {
- MCDwarfLineAddr::Encode(*MC, Params, std::numeric_limits<int64_t>::max(), 0,
- EncodingOS);
- MS->EmitBytes(EncodingOS.str());
- LineSectionSize += EncodingBuffer.size();
- EncodingBuffer.resize(0);
- }
-
- MS->EmitLabel(LineEndSym);
-}
-
-static void emitSectionContents(const object::ObjectFile &Obj,
- StringRef SecName, MCStreamer *MS) {
- StringRef Contents;
- if (auto Sec = getSectionByName(Obj, SecName))
- if (!Sec->getContents(Contents))
- MS->EmitBytes(Contents);
-}
-
-void DwarfStreamer::copyInvariantDebugSection(const object::ObjectFile &Obj,
- LinkOptions &Options) {
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
- emitSectionContents(Obj, "debug_line", MS);
-
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection());
- emitSectionContents(Obj, "debug_loc", MS);
-
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
- emitSectionContents(Obj, "debug_ranges", MS);
-
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
- emitSectionContents(Obj, "debug_frame", MS);
-
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection());
- emitSectionContents(Obj, "debug_aranges", MS);
-}
-
-/// Emit the pubnames or pubtypes section contribution for \p
-/// Unit into \p Sec. The data is provided in \p Names.
-void DwarfStreamer::emitPubSectionForUnit(
- MCSection *Sec, StringRef SecName, const CompileUnit &Unit,
- const std::vector<CompileUnit::AccelInfo> &Names) {
- if (Names.empty())
- return;
-
- // Start the dwarf pubnames section.
- Asm->OutStreamer->SwitchSection(Sec);
- MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + SecName + "_begin");
- MCSymbol *EndLabel = Asm->createTempSymbol("pub" + SecName + "_end");
-
- bool HeaderEmitted = false;
- // Emit the pubnames for this compilation unit.
- for (const auto &Name : Names) {
- if (Name.SkipPubSection)
- continue;
-
- if (!HeaderEmitted) {
- // Emit the header.
- Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Length
- Asm->OutStreamer->EmitLabel(BeginLabel);
- Asm->emitInt16(dwarf::DW_PUBNAMES_VERSION); // Version
- Asm->emitInt32(Unit.getStartOffset()); // Unit offset
- Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset()); // Size
- HeaderEmitted = true;
- }
- Asm->emitInt32(Name.Die->getOffset());
-
- // Emit the string itself.
- Asm->OutStreamer->EmitBytes(Name.Name.getString());
- // Emit a null terminator.
- Asm->emitInt8(0);
- }
-
- if (!HeaderEmitted)
- return;
- Asm->emitInt32(0); // End marker.
- Asm->OutStreamer->EmitLabel(EndLabel);
-}
-
-/// Emit .debug_pubnames for \p Unit.
-void DwarfStreamer::emitPubNamesForUnit(const CompileUnit &Unit) {
- emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubNamesSection(),
- "names", Unit, Unit.getPubnames());
-}
-
-/// Emit .debug_pubtypes for \p Unit.
-void DwarfStreamer::emitPubTypesForUnit(const CompileUnit &Unit) {
- emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubTypesSection(),
- "types", Unit, Unit.getPubtypes());
-}
-
-/// Emit a CIE into the debug_frame section.
-void DwarfStreamer::emitCIE(StringRef CIEBytes) {
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
-
- MS->EmitBytes(CIEBytes);
- FrameSectionSize += CIEBytes.size();
-}
-
-/// Emit a FDE into the debug_frame section. \p FDEBytes
-/// contains the FDE data without the length, CIE offset and address
-/// which will be replaced with the parameter values.
-void DwarfStreamer::emitFDE(uint32_t CIEOffset, uint32_t AddrSize,
- uint32_t Address, StringRef FDEBytes) {
- MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
-
- MS->EmitIntValue(FDEBytes.size() + 4 + AddrSize, 4);
- MS->EmitIntValue(CIEOffset, 4);
- MS->EmitIntValue(Address, AddrSize);
- MS->EmitBytes(FDEBytes);
- FrameSectionSize += FDEBytes.size() + 8 + AddrSize;
-}
-
-namespace {
-
-/// 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.
-///
-/// The link of the dwarf information from the object files will be
-/// driven by the selection of 'root DIEs', which are DIEs that
-/// describe variables or functions that are present in the linked
-/// binary (and thus have entries in the debug map). All the debug
-/// information that will be linked (the DIEs, but also the line
-/// tables, ranges, ...) is derived from that set of root DIEs.
-///
-/// The root DIEs are identified because they contain relocations that
-/// correspond to a debug map entry at specific places (the low_pc for
-/// a function, the location for a variable). These relocations are
-/// called ValidRelocs in the DwarfLinker and are gathered as a very
-/// first step when we start processing a DebugMapObject.
-class DwarfLinker {
-public:
- DwarfLinker(raw_fd_ostream &OutFile, const LinkOptions &Options)
- : OutFile(OutFile), Options(Options) {}
-
- /// Link the contents of the DebugMap.
- bool link(const DebugMap &);
-
- void reportWarning(const Twine &Warning, const DebugMapObject &DMO,
- const DWARFDie *DIE = nullptr) const;
-
-private:
- /// Remembers the newest DWARF version we've seen in a unit.
- void maybeUpdateMaxDwarfVersion(unsigned Version) {
- if (MaxDwarfVersion < Version)
- MaxDwarfVersion = Version;
- }
-
- /// Emit warnings as Dwarf compile units to leave a trail after linking.
- bool emitPaperTrailWarnings(const DebugMapObject &DMO, const DebugMap &Map,
- OffsetsStringPool &StringPool);
-
- /// Keeps track of relocations.
- class RelocationManager {
- struct ValidReloc {
- uint32_t Offset;
- uint32_t Size;
- uint64_t Addend;
- const DebugMapObject::DebugMapEntry *Mapping;
-
- ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend,
- const DebugMapObject::DebugMapEntry *Mapping)
- : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
-
- bool operator<(const ValidReloc &RHS) const {
- return Offset < RHS.Offset;
- }
- };
-
- const DwarfLinker &Linker;
-
- /// The valid relocations for the current DebugMapObject.
- /// This vector is sorted by relocation offset.
- std::vector<ValidReloc> ValidRelocs;
-
- /// Index into ValidRelocs of the next relocation to consider. As we walk
- /// the DIEs in acsending file offset and as ValidRelocs is sorted by file
- /// offset, keeping this index up to date is all we have to do to have a
- /// cheap lookup during the root DIE selection and during DIE cloning.
- unsigned NextValidReloc = 0;
-
- public:
- RelocationManager(DwarfLinker &Linker) : Linker(Linker) {}
-
- bool hasValidRelocs() const { return !ValidRelocs.empty(); }
-
- /// Reset the NextValidReloc counter.
- void resetValidRelocs() { NextValidReloc = 0; }
-
- /// \defgroup FindValidRelocations Translate debug map into a list
- /// of relevant relocations
- ///
- /// @{
- bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
- const DebugMapObject &DMO);
-
- bool findValidRelocs(const object::SectionRef &Section,
- const object::ObjectFile &Obj,
- const DebugMapObject &DMO);
-
- void findValidRelocsMachO(const object::SectionRef &Section,
- const object::MachOObjectFile &Obj,
- const DebugMapObject &DMO);
- /// @}
-
- bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
- CompileUnit::DIEInfo &Info);
-
- bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
- bool isLittleEndian);
- };
-
- /// Keeps track of data associated with one object during linking.
- struct LinkContext {
- DebugMapObject &DMO;
- BinaryHolder BinHolder;
- const object::ObjectFile *ObjectFile;
- RelocationManager RelocMgr;
- std::unique_ptr<DWARFContext> DwarfContext;
- RangesTy Ranges;
- UnitListTy CompileUnits;
-
- LinkContext(const DebugMap &Map, DwarfLinker &Linker, DebugMapObject &DMO,
- bool Verbose = false)
- : DMO(DMO), BinHolder(Verbose), RelocMgr(Linker) {
- // Swift ASTs are not object files.
- if (DMO.getType() == MachO::N_AST) {
- ObjectFile = nullptr;
- return;
- }
- auto ErrOrObj = Linker.loadObject(BinHolder, DMO, Map);
- ObjectFile = ErrOrObj ? &*ErrOrObj : nullptr;
- DwarfContext = ObjectFile ? DWARFContext::create(*ObjectFile) : nullptr;
- }
-
- /// Clear compile units and ranges.
- void Clear() {
- CompileUnits.clear();
- Ranges.clear();
- }
- };
-
- /// Called at the start of a debug object link.
- void startDebugObject(LinkContext &Context);
-
- /// Called at the end of a debug object link.
- void endDebugObject(LinkContext &Context);
-
- /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries.
- ///
- /// @{
- /// Recursively walk the \p DIE tree and look for DIEs to
- /// keep. Store that information in \p CU's DIEInfo.
- ///
- /// The return value indicates whether the DIE is incomplete.
- bool lookForDIEsToKeep(RelocationManager &RelocMgr, RangesTy &Ranges,
- UnitListTy &Units, const DWARFDie &DIE,
- const DebugMapObject &DMO, CompileUnit &CU,
- unsigned Flags);
-
- /// If this compile unit is really a skeleton CU that points to a
- /// clang module, register it in ClangModules and return true.
- ///
- /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
- /// pointing to the module, and a DW_AT_gnu_dwo_id with the module
- /// hash.
- bool registerModuleReference(const DWARFDie &CUDie, const DWARFUnit &Unit,
- DebugMap &ModuleMap, const DebugMapObject &DMO,
- RangesTy &Ranges,
- OffsetsStringPool &OffsetsStringPool,
- UniquingStringPool &UniquingStringPoolStringPool,
- DeclContextTree &ODRContexts, unsigned &UnitID,
- unsigned Indent = 0);
-
- /// Recursively add the debug info in this clang module .pcm
- /// file (and all the modules imported by it in a bottom-up fashion)
- /// to Units.
- Error loadClangModule(StringRef Filename, StringRef ModulePath,
- StringRef ModuleName, uint64_t DwoId,
- DebugMap &ModuleMap, const DebugMapObject &DMO,
- RangesTy &Ranges, OffsetsStringPool &OffsetsStringPool,
- UniquingStringPool &UniquingStringPool,
- DeclContextTree &ODRContexts, unsigned &UnitID,
- unsigned Indent = 0);
-
- /// Flags passed to DwarfLinker::lookForDIEsToKeep
- enum TraversalFlags {
- TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept.
- TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope.
- TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE.
- TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE.
- TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents.
- TF_SkipPC = 1 << 5, ///< Skip all location attributes.
- };
-
- /// Mark the passed DIE as well as all the ones it depends on as kept.
- void keepDIEAndDependencies(RelocationManager &RelocMgr, RangesTy &Ranges,
- UnitListTy &Units, const DWARFDie &DIE,
- CompileUnit::DIEInfo &MyInfo,
- const DebugMapObject &DMO, CompileUnit &CU,
- bool UseODR);
-
- unsigned shouldKeepDIE(RelocationManager &RelocMgr, RangesTy &Ranges,
- const DWARFDie &DIE, const DebugMapObject &DMO,
- CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
- unsigned Flags);
-
- unsigned shouldKeepVariableDIE(RelocationManager &RelocMgr,
- const DWARFDie &DIE, CompileUnit &Unit,
- CompileUnit::DIEInfo &MyInfo, unsigned Flags);
-
- unsigned shouldKeepSubprogramDIE(RelocationManager &RelocMgr,
- RangesTy &Ranges, const DWARFDie &DIE,
- const DebugMapObject &DMO, CompileUnit &Unit,
- CompileUnit::DIEInfo &MyInfo,
- unsigned Flags);
-
- bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
- CompileUnit::DIEInfo &Info);
- /// @}
-
- /// \defgroup Linking Methods used to link the debug information
- ///
- /// @{
-
- class DIECloner {
- DwarfLinker &Linker;
- RelocationManager &RelocMgr;
-
- /// Allocator used for all the DIEValue objects.
- BumpPtrAllocator &DIEAlloc;
-
- std::vector<std::unique_ptr<CompileUnit>> &CompileUnits;
- LinkOptions Options;
-
- public:
- DIECloner(DwarfLinker &Linker, RelocationManager &RelocMgr,
- BumpPtrAllocator &DIEAlloc,
- std::vector<std::unique_ptr<CompileUnit>> &CompileUnits,
- LinkOptions &Options)
- : Linker(Linker), RelocMgr(RelocMgr), DIEAlloc(DIEAlloc),
- CompileUnits(CompileUnits), Options(Options) {}
-
- /// Recursively clone \p InputDIE into an tree of DIE objects
- /// where useless (as decided by lookForDIEsToKeep()) bits have been
- /// stripped out and addresses have been rewritten according to the
- /// debug map.
- ///
- /// \param OutOffset is the offset the cloned DIE in the output
- /// compile unit.
- /// \param PCOffset (while cloning a function scope) is the offset
- /// applied to the entry point of the function to get the linked address.
- /// \param Die the output DIE to use, pass NULL to create one.
- /// \returns the root of the cloned tree or null if nothing was selected.
- DIE *cloneDIE(const DWARFDie &InputDIE, const DebugMapObject &DMO,
- CompileUnit &U, OffsetsStringPool &StringPool,
- int64_t PCOffset, uint32_t OutOffset, unsigned Flags,
- DIE *Die = nullptr);
-
- /// Construct the output DIE tree by cloning the DIEs we
- /// chose to keep above. If there are no valid relocs, then there's
- /// nothing to clone/emit.
- void cloneAllCompileUnits(DWARFContext &DwarfContext,
- const DebugMapObject &DMO, RangesTy &Ranges,
- OffsetsStringPool &StringPool);
-
- private:
- using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec;
-
- /// Information gathered and exchanged between the various
- /// clone*Attributes helpers about the attributes of a particular DIE.
- struct AttributesInfo {
- /// Names.
- DwarfStringPoolEntryRef Name, MangledName, NameWithoutTemplate;
-
- /// Offsets in the string pool.
- uint32_t NameOffset = 0;
- uint32_t MangledNameOffset = 0;
-
- /// Value of AT_low_pc in the input DIE
- uint64_t OrigLowPc = std::numeric_limits<uint64_t>::max();
-
- /// Value of AT_high_pc in the input DIE
- uint64_t OrigHighPc = 0;
-
- /// Offset to apply to PC addresses inside a function.
- int64_t PCOffset = 0;
-
- /// Does the DIE have a low_pc attribute?
- bool HasLowPc = false;
-
- /// Does the DIE have a ranges attribute?
- bool HasRanges = false;
-
- /// Is this DIE only a declaration?
- bool IsDeclaration = false;
-
- AttributesInfo() = default;
- };
-
- /// Helper for cloneDIE.
- unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE,
- const DebugMapObject &DMO, CompileUnit &U,
- OffsetsStringPool &StringPool,
- const DWARFFormValue &Val,
- const AttributeSpec AttrSpec, unsigned AttrSize,
- AttributesInfo &AttrInfo);
-
- /// Clone a string attribute described by \p AttrSpec and add
- /// it to \p Die.
- /// \returns the size of the new attribute.
- unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
- const DWARFFormValue &Val, const DWARFUnit &U,
- OffsetsStringPool &StringPool,
- AttributesInfo &Info);
-
- /// Clone an attribute referencing another DIE and add
- /// it to \p Die.
- /// \returns the size of the new attribute.
- unsigned cloneDieReferenceAttribute(DIE &Die, const DWARFDie &InputDIE,
- AttributeSpec AttrSpec,
- unsigned AttrSize,
- const DWARFFormValue &Val,
- const DebugMapObject &DMO,
- CompileUnit &Unit);
-
- /// Clone an attribute referencing another DIE and add
- /// it to \p Die.
- /// \returns the size of the new attribute.
- unsigned cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec,
- const DWARFFormValue &Val, unsigned AttrSize);
-
- /// Clone an attribute referencing another DIE and add
- /// it to \p Die.
- /// \returns the size of the new attribute.
- unsigned cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec,
- const DWARFFormValue &Val,
- const CompileUnit &Unit,
- AttributesInfo &Info);
-
- /// Clone a scalar attribute and add it to \p Die.
- /// \returns the size of the new attribute.
- unsigned cloneScalarAttribute(DIE &Die, const DWARFDie &InputDIE,
- const DebugMapObject &DMO, CompileUnit &U,
- AttributeSpec AttrSpec,
- const DWARFFormValue &Val, unsigned AttrSize,
- AttributesInfo &Info);
-
- /// Get the potential name and mangled name for the entity
- /// described by \p Die and store them in \Info if they are not
- /// already there.
- /// \returns is a name was found.
- bool getDIENames(const DWARFDie &Die, AttributesInfo &Info,
- OffsetsStringPool &StringPool, bool StripTemplate = false);
-
- /// Create a copy of abbreviation Abbrev.
- void copyAbbrev(const DWARFAbbreviationDeclaration &Abbrev, bool hasODR);
-
- uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U,
- const DebugMapObject &DMO,
- int RecurseDepth = 0);
-
- /// Helper for cloneDIE.
- void addObjCAccelerator(CompileUnit &Unit, const DIE *Die,
- DwarfStringPoolEntryRef Name,
- OffsetsStringPool &StringPool, bool SkipPubSection);
- };
-
- /// Assign an abbreviation number to \p Abbrev
- void AssignAbbrev(DIEAbbrev &Abbrev);
-
- /// Compute and emit debug_ranges section for \p Unit, and
- /// patch the attributes referencing it.
- void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf,
- const DebugMapObject &DMO) const;
-
- /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had
- /// one.
- void generateUnitRanges(CompileUnit &Unit) const;
-
- /// Extract the line tables from the original dwarf, extract the relevant
- /// parts according to the linked function ranges and emit the result in the
- /// debug_line section.
- void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf,
- RangesTy &Ranges, const DebugMapObject &DMO);
-
- /// Emit the accelerator entries for \p Unit.
- void emitAcceleratorEntriesForUnit(CompileUnit &Unit);
-
- /// Patch the frame info for an object file and emit it.
- void patchFrameInfoForObject(const DebugMapObject &, RangesTy &Ranges,
- DWARFContext &, unsigned AddressSize);
-
- /// FoldingSet that uniques the abbreviations.
- FoldingSet<DIEAbbrev> AbbreviationsSet;
-
- /// Storage for the unique Abbreviations.
- /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot be
- /// changed to a vector of unique_ptrs.
- std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
-
- /// DIELoc objects that need to be destructed (but not freed!).
- std::vector<DIELoc *> DIELocs;
-
- /// DIEBlock objects that need to be destructed (but not freed!).
- std::vector<DIEBlock *> DIEBlocks;
-
- /// Allocator used for all the DIEValue objects.
- BumpPtrAllocator DIEAlloc;
- /// @}
-
- /// \defgroup Helpers Various helper methods.
- ///
- /// @{
- bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile);
-
- /// Attempt to load a debug object from disk.
- ErrorOr<const object::ObjectFile &> loadObject(BinaryHolder &BinaryHolder,
- const DebugMapObject &Obj,
- const DebugMap &Map);
- /// @}
-
- raw_fd_ostream &OutFile;
- LinkOptions Options;
- std::unique_ptr<DwarfStreamer> Streamer;
- uint64_t OutputDebugInfoSize;
- unsigned MaxDwarfVersion = 0;
-
- /// The CIEs that have been emitted in the output section. The actual CIE
- /// data serves a the key to this StringMap, this takes care of comparing the
- /// semantics of CIEs defined in different object files.
- StringMap<uint32_t> EmittedCIEs;
-
- /// Offset of the last CIE that has been emitted in the output
- /// debug_frame section.
- uint32_t LastCIEOffset = 0;
-
- /// Apple accelerator tables.
- AccelTable<AppleAccelTableStaticOffsetData> AppleNames;
- AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces;
- AccelTable<AppleAccelTableStaticOffsetData> AppleObjc;
- AccelTable<AppleAccelTableStaticTypeData> AppleTypes;
-
- /// Mapping the PCM filename to the DwoId.
- StringMap<uint64_t> ClangModules;
-
- bool ModuleCacheHintDisplayed = false;
- bool ArchiveHintDisplayed = false;
-};
-
-} // end anonymous namespace
-
/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
/// CompileUnit object instead.
static CompileUnit *
llvm_unreachable("Improper attribute.");
}
-/// 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);
-}
-
bool DwarfLinker::DIECloner::getDIENames(const DWARFDie &Die,
AttributesInfo &Info,
OffsetsStringPool &StringPool,
--- /dev/null
+//===- tools/dsymutil/DwarfLinker.h - Dwarf debug info linker ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
+#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"
+
+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.
+///
+/// The link of the dwarf information from the object files will be
+/// driven by the selection of 'root DIEs', which are DIEs that
+/// describe variables or functions that are present in the linked
+/// binary (and thus have entries in the debug map). All the debug
+/// information that will be linked (the DIEs, but also the line
+/// tables, ranges, ...) is derived from that set of root DIEs.
+///
+/// The root DIEs are identified because they contain relocations that
+/// correspond to a debug map entry at specific places (the low_pc for
+/// a function, the location for a variable). These relocations are
+/// called ValidRelocs in the DwarfLinker and are gathered as a very
+/// first step when we start processing a DebugMapObject.
+class DwarfLinker {
+public:
+ DwarfLinker(raw_fd_ostream &OutFile, const LinkOptions &Options)
+ : OutFile(OutFile), Options(Options) {}
+
+ /// Link the contents of the DebugMap.
+ bool link(const DebugMap &);
+
+ void reportWarning(const Twine &Warning, const DebugMapObject &DMO,
+ const DWARFDie *DIE = nullptr) const;
+
+private:
+ /// Remembers the newest DWARF version we've seen in a unit.
+ void maybeUpdateMaxDwarfVersion(unsigned Version) {
+ if (MaxDwarfVersion < Version)
+ MaxDwarfVersion = Version;
+ }
+
+ /// Emit warnings as Dwarf compile units to leave a trail after linking.
+ bool emitPaperTrailWarnings(const DebugMapObject &DMO, const DebugMap &Map,
+ OffsetsStringPool &StringPool);
+
+ /// Keeps track of relocations.
+ class RelocationManager {
+ struct ValidReloc {
+ uint32_t Offset;
+ uint32_t Size;
+ uint64_t Addend;
+ const DebugMapObject::DebugMapEntry *Mapping;
+
+ ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend,
+ const DebugMapObject::DebugMapEntry *Mapping)
+ : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
+
+ bool operator<(const ValidReloc &RHS) const {
+ return Offset < RHS.Offset;
+ }
+ };
+
+ const DwarfLinker &Linker;
+
+ /// The valid relocations for the current DebugMapObject.
+ /// This vector is sorted by relocation offset.
+ std::vector<ValidReloc> ValidRelocs;
+
+ /// Index into ValidRelocs of the next relocation to consider. As we walk
+ /// the DIEs in acsending file offset and as ValidRelocs is sorted by file
+ /// offset, keeping this index up to date is all we have to do to have a
+ /// cheap lookup during the root DIE selection and during DIE cloning.
+ unsigned NextValidReloc = 0;
+
+ public:
+ RelocationManager(DwarfLinker &Linker) : Linker(Linker) {}
+
+ bool hasValidRelocs() const { return !ValidRelocs.empty(); }
+
+ /// Reset the NextValidReloc counter.
+ void resetValidRelocs() { NextValidReloc = 0; }
+
+ /// \defgroup FindValidRelocations Translate debug map into a list
+ /// of relevant relocations
+ ///
+ /// @{
+ bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
+ const DebugMapObject &DMO);
+
+ bool findValidRelocs(const object::SectionRef &Section,
+ const object::ObjectFile &Obj,
+ const DebugMapObject &DMO);
+
+ void findValidRelocsMachO(const object::SectionRef &Section,
+ const object::MachOObjectFile &Obj,
+ const DebugMapObject &DMO);
+ /// @}
+
+ bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
+ CompileUnit::DIEInfo &Info);
+
+ bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
+ bool isLittleEndian);
+ };
+
+ /// Keeps track of data associated with one object during linking.
+ struct LinkContext {
+ DebugMapObject &DMO;
+ BinaryHolder BinHolder;
+ const object::ObjectFile *ObjectFile;
+ RelocationManager RelocMgr;
+ std::unique_ptr<DWARFContext> DwarfContext;
+ RangesTy Ranges;
+ UnitListTy CompileUnits;
+
+ LinkContext(const DebugMap &Map, DwarfLinker &Linker, DebugMapObject &DMO,
+ bool Verbose = false)
+ : DMO(DMO), BinHolder(Verbose), RelocMgr(Linker) {
+ // Swift ASTs are not object files.
+ if (DMO.getType() == MachO::N_AST) {
+ ObjectFile = nullptr;
+ return;
+ }
+ auto ErrOrObj = Linker.loadObject(BinHolder, DMO, Map);
+ ObjectFile = ErrOrObj ? &*ErrOrObj : nullptr;
+ DwarfContext = ObjectFile ? DWARFContext::create(*ObjectFile) : nullptr;
+ }
+
+ /// Clear compile units and ranges.
+ void Clear() {
+ CompileUnits.clear();
+ Ranges.clear();
+ }
+ };
+
+ /// Called at the start of a debug object link.
+ void startDebugObject(LinkContext &Context);
+
+ /// Called at the end of a debug object link.
+ void endDebugObject(LinkContext &Context);
+
+ /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries.
+ ///
+ /// @{
+ /// Recursively walk the \p DIE tree and look for DIEs to
+ /// keep. Store that information in \p CU's DIEInfo.
+ ///
+ /// The return value indicates whether the DIE is incomplete.
+ bool lookForDIEsToKeep(RelocationManager &RelocMgr, RangesTy &Ranges,
+ UnitListTy &Units, const DWARFDie &DIE,
+ const DebugMapObject &DMO, CompileUnit &CU,
+ unsigned Flags);
+
+ /// If this compile unit is really a skeleton CU that points to a
+ /// clang module, register it in ClangModules and return true.
+ ///
+ /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
+ /// pointing to the module, and a DW_AT_gnu_dwo_id with the module
+ /// hash.
+ bool registerModuleReference(const DWARFDie &CUDie, const DWARFUnit &Unit,
+ DebugMap &ModuleMap, const DebugMapObject &DMO,
+ RangesTy &Ranges,
+ OffsetsStringPool &OffsetsStringPool,
+ UniquingStringPool &UniquingStringPoolStringPool,
+ DeclContextTree &ODRContexts, unsigned &UnitID,
+ unsigned Indent = 0);
+
+ /// Recursively add the debug info in this clang module .pcm
+ /// file (and all the modules imported by it in a bottom-up fashion)
+ /// to Units.
+ Error loadClangModule(StringRef Filename, StringRef ModulePath,
+ StringRef ModuleName, uint64_t DwoId,
+ DebugMap &ModuleMap, const DebugMapObject &DMO,
+ RangesTy &Ranges, OffsetsStringPool &OffsetsStringPool,
+ UniquingStringPool &UniquingStringPool,
+ DeclContextTree &ODRContexts, unsigned &UnitID,
+ unsigned Indent = 0);
+
+ /// Flags passed to DwarfLinker::lookForDIEsToKeep
+ enum TraversalFlags {
+ TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept.
+ TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope.
+ TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE.
+ TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE.
+ TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents.
+ TF_SkipPC = 1 << 5, ///< Skip all location attributes.
+ };
+
+ /// Mark the passed DIE as well as all the ones it depends on as kept.
+ void keepDIEAndDependencies(RelocationManager &RelocMgr, RangesTy &Ranges,
+ UnitListTy &Units, const DWARFDie &DIE,
+ CompileUnit::DIEInfo &MyInfo,
+ const DebugMapObject &DMO, CompileUnit &CU,
+ bool UseODR);
+
+ unsigned shouldKeepDIE(RelocationManager &RelocMgr, RangesTy &Ranges,
+ const DWARFDie &DIE, const DebugMapObject &DMO,
+ CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
+ unsigned Flags);
+
+ unsigned shouldKeepVariableDIE(RelocationManager &RelocMgr,
+ const DWARFDie &DIE, CompileUnit &Unit,
+ CompileUnit::DIEInfo &MyInfo, unsigned Flags);
+
+ unsigned shouldKeepSubprogramDIE(RelocationManager &RelocMgr,
+ RangesTy &Ranges, const DWARFDie &DIE,
+ const DebugMapObject &DMO, CompileUnit &Unit,
+ CompileUnit::DIEInfo &MyInfo,
+ unsigned Flags);
+
+ bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
+ CompileUnit::DIEInfo &Info);
+ /// @}
+
+ /// \defgroup Linking Methods used to link the debug information
+ ///
+ /// @{
+
+ class DIECloner {
+ DwarfLinker &Linker;
+ RelocationManager &RelocMgr;
+
+ /// Allocator used for all the DIEValue objects.
+ BumpPtrAllocator &DIEAlloc;
+
+ std::vector<std::unique_ptr<CompileUnit>> &CompileUnits;
+ LinkOptions Options;
+
+ public:
+ DIECloner(DwarfLinker &Linker, RelocationManager &RelocMgr,
+ BumpPtrAllocator &DIEAlloc,
+ std::vector<std::unique_ptr<CompileUnit>> &CompileUnits,
+ LinkOptions &Options)
+ : Linker(Linker), RelocMgr(RelocMgr), DIEAlloc(DIEAlloc),
+ CompileUnits(CompileUnits), Options(Options) {}
+
+ /// Recursively clone \p InputDIE into an tree of DIE objects
+ /// where useless (as decided by lookForDIEsToKeep()) bits have been
+ /// stripped out and addresses have been rewritten according to the
+ /// debug map.
+ ///
+ /// \param OutOffset is the offset the cloned DIE in the output
+ /// compile unit.
+ /// \param PCOffset (while cloning a function scope) is the offset
+ /// applied to the entry point of the function to get the linked address.
+ /// \param Die the output DIE to use, pass NULL to create one.
+ /// \returns the root of the cloned tree or null if nothing was selected.
+ DIE *cloneDIE(const DWARFDie &InputDIE, const DebugMapObject &DMO,
+ CompileUnit &U, OffsetsStringPool &StringPool,
+ int64_t PCOffset, uint32_t OutOffset, unsigned Flags,
+ DIE *Die = nullptr);
+
+ /// Construct the output DIE tree by cloning the DIEs we
+ /// chose to keep above. If there are no valid relocs, then there's
+ /// nothing to clone/emit.
+ void cloneAllCompileUnits(DWARFContext &DwarfContext,
+ const DebugMapObject &DMO, RangesTy &Ranges,
+ OffsetsStringPool &StringPool);
+
+ private:
+ using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec;
+
+ /// Information gathered and exchanged between the various
+ /// clone*Attributes helpers about the attributes of a particular DIE.
+ struct AttributesInfo {
+ /// Names.
+ DwarfStringPoolEntryRef Name, MangledName, NameWithoutTemplate;
+
+ /// Offsets in the string pool.
+ uint32_t NameOffset = 0;
+ uint32_t MangledNameOffset = 0;
+
+ /// Value of AT_low_pc in the input DIE
+ uint64_t OrigLowPc = std::numeric_limits<uint64_t>::max();
+
+ /// Value of AT_high_pc in the input DIE
+ uint64_t OrigHighPc = 0;
+
+ /// Offset to apply to PC addresses inside a function.
+ int64_t PCOffset = 0;
+
+ /// Does the DIE have a low_pc attribute?
+ bool HasLowPc = false;
+
+ /// Does the DIE have a ranges attribute?
+ bool HasRanges = false;
+
+ /// Is this DIE only a declaration?
+ bool IsDeclaration = false;
+
+ AttributesInfo() = default;
+ };
+
+ /// Helper for cloneDIE.
+ unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE,
+ const DebugMapObject &DMO, CompileUnit &U,
+ OffsetsStringPool &StringPool,
+ const DWARFFormValue &Val,
+ const AttributeSpec AttrSpec, unsigned AttrSize,
+ AttributesInfo &AttrInfo);
+
+ /// Clone a string attribute described by \p AttrSpec and add
+ /// it to \p Die.
+ /// \returns the size of the new attribute.
+ unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val, const DWARFUnit &U,
+ OffsetsStringPool &StringPool,
+ AttributesInfo &Info);
+
+ /// Clone an attribute referencing another DIE and add
+ /// it to \p Die.
+ /// \returns the size of the new attribute.
+ unsigned cloneDieReferenceAttribute(DIE &Die, const DWARFDie &InputDIE,
+ AttributeSpec AttrSpec,
+ unsigned AttrSize,
+ const DWARFFormValue &Val,
+ const DebugMapObject &DMO,
+ CompileUnit &Unit);
+
+ /// Clone an attribute referencing another DIE and add
+ /// it to \p Die.
+ /// \returns the size of the new attribute.
+ unsigned cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val, unsigned AttrSize);
+
+ /// Clone an attribute referencing another DIE and add
+ /// it to \p Die.
+ /// \returns the size of the new attribute.
+ unsigned cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val,
+ const CompileUnit &Unit,
+ AttributesInfo &Info);
+
+ /// Clone a scalar attribute and add it to \p Die.
+ /// \returns the size of the new attribute.
+ unsigned cloneScalarAttribute(DIE &Die, const DWARFDie &InputDIE,
+ const DebugMapObject &DMO, CompileUnit &U,
+ AttributeSpec AttrSpec,
+ const DWARFFormValue &Val, unsigned AttrSize,
+ AttributesInfo &Info);
+
+ /// Get the potential name and mangled name for the entity
+ /// described by \p Die and store them in \Info if they are not
+ /// already there.
+ /// \returns is a name was found.
+ bool getDIENames(const DWARFDie &Die, AttributesInfo &Info,
+ OffsetsStringPool &StringPool, bool StripTemplate = false);
+
+ /// Create a copy of abbreviation Abbrev.
+ void copyAbbrev(const DWARFAbbreviationDeclaration &Abbrev, bool hasODR);
+
+ uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U,
+ const DebugMapObject &DMO,
+ int RecurseDepth = 0);
+
+ /// Helper for cloneDIE.
+ void addObjCAccelerator(CompileUnit &Unit, const DIE *Die,
+ DwarfStringPoolEntryRef Name,
+ OffsetsStringPool &StringPool, bool SkipPubSection);
+ };
+
+ /// Assign an abbreviation number to \p Abbrev
+ void AssignAbbrev(DIEAbbrev &Abbrev);
+
+ /// Compute and emit debug_ranges section for \p Unit, and
+ /// patch the attributes referencing it.
+ void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf,
+ const DebugMapObject &DMO) const;
+
+ /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had
+ /// one.
+ void generateUnitRanges(CompileUnit &Unit) const;
+
+ /// Extract the line tables from the original dwarf, extract the relevant
+ /// parts according to the linked function ranges and emit the result in the
+ /// debug_line section.
+ void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf,
+ RangesTy &Ranges, const DebugMapObject &DMO);
+
+ /// Emit the accelerator entries for \p Unit.
+ void emitAcceleratorEntriesForUnit(CompileUnit &Unit);
+
+ /// Patch the frame info for an object file and emit it.
+ void patchFrameInfoForObject(const DebugMapObject &, RangesTy &Ranges,
+ DWARFContext &, unsigned AddressSize);
+
+ /// FoldingSet that uniques the abbreviations.
+ FoldingSet<DIEAbbrev> AbbreviationsSet;
+
+ /// Storage for the unique Abbreviations.
+ /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot be
+ /// changed to a vector of unique_ptrs.
+ std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
+
+ /// DIELoc objects that need to be destructed (but not freed!).
+ std::vector<DIELoc *> DIELocs;
+
+ /// DIEBlock objects that need to be destructed (but not freed!).
+ std::vector<DIEBlock *> DIEBlocks;
+
+ /// Allocator used for all the DIEValue objects.
+ BumpPtrAllocator DIEAlloc;
+ /// @}
+
+ /// \defgroup Helpers Various helper methods.
+ ///
+ /// @{
+ bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile);
+
+ /// Attempt to load a debug object from disk.
+ ErrorOr<const object::ObjectFile &> loadObject(BinaryHolder &BinaryHolder,
+ const DebugMapObject &Obj,
+ const DebugMap &Map);
+ /// @}
+
+ raw_fd_ostream &OutFile;
+ LinkOptions Options;
+ std::unique_ptr<DwarfStreamer> Streamer;
+ uint64_t OutputDebugInfoSize;
+ unsigned MaxDwarfVersion = 0;
+
+ /// The CIEs that have been emitted in the output section. The actual CIE
+ /// data serves a the key to this StringMap, this takes care of comparing the
+ /// semantics of CIEs defined in different object files.
+ StringMap<uint32_t> EmittedCIEs;
+
+ /// Offset of the last CIE that has been emitted in the output
+ /// debug_frame section.
+ uint32_t LastCIEOffset = 0;
+
+ /// Apple accelerator tables.
+ AccelTable<AppleAccelTableStaticOffsetData> AppleNames;
+ AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces;
+ AccelTable<AppleAccelTableStaticOffsetData> AppleObjc;
+ AccelTable<AppleAccelTableStaticTypeData> AppleTypes;
+
+ /// Mapping the PCM filename to the DwoId.
+ StringMap<uint64_t> ClangModules;
+
+ bool ModuleCacheHintDisplayed = false;
+ bool ArchiveHintDisplayed = false;
+};
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
--- /dev/null
+//===- tools/dsymutil/DwarfStreamer.cpp - Dwarf Streamer ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DwarfStreamer.h"
+#include "LinkUtils.h"
+#include "MachOUtils.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.inc"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+
+namespace llvm {
+namespace dsymutil {
+
+/// Retrieve the section named \a SecName in \a Obj.
+///
+/// To accommodate for platform discrepancies, the name passed should be
+/// (for example) 'debug_info' to match either '__debug_info' or '.debug_info'.
+/// This function will strip the initial platform-specific characters.
+static Optional<object::SectionRef>
+getSectionByName(const object::ObjectFile &Obj, StringRef SecName) {
+ for (const object::SectionRef &Section : Obj.sections()) {
+ StringRef SectionName;
+ Section.getName(SectionName);
+ SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
+ if (SectionName != SecName)
+ continue;
+ return Section;
+ }
+ return None;
+}
+
+bool DwarfStreamer::init(Triple TheTriple) {
+ std::string ErrorStr;
+ std::string TripleName;
+ StringRef Context = "dwarf streamer init";
+
+ // Get the target.
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
+ if (!TheTarget)
+ return error(ErrorStr, Context);
+ TripleName = TheTriple.getTriple();
+
+ // Create all the MC Objects.
+ MRI.reset(TheTarget->createMCRegInfo(TripleName));
+ if (!MRI)
+ return error(Twine("no register info for target ") + TripleName, Context);
+
+ MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName));
+ if (!MAI)
+ return error("no asm info for target " + TripleName, Context);
+
+ MOFI.reset(new MCObjectFileInfo);
+ MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get()));
+ MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, *MC);
+
+ MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
+ if (!MSTI)
+ return error("no subtarget info for target " + TripleName, Context);
+
+ MCTargetOptions Options;
+ MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, Options);
+ if (!MAB)
+ return error("no asm backend for target " + TripleName, Context);
+
+ MII.reset(TheTarget->createMCInstrInfo());
+ if (!MII)
+ return error("no instr info info for target " + TripleName, Context);
+
+ MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC);
+ if (!MCE)
+ return error("no code emitter for target " + TripleName, Context);
+
+ MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
+ MS = TheTarget->createMCObjectStreamer(
+ TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
+ MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE),
+ *MSTI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible,
+ /*DWARFMustBeAtTheEnd*/ false);
+ if (!MS)
+ return error("no object streamer for target " + TripleName, Context);
+
+ // Finally create the AsmPrinter we'll use to emit the DIEs.
+ TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
+ None));
+ if (!TM)
+ return error("no target machine for target " + TripleName, Context);
+
+ Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
+ if (!Asm)
+ return error("no asm printer for target " + TripleName, Context);
+
+ RangesSectionSize = 0;
+ LocSectionSize = 0;
+ LineSectionSize = 0;
+ FrameSectionSize = 0;
+
+ return true;
+}
+
+bool DwarfStreamer::finish(const DebugMap &DM) {
+ bool Result = true;
+ if (DM.getTriple().isOSDarwin() && !DM.getBinaryPath().empty())
+ Result = MachOUtils::generateDsymCompanion(DM, *MS, OutFile);
+ else
+ MS->Finish();
+ return Result;
+}
+
+void DwarfStreamer::switchToDebugInfoSection(unsigned DwarfVersion) {
+ MS->SwitchSection(MOFI->getDwarfInfoSection());
+ MC->setDwarfVersion(DwarfVersion);
+}
+
+/// Emit the compilation unit header for \p Unit in the debug_info section.
+///
+/// A Dwarf section header is encoded as:
+/// uint32_t Unit length (omitting this field)
+/// uint16_t Version
+/// uint32_t Abbreviation table offset
+/// uint8_t Address size
+///
+/// Leading to a total of 11 bytes.
+void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) {
+ unsigned Version = Unit.getOrigUnit().getVersion();
+ switchToDebugInfoSection(Version);
+
+ // Emit size of content not including length itself. The size has already
+ // been computed in CompileUnit::computeOffsets(). Subtract 4 to that size to
+ // account for the length field.
+ Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset() - 4);
+ Asm->emitInt16(Version);
+ // We share one abbreviations table across all units so it's always at the
+ // start of the section.
+ Asm->emitInt32(0);
+ Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize());
+}
+
+/// Emit the \p Abbrevs array as the shared abbreviation table
+/// for the linked Dwarf file.
+void DwarfStreamer::emitAbbrevs(
+ const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs,
+ unsigned DwarfVersion) {
+ MS->SwitchSection(MOFI->getDwarfAbbrevSection());
+ MC->setDwarfVersion(DwarfVersion);
+ Asm->emitDwarfAbbrevs(Abbrevs);
+}
+
+/// Recursively emit the DIE tree rooted at \p Die.
+void DwarfStreamer::emitDIE(DIE &Die) {
+ MS->SwitchSection(MOFI->getDwarfInfoSection());
+ Asm->emitDwarfDIE(Die);
+}
+
+/// Emit the debug_str section stored in \p Pool.
+void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
+ Asm->OutStreamer->SwitchSection(MOFI->getDwarfStrSection());
+ std::vector<DwarfStringPoolEntryRef> Entries = Pool.getEntries();
+ for (auto Entry : Entries) {
+ if (Entry.getIndex() == -1U)
+ break;
+ // Emit the string itself.
+ Asm->OutStreamer->EmitBytes(Entry.getString());
+ // Emit a null terminator.
+ Asm->emitInt8(0);
+ }
+}
+
+void DwarfStreamer::emitAppleNamespaces(
+ AccelTable<AppleAccelTableStaticOffsetData> &Table) {
+ Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamespaceSection());
+ auto *SectionBegin = Asm->createTempSymbol("namespac_begin");
+ Asm->OutStreamer->EmitLabel(SectionBegin);
+ emitAppleAccelTable(Asm.get(), Table, "namespac", SectionBegin);
+}
+
+void DwarfStreamer::emitAppleNames(
+ AccelTable<AppleAccelTableStaticOffsetData> &Table) {
+ Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamesSection());
+ auto *SectionBegin = Asm->createTempSymbol("names_begin");
+ Asm->OutStreamer->EmitLabel(SectionBegin);
+ emitAppleAccelTable(Asm.get(), Table, "names", SectionBegin);
+}
+
+void DwarfStreamer::emitAppleObjc(
+ AccelTable<AppleAccelTableStaticOffsetData> &Table) {
+ Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelObjCSection());
+ auto *SectionBegin = Asm->createTempSymbol("objc_begin");
+ Asm->OutStreamer->EmitLabel(SectionBegin);
+ emitAppleAccelTable(Asm.get(), Table, "objc", SectionBegin);
+}
+
+void DwarfStreamer::emitAppleTypes(
+ AccelTable<AppleAccelTableStaticTypeData> &Table) {
+ Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelTypesSection());
+ auto *SectionBegin = Asm->createTempSymbol("types_begin");
+ Asm->OutStreamer->EmitLabel(SectionBegin);
+ emitAppleAccelTable(Asm.get(), Table, "types", SectionBegin);
+}
+
+/// Emit the swift_ast section stored in \p Buffers.
+void DwarfStreamer::emitSwiftAST(StringRef Buffer) {
+ MCSection *SwiftASTSection = MOFI->getDwarfSwiftASTSection();
+ SwiftASTSection->setAlignment(1 << 5);
+ MS->SwitchSection(SwiftASTSection);
+ MS->EmitBytes(Buffer);
+}
+
+/// Emit the debug_range section contents for \p FuncRange by
+/// translating the original \p Entries. The debug_range section
+/// format is totally trivial, consisting just of pairs of address
+/// sized addresses describing the ranges.
+void DwarfStreamer::emitRangesEntries(
+ int64_t UnitPcOffset, uint64_t OrigLowPc,
+ const FunctionIntervals::const_iterator &FuncRange,
+ const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries,
+ unsigned AddressSize) {
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
+
+ // Offset each range by the right amount.
+ int64_t PcOffset = Entries.empty() ? 0 : FuncRange.value() + UnitPcOffset;
+ for (const auto &Range : Entries) {
+ if (Range.isBaseAddressSelectionEntry(AddressSize)) {
+ warn("unsupported base address selection operation",
+ "emitting debug_ranges");
+ break;
+ }
+ // Do not emit empty ranges.
+ if (Range.StartAddress == Range.EndAddress)
+ continue;
+
+ // All range entries should lie in the function range.
+ if (!(Range.StartAddress + OrigLowPc >= FuncRange.start() &&
+ Range.EndAddress + OrigLowPc <= FuncRange.stop()))
+ warn("inconsistent range data.", "emitting debug_ranges");
+ MS->EmitIntValue(Range.StartAddress + PcOffset, AddressSize);
+ MS->EmitIntValue(Range.EndAddress + PcOffset, AddressSize);
+ RangesSectionSize += 2 * AddressSize;
+ }
+
+ // Add the terminator entry.
+ MS->EmitIntValue(0, AddressSize);
+ MS->EmitIntValue(0, AddressSize);
+ RangesSectionSize += 2 * AddressSize;
+}
+
+/// Emit the debug_aranges contribution of a unit and
+/// if \p DoDebugRanges is true the debug_range contents for a
+/// compile_unit level DW_AT_ranges attribute (Which are basically the
+/// same thing with a different base address).
+/// Just aggregate all the ranges gathered inside that unit.
+void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit,
+ bool DoDebugRanges) {
+ unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
+ // Gather the ranges in a vector, so that we can simplify them. The
+ // IntervalMap will have coalesced the non-linked ranges, but here
+ // we want to coalesce the linked addresses.
+ std::vector<std::pair<uint64_t, uint64_t>> Ranges;
+ const auto &FunctionRanges = Unit.getFunctionRanges();
+ for (auto Range = FunctionRanges.begin(), End = FunctionRanges.end();
+ Range != End; ++Range)
+ Ranges.push_back(std::make_pair(Range.start() + Range.value(),
+ Range.stop() + Range.value()));
+
+ // The object addresses where sorted, but again, the linked
+ // addresses might end up in a different order.
+ llvm::sort(Ranges.begin(), Ranges.end());
+
+ if (!Ranges.empty()) {
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection());
+
+ MCSymbol *BeginLabel = Asm->createTempSymbol("Barange");
+ MCSymbol *EndLabel = Asm->createTempSymbol("Earange");
+
+ unsigned HeaderSize =
+ sizeof(int32_t) + // Size of contents (w/o this field
+ sizeof(int16_t) + // DWARF ARange version number
+ sizeof(int32_t) + // Offset of CU in the .debug_info section
+ sizeof(int8_t) + // Pointer Size (in bytes)
+ sizeof(int8_t); // Segment Size (in bytes)
+
+ unsigned TupleSize = AddressSize * 2;
+ unsigned Padding = OffsetToAlignment(HeaderSize, TupleSize);
+
+ Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Arange length
+ Asm->OutStreamer->EmitLabel(BeginLabel);
+ Asm->emitInt16(dwarf::DW_ARANGES_VERSION); // Version number
+ Asm->emitInt32(Unit.getStartOffset()); // Corresponding unit's offset
+ Asm->emitInt8(AddressSize); // Address size
+ Asm->emitInt8(0); // Segment size
+
+ Asm->OutStreamer->emitFill(Padding, 0x0);
+
+ for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End;
+ ++Range) {
+ uint64_t RangeStart = Range->first;
+ MS->EmitIntValue(RangeStart, AddressSize);
+ while ((Range + 1) != End && Range->second == (Range + 1)->first)
+ ++Range;
+ MS->EmitIntValue(Range->second - RangeStart, AddressSize);
+ }
+
+ // Emit terminator
+ Asm->OutStreamer->EmitIntValue(0, AddressSize);
+ Asm->OutStreamer->EmitIntValue(0, AddressSize);
+ Asm->OutStreamer->EmitLabel(EndLabel);
+ }
+
+ if (!DoDebugRanges)
+ return;
+
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
+ // Offset each range by the right amount.
+ int64_t PcOffset = -Unit.getLowPc();
+ // Emit coalesced ranges.
+ for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) {
+ MS->EmitIntValue(Range->first + PcOffset, AddressSize);
+ while (Range + 1 != End && Range->second == (Range + 1)->first)
+ ++Range;
+ MS->EmitIntValue(Range->second + PcOffset, AddressSize);
+ RangesSectionSize += 2 * AddressSize;
+ }
+
+ // Add the terminator entry.
+ MS->EmitIntValue(0, AddressSize);
+ MS->EmitIntValue(0, AddressSize);
+ RangesSectionSize += 2 * AddressSize;
+}
+
+/// Emit location lists for \p Unit and update attributes to point to the new
+/// entries.
+void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
+ DWARFContext &Dwarf) {
+ const auto &Attributes = Unit.getLocationAttributes();
+
+ if (Attributes.empty())
+ return;
+
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection());
+
+ unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
+ const DWARFSection &InputSec = Dwarf.getDWARFObj().getLocSection();
+ DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize);
+ DWARFUnit &OrigUnit = Unit.getOrigUnit();
+ auto OrigUnitDie = OrigUnit.getUnitDIE(false);
+ int64_t UnitPcOffset = 0;
+ if (auto OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc)))
+ UnitPcOffset = int64_t(*OrigLowPc) - Unit.getLowPc();
+
+ for (const auto &Attr : Attributes) {
+ uint32_t Offset = Attr.first.get();
+ Attr.first.set(LocSectionSize);
+ // This is the quantity to add to the old location address to get
+ // the correct address for the new one.
+ int64_t LocPcOffset = Attr.second + UnitPcOffset;
+ while (Data.isValidOffset(Offset)) {
+ uint64_t Low = Data.getUnsigned(&Offset, AddressSize);
+ uint64_t High = Data.getUnsigned(&Offset, AddressSize);
+ LocSectionSize += 2 * AddressSize;
+ if (Low == 0 && High == 0) {
+ Asm->OutStreamer->EmitIntValue(0, AddressSize);
+ Asm->OutStreamer->EmitIntValue(0, AddressSize);
+ break;
+ }
+ Asm->OutStreamer->EmitIntValue(Low + LocPcOffset, AddressSize);
+ Asm->OutStreamer->EmitIntValue(High + LocPcOffset, AddressSize);
+ uint64_t Length = Data.getU16(&Offset);
+ Asm->OutStreamer->EmitIntValue(Length, 2);
+ // Just copy the bytes over.
+ Asm->OutStreamer->EmitBytes(
+ StringRef(InputSec.Data.substr(Offset, Length)));
+ Offset += Length;
+ LocSectionSize += Length + 2;
+ }
+ }
+}
+
+void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
+ StringRef PrologueBytes,
+ unsigned MinInstLength,
+ std::vector<DWARFDebugLine::Row> &Rows,
+ unsigned PointerSize) {
+ // Switch to the section where the table will be emitted into.
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
+ MCSymbol *LineStartSym = MC->createTempSymbol();
+ MCSymbol *LineEndSym = MC->createTempSymbol();
+
+ // The first 4 bytes is the total length of the information for this
+ // compilation unit (not including these 4 bytes for the length).
+ Asm->EmitLabelDifference(LineEndSym, LineStartSym, 4);
+ Asm->OutStreamer->EmitLabel(LineStartSym);
+ // Copy Prologue.
+ MS->EmitBytes(PrologueBytes);
+ LineSectionSize += PrologueBytes.size() + 4;
+
+ SmallString<128> EncodingBuffer;
+ raw_svector_ostream EncodingOS(EncodingBuffer);
+
+ if (Rows.empty()) {
+ // We only have the dummy entry, dsymutil emits an entry with a 0
+ // address in that case.
+ MCDwarfLineAddr::Encode(*MC, Params, std::numeric_limits<int64_t>::max(), 0,
+ EncodingOS);
+ MS->EmitBytes(EncodingOS.str());
+ LineSectionSize += EncodingBuffer.size();
+ MS->EmitLabel(LineEndSym);
+ return;
+ }
+
+ // Line table state machine fields
+ unsigned FileNum = 1;
+ unsigned LastLine = 1;
+ unsigned Column = 0;
+ unsigned IsStatement = 1;
+ unsigned Isa = 0;
+ uint64_t Address = -1ULL;
+
+ unsigned RowsSinceLastSequence = 0;
+
+ for (unsigned Idx = 0; Idx < Rows.size(); ++Idx) {
+ auto &Row = Rows[Idx];
+
+ int64_t AddressDelta;
+ if (Address == -1ULL) {
+ MS->EmitIntValue(dwarf::DW_LNS_extended_op, 1);
+ MS->EmitULEB128IntValue(PointerSize + 1);
+ MS->EmitIntValue(dwarf::DW_LNE_set_address, 1);
+ MS->EmitIntValue(Row.Address, PointerSize);
+ LineSectionSize += 2 + PointerSize + getULEB128Size(PointerSize + 1);
+ AddressDelta = 0;
+ } else {
+ AddressDelta = (Row.Address - Address) / MinInstLength;
+ }
+
+ // FIXME: code copied and transformed from MCDwarf.cpp::EmitDwarfLineTable.
+ // We should find a way to share this code, but the current compatibility
+ // requirement with classic dsymutil makes it hard. Revisit that once this
+ // requirement is dropped.
+
+ if (FileNum != Row.File) {
+ FileNum = Row.File;
+ MS->EmitIntValue(dwarf::DW_LNS_set_file, 1);
+ MS->EmitULEB128IntValue(FileNum);
+ LineSectionSize += 1 + getULEB128Size(FileNum);
+ }
+ if (Column != Row.Column) {
+ Column = Row.Column;
+ MS->EmitIntValue(dwarf::DW_LNS_set_column, 1);
+ MS->EmitULEB128IntValue(Column);
+ LineSectionSize += 1 + getULEB128Size(Column);
+ }
+
+ // FIXME: We should handle the discriminator here, but dsymutil doesn't
+ // consider it, thus ignore it for now.
+
+ if (Isa != Row.Isa) {
+ Isa = Row.Isa;
+ MS->EmitIntValue(dwarf::DW_LNS_set_isa, 1);
+ MS->EmitULEB128IntValue(Isa);
+ LineSectionSize += 1 + getULEB128Size(Isa);
+ }
+ if (IsStatement != Row.IsStmt) {
+ IsStatement = Row.IsStmt;
+ MS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1);
+ LineSectionSize += 1;
+ }
+ if (Row.BasicBlock) {
+ MS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1);
+ LineSectionSize += 1;
+ }
+
+ if (Row.PrologueEnd) {
+ MS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1);
+ LineSectionSize += 1;
+ }
+
+ if (Row.EpilogueBegin) {
+ MS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1);
+ LineSectionSize += 1;
+ }
+
+ int64_t LineDelta = int64_t(Row.Line) - LastLine;
+ if (!Row.EndSequence) {
+ MCDwarfLineAddr::Encode(*MC, Params, LineDelta, AddressDelta, EncodingOS);
+ MS->EmitBytes(EncodingOS.str());
+ LineSectionSize += EncodingBuffer.size();
+ EncodingBuffer.resize(0);
+ Address = Row.Address;
+ LastLine = Row.Line;
+ RowsSinceLastSequence++;
+ } else {
+ if (LineDelta) {
+ MS->EmitIntValue(dwarf::DW_LNS_advance_line, 1);
+ MS->EmitSLEB128IntValue(LineDelta);
+ LineSectionSize += 1 + getSLEB128Size(LineDelta);
+ }
+ if (AddressDelta) {
+ MS->EmitIntValue(dwarf::DW_LNS_advance_pc, 1);
+ MS->EmitULEB128IntValue(AddressDelta);
+ LineSectionSize += 1 + getULEB128Size(AddressDelta);
+ }
+ MCDwarfLineAddr::Encode(*MC, Params, std::numeric_limits<int64_t>::max(),
+ 0, EncodingOS);
+ MS->EmitBytes(EncodingOS.str());
+ LineSectionSize += EncodingBuffer.size();
+ EncodingBuffer.resize(0);
+ Address = -1ULL;
+ LastLine = FileNum = IsStatement = 1;
+ RowsSinceLastSequence = Column = Isa = 0;
+ }
+ }
+
+ if (RowsSinceLastSequence) {
+ MCDwarfLineAddr::Encode(*MC, Params, std::numeric_limits<int64_t>::max(), 0,
+ EncodingOS);
+ MS->EmitBytes(EncodingOS.str());
+ LineSectionSize += EncodingBuffer.size();
+ EncodingBuffer.resize(0);
+ }
+
+ MS->EmitLabel(LineEndSym);
+}
+
+static void emitSectionContents(const object::ObjectFile &Obj,
+ StringRef SecName, MCStreamer *MS) {
+ StringRef Contents;
+ if (auto Sec = getSectionByName(Obj, SecName))
+ if (!Sec->getContents(Contents))
+ MS->EmitBytes(Contents);
+}
+
+void DwarfStreamer::copyInvariantDebugSection(const object::ObjectFile &Obj,
+ LinkOptions &Options) {
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
+ emitSectionContents(Obj, "debug_line", MS);
+
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection());
+ emitSectionContents(Obj, "debug_loc", MS);
+
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
+ emitSectionContents(Obj, "debug_ranges", MS);
+
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
+ emitSectionContents(Obj, "debug_frame", MS);
+
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection());
+ emitSectionContents(Obj, "debug_aranges", MS);
+}
+
+/// Emit the pubnames or pubtypes section contribution for \p
+/// Unit into \p Sec. The data is provided in \p Names.
+void DwarfStreamer::emitPubSectionForUnit(
+ MCSection *Sec, StringRef SecName, const CompileUnit &Unit,
+ const std::vector<CompileUnit::AccelInfo> &Names) {
+ if (Names.empty())
+ return;
+
+ // Start the dwarf pubnames section.
+ Asm->OutStreamer->SwitchSection(Sec);
+ MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + SecName + "_begin");
+ MCSymbol *EndLabel = Asm->createTempSymbol("pub" + SecName + "_end");
+
+ bool HeaderEmitted = false;
+ // Emit the pubnames for this compilation unit.
+ for (const auto &Name : Names) {
+ if (Name.SkipPubSection)
+ continue;
+
+ if (!HeaderEmitted) {
+ // Emit the header.
+ Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Length
+ Asm->OutStreamer->EmitLabel(BeginLabel);
+ Asm->emitInt16(dwarf::DW_PUBNAMES_VERSION); // Version
+ Asm->emitInt32(Unit.getStartOffset()); // Unit offset
+ Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset()); // Size
+ HeaderEmitted = true;
+ }
+ Asm->emitInt32(Name.Die->getOffset());
+
+ // Emit the string itself.
+ Asm->OutStreamer->EmitBytes(Name.Name.getString());
+ // Emit a null terminator.
+ Asm->emitInt8(0);
+ }
+
+ if (!HeaderEmitted)
+ return;
+ Asm->emitInt32(0); // End marker.
+ Asm->OutStreamer->EmitLabel(EndLabel);
+}
+
+/// Emit .debug_pubnames for \p Unit.
+void DwarfStreamer::emitPubNamesForUnit(const CompileUnit &Unit) {
+ emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubNamesSection(),
+ "names", Unit, Unit.getPubnames());
+}
+
+/// Emit .debug_pubtypes for \p Unit.
+void DwarfStreamer::emitPubTypesForUnit(const CompileUnit &Unit) {
+ emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubTypesSection(),
+ "types", Unit, Unit.getPubtypes());
+}
+
+/// Emit a CIE into the debug_frame section.
+void DwarfStreamer::emitCIE(StringRef CIEBytes) {
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
+
+ MS->EmitBytes(CIEBytes);
+ FrameSectionSize += CIEBytes.size();
+}
+
+/// Emit a FDE into the debug_frame section. \p FDEBytes
+/// contains the FDE data without the length, CIE offset and address
+/// which will be replaced with the parameter values.
+void DwarfStreamer::emitFDE(uint32_t CIEOffset, uint32_t AddrSize,
+ uint32_t Address, StringRef FDEBytes) {
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
+
+ MS->EmitIntValue(FDEBytes.size() + 4 + AddrSize, 4);
+ MS->EmitIntValue(CIEOffset, 4);
+ MS->EmitIntValue(Address, AddrSize);
+ MS->EmitBytes(FDEBytes);
+ FrameSectionSize += FDEBytes.size() + 8 + AddrSize;
+}
+
+} // namespace dsymutil
+} // namespace llvm
--- /dev/null
+//===- tools/dsymutil/DwarfStreamer.h - Dwarf Streamer ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CompileUnit.h"
+#include "DebugMap.h"
+#include "NonRelocatableStringpool.h"
+#include "llvm/CodeGen/AccelTable.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+
+#ifndef LLVM_TOOLS_DSYMUTIL_DWARFSTREAMER_H
+#define LLVM_TOOLS_DSYMUTIL_DWARFSTREAMER_H
+
+namespace llvm {
+namespace dsymutil {
+
+struct LinkOptions;
+
+/// The Dwarf streaming logic.
+///
+/// All interactions with the MC layer that is used to build the debug
+/// information binary representation are handled in this class.
+class DwarfStreamer {
+public:
+ DwarfStreamer(raw_fd_ostream &OutFile) : OutFile(OutFile) {}
+ bool init(Triple TheTriple);
+
+ /// Dump the file to the disk.
+ bool finish(const DebugMap &);
+
+ AsmPrinter &getAsmPrinter() const { return *Asm; }
+
+ /// Set the current output section to debug_info and change
+ /// the MC Dwarf version to \p DwarfVersion.
+ void switchToDebugInfoSection(unsigned DwarfVersion);
+
+ /// Emit the compilation unit header for \p Unit in the
+ /// debug_info section.
+ ///
+ /// As a side effect, this also switches the current Dwarf version
+ /// of the MC layer to the one of U.getOrigUnit().
+ void emitCompileUnitHeader(CompileUnit &Unit);
+
+ /// Recursively emit the DIE tree rooted at \p Die.
+ void emitDIE(DIE &Die);
+
+ /// Emit the abbreviation table \p Abbrevs to the debug_abbrev section.
+ void emitAbbrevs(const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs,
+ unsigned DwarfVersion);
+
+ /// Emit the string table described by \p Pool.
+ void emitStrings(const NonRelocatableStringpool &Pool);
+
+ /// Emit the swift_ast section stored in \p Buffer.
+ void emitSwiftAST(StringRef Buffer);
+
+ /// Emit debug_ranges for \p FuncRange by translating the
+ /// original \p Entries.
+ void emitRangesEntries(
+ int64_t UnitPcOffset, uint64_t OrigLowPc,
+ const FunctionIntervals::const_iterator &FuncRange,
+ const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries,
+ unsigned AddressSize);
+
+ /// Emit debug_aranges entries for \p Unit and if \p DoRangesSection is true,
+ /// also emit the debug_ranges entries for the DW_TAG_compile_unit's
+ /// DW_AT_ranges attribute.
+ void emitUnitRangesEntries(CompileUnit &Unit, bool DoRangesSection);
+
+ uint32_t getRangesSectionSize() const { return RangesSectionSize; }
+
+ /// Emit the debug_loc contribution for \p Unit by copying the entries from
+ /// \p Dwarf and offsetting them. Update the location attributes to point to
+ /// the new entries.
+ void emitLocationsForUnit(const CompileUnit &Unit, DWARFContext &Dwarf);
+
+ /// Emit the line table described in \p Rows into the debug_line section.
+ void emitLineTableForUnit(MCDwarfLineTableParams Params,
+ StringRef PrologueBytes, unsigned MinInstLength,
+ std::vector<DWARFDebugLine::Row> &Rows,
+ unsigned AdddressSize);
+
+ /// Copy over the debug sections that are not modified when updating.
+ void copyInvariantDebugSection(const object::ObjectFile &Obj, LinkOptions &);
+
+ uint32_t getLineSectionSize() const { return LineSectionSize; }
+
+ /// Emit the .debug_pubnames contribution for \p Unit.
+ void emitPubNamesForUnit(const CompileUnit &Unit);
+
+ /// Emit the .debug_pubtypes contribution for \p Unit.
+ void emitPubTypesForUnit(const CompileUnit &Unit);
+
+ /// Emit a CIE.
+ void emitCIE(StringRef CIEBytes);
+
+ /// Emit an FDE with data \p Bytes.
+ void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint32_t Address,
+ StringRef Bytes);
+
+ /// Emit Apple namespaces accelerator table.
+ void emitAppleNamespaces(AccelTable<AppleAccelTableStaticOffsetData> &Table);
+
+ /// Emit Apple names accelerator table.
+ void emitAppleNames(AccelTable<AppleAccelTableStaticOffsetData> &Table);
+
+ /// Emit Apple Objective-C accelerator table.
+ void emitAppleObjc(AccelTable<AppleAccelTableStaticOffsetData> &Table);
+
+ /// Emit Apple type accelerator table.
+ void emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> &Table);
+
+ uint32_t getFrameSectionSize() const { return FrameSectionSize; }
+
+private:
+ /// \defgroup MCObjects MC layer objects constructed by the streamer
+ /// @{
+ std::unique_ptr<MCRegisterInfo> MRI;
+ std::unique_ptr<MCAsmInfo> MAI;
+ std::unique_ptr<MCObjectFileInfo> MOFI;
+ std::unique_ptr<MCContext> MC;
+ MCAsmBackend *MAB; // Owned by MCStreamer
+ std::unique_ptr<MCInstrInfo> MII;
+ std::unique_ptr<MCSubtargetInfo> MSTI;
+ MCCodeEmitter *MCE; // Owned by MCStreamer
+ MCStreamer *MS; // Owned by AsmPrinter
+ std::unique_ptr<TargetMachine> TM;
+ std::unique_ptr<AsmPrinter> Asm;
+ /// @}
+
+ /// The file we stream the linked Dwarf to.
+ raw_fd_ostream &OutFile;
+
+ uint32_t RangesSectionSize;
+ uint32_t LocSectionSize;
+ uint32_t LineSectionSize;
+ uint32_t FrameSectionSize;
+
+ /// Emit the pubnames or pubtypes section contribution for \p
+ /// Unit into \p Sec. The data is provided in \p Names.
+ void emitPubSectionForUnit(MCSection *Sec, StringRef Name,
+ const CompileUnit &Unit,
+ const std::vector<CompileUnit::AccelInfo> &Names);
+};
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_DWARFSTREAMER_H
--- /dev/null
+//===- tools/dsymutil/LinkUtils.h - Dwarf linker utilities ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
+#define LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/WithColor.h"
+#include <string>
+
+namespace llvm {
+namespace dsymutil {
+
+struct LinkOptions {
+ /// Verbosity
+ bool Verbose = false;
+
+ /// Skip emitting output
+ bool NoOutput = false;
+
+ /// Do not unique types according to ODR
+ bool NoODR = false;
+
+ /// Update
+ bool Update = false;
+
+ /// Minimize
+ bool Minimize = false;
+
+ /// Do not check swiftmodule timestamp
+ bool NoTimestamp = false;
+
+ /// Number of threads.
+ unsigned Threads = 1;
+
+ /// -oso-prepend-path
+ std::string PrependPath;
+
+ LinkOptions() = default;
+};
+
+inline void warn(Twine Warning, Twine Context = {}) {
+ WithColor::warning() << Warning + "\n";
+ if (!Context.isTriviallyEmpty())
+ WithColor::note() << Twine("while processing ") + Context + "\n";
+}
+
+inline bool error(Twine Error, Twine Context = {}) {
+ WithColor::error() << Error + "\n";
+ if (!Context.isTriviallyEmpty())
+ WithColor::note() << Twine("while processing ") + Context + "\n";
+ return false;
+}
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===//
//
-// The LLVM Linker
+// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
-//===-- MachOUtils.h - Mach-o specific helpers for dsymutil --------------===//
+//===-- MachOUtils.cpp - Mach-o specific helpers for dsymutil ------------===//
//
// The LLVM Compiler Infrastructure
//
#include "MachOUtils.h"
#include "BinaryHolder.h"
#include "DebugMap.h"
+#include "LinkUtils.h"
#include "NonRelocatableStringpool.h"
-#include "dsymutil.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCMachObjectWriter.h"
#include "llvm/MC/MCObjectStreamer.h"
DwarfStringPoolEntryRef EmptyString;
};
+/// Helper for making strong types.
+template <typename T, typename S> class StrongType : public T {
+public:
+ template <typename... Args>
+ explicit StrongType(Args... A) : T(std::forward<Args>(A)...) {}
+};
+
+/// It's very easy to introduce bugs by passing the wrong string pool in the
+/// dwarf linker. By using strong types the interface enforces that the right
+/// kind of pool is used.
+struct UniqueTag {};
+struct OffsetsTag {};
+using UniquingStringPool = StrongType<NonRelocatableStringpool, UniqueTag>;
+using OffsetsStringPool = StrongType<NonRelocatableStringpool, OffsetsTag>;
+
} // end namespace dsymutil
} // end namespace llvm
#include "dsymutil.h"
#include "CFBundle.h"
#include "DebugMap.h"
+#include "LinkUtils.h"
#include "MachOUtils.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
//===- tools/dsymutil/dsymutil.h - dsymutil high-level functionality ------===//
//
-// The LLVM Linker
+// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#define LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H
#include "DebugMap.h"
+#include "LinkUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
namespace llvm {
namespace dsymutil {
-struct LinkOptions {
- /// Verbosity
- bool Verbose = false;
-
- /// Skip emitting output
- bool NoOutput = false;
-
- /// Do not unique types according to ODR
- bool NoODR = false;
-
- /// Update
- bool Update = false;
-
- /// Minimize
- bool Minimize = false;
-
- /// Do not check swiftmodule timestamp
- bool NoTimestamp = false;
-
- /// Number of threads.
- unsigned Threads = 1;
-
- /// -oso-prepend-path
- std::string PrependPath;
-
- LinkOptions() = default;
-};
-
/// Extract the DebugMaps from the given file.
/// The file has to be a MachO object file. Multiple debug maps can be
/// returned when the file is universal (aka fat) binary.
bool linkDwarf(raw_fd_ostream &OutFile, const DebugMap &DM,
const LinkOptions &Options);
-void warn(Twine Warning, Twine Context = {});
-bool error(Twine Error, Twine Context = {});
-
} // end namespace dsymutil
} // end namespace llvm