| //===- 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; |
| } |
| |
| MCSymbol *getLabelBegin() { return LabelBegin; } |
| void setLabelBegin(MCSymbol *S) { LabelBegin = S; } |
| |
| private: |
| DWARFUnit &OrigUnit; |
| unsigned ID; |
| std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index. |
| Optional<BasicDIEUnit> NewUnit; |
| MCSymbol *LabelBegin = nullptr; |
| |
| uint64_t StartOffset; |
| uint64_t NextUnitOffset; |
| |
| uint64_t LowPc = std::numeric_limits<uint64_t>::max(); |
| uint64_t HighPc = 0; |
| |
| /// A list of attributes to fixup with the absolute offset of |
| /// a DIE in the debug_info section. |
| /// |
| /// The offsets for the attributes in this array couldn't be set while |
| /// cloning because for cross-cu forward references the target DIE's offset |
| /// isn't known you emit the reference attribute. |
| std::vector< |
| std::tuple<DIE *, const CompileUnit *, DeclContext *, PatchLocation>> |
| ForwardDIEReferences; |
| |
| FunctionIntervals::Allocator RangeAlloc; |
| |
| /// The ranges in that interval map are the PC ranges for |
| /// functions in this unit, associated with the PC offset to apply |
| /// to the addresses to get the linked address. |
| FunctionIntervals Ranges; |
| |
| /// The DW_AT_low_pc of each DW_TAG_label. |
| SmallDenseMap<uint64_t, uint64_t, 1> Labels; |
| |
| /// DW_AT_ranges attributes to patch after we have gathered |
| /// all the unit's function addresses. |
| /// @{ |
| std::vector<PatchLocation> RangeAttributes; |
| Optional<PatchLocation> UnitRangeAttribute; |
| /// @} |
| |
| /// Location attributes that need to be transferred from the |
| /// original debug_loc section to the liked one. They are stored |
| /// along with the PC offset that is to be applied to their |
| /// function's address. |
| std::vector<std::pair<PatchLocation, int64_t>> LocationAttributes; |
| |
| /// Accelerator entries for the unit, both for the pub* |
| /// sections and the apple* ones. |
| /// @{ |
| std::vector<AccelInfo> Pubnames; |
| std::vector<AccelInfo> Pubtypes; |
| std::vector<AccelInfo> Namespaces; |
| std::vector<AccelInfo> ObjC; |
| /// @} |
| |
| /// Cached resolved paths from the line table. |
| /// Note, the StringRefs here point in to the intern (uniquing) string pool. |
| /// This means that a StringRef returned here doesn't need to then be uniqued |
| /// for the purposes of getting a unique address for each string. |
| std::vector<StringRef> ResolvedPaths; |
| |
| /// Is this unit subject to the ODR rule? |
| bool HasODR; |
| |
| /// Did a DIE actually contain a valid reloc? |
| bool HasInterestingContent; |
| |
| /// 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 |