Home | History | Annotate | Download | only in dsymutil
      1 //===- tools/dsymutil/CompileUnit.h - Dwarf debug info linker ---*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/ADT/IntervalMap.h"
     11 #include "llvm/CodeGen/DIE.h"
     12 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
     13 
     14 #ifndef LLVM_TOOLS_DSYMUTIL_COMPILEUNIT_H
     15 #define LLVM_TOOLS_DSYMUTIL_COMPILEUNIT_H
     16 
     17 namespace llvm {
     18 namespace dsymutil {
     19 
     20 class DeclContext;
     21 
     22 template <typename KeyT, typename ValT>
     23 using HalfOpenIntervalMap =
     24     IntervalMap<KeyT, ValT, IntervalMapImpl::NodeSizer<KeyT, ValT>::LeafSize,
     25                 IntervalMapHalfOpenInfo<KeyT>>;
     26 
     27 using FunctionIntervals = HalfOpenIntervalMap<uint64_t, int64_t>;
     28 
     29 // FIXME: Delete this structure.
     30 struct PatchLocation {
     31   DIE::value_iterator I;
     32 
     33   PatchLocation() = default;
     34   PatchLocation(DIE::value_iterator I) : I(I) {}
     35 
     36   void set(uint64_t New) const {
     37     assert(I);
     38     const auto &Old = *I;
     39     assert(Old.getType() == DIEValue::isInteger);
     40     *I = DIEValue(Old.getAttribute(), Old.getForm(), DIEInteger(New));
     41   }
     42 
     43   uint64_t get() const {
     44     assert(I);
     45     return I->getDIEInteger().getValue();
     46   }
     47 };
     48 
     49 /// Stores all information relating to a compile unit, be it in its original
     50 /// instance in the object file to its brand new cloned and linked DIE tree.
     51 class CompileUnit {
     52 public:
     53   /// Information gathered about a DIE in the object file.
     54   struct DIEInfo {
     55     /// Address offset to apply to the described entity.
     56     int64_t AddrAdjust;
     57 
     58     /// ODR Declaration context.
     59     DeclContext *Ctxt;
     60 
     61     /// Cloned version of that DIE.
     62     DIE *Clone;
     63 
     64     /// The index of this DIE's parent.
     65     uint32_t ParentIdx;
     66 
     67     /// Is the DIE part of the linked output?
     68     bool Keep : 1;
     69 
     70     /// Was this DIE's entity found in the map?
     71     bool InDebugMap : 1;
     72 
     73     /// Is this a pure forward declaration we can strip?
     74     bool Prune : 1;
     75 
     76     /// Does DIE transitively refer an incomplete decl?
     77     bool Incomplete : 1;
     78   };
     79 
     80   CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR,
     81               StringRef ClangModuleName)
     82       : OrigUnit(OrigUnit), ID(ID), Ranges(RangeAlloc),
     83         ClangModuleName(ClangModuleName) {
     84     Info.resize(OrigUnit.getNumDIEs());
     85 
     86     auto CUDie = OrigUnit.getUnitDIE(false);
     87     if (!CUDie) {
     88       HasODR = false;
     89       return;
     90     }
     91     if (auto Lang = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language)))
     92       HasODR = CanUseODR && (*Lang == dwarf::DW_LANG_C_plus_plus ||
     93                              *Lang == dwarf::DW_LANG_C_plus_plus_03 ||
     94                              *Lang == dwarf::DW_LANG_C_plus_plus_11 ||
     95                              *Lang == dwarf::DW_LANG_C_plus_plus_14 ||
     96                              *Lang == dwarf::DW_LANG_ObjC_plus_plus);
     97     else
     98       HasODR = false;
     99   }
    100 
    101   DWARFUnit &getOrigUnit() const { return OrigUnit; }
    102 
    103   unsigned getUniqueID() const { return ID; }
    104 
    105   void createOutputDIE() {
    106     NewUnit.emplace(OrigUnit.getVersion(), OrigUnit.getAddressByteSize(),
    107                     OrigUnit.getUnitDIE().getTag());
    108   }
    109 
    110   DIE *getOutputUnitDIE() const {
    111     if (NewUnit)
    112       return &const_cast<BasicDIEUnit &>(*NewUnit).getUnitDie();
    113     return nullptr;
    114   }
    115 
    116   bool hasODR() const { return HasODR; }
    117   bool isClangModule() const { return !ClangModuleName.empty(); }
    118   const std::string &getClangModuleName() const { return ClangModuleName; }
    119 
    120   DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
    121   const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
    122 
    123   uint64_t getStartOffset() const { return StartOffset; }
    124   uint64_t getNextUnitOffset() const { return NextUnitOffset; }
    125   void setStartOffset(uint64_t DebugInfoSize) { StartOffset = DebugInfoSize; }
    126 
    127   uint64_t getLowPc() const { return LowPc; }
    128   uint64_t getHighPc() const { return HighPc; }
    129   bool hasLabelAt(uint64_t Addr) const { return Labels.count(Addr); }
    130 
    131   Optional<PatchLocation> getUnitRangesAttribute() const {
    132     return UnitRangeAttribute;
    133   }
    134 
    135   const FunctionIntervals &getFunctionRanges() const { return Ranges; }
    136 
    137   const std::vector<PatchLocation> &getRangesAttributes() const {
    138     return RangeAttributes;
    139   }
    140 
    141   const std::vector<std::pair<PatchLocation, int64_t>> &
    142   getLocationAttributes() const {
    143     return LocationAttributes;
    144   }
    145 
    146   void setHasInterestingContent() { HasInterestingContent = true; }
    147   bool hasInterestingContent() { return HasInterestingContent; }
    148 
    149   /// Mark every DIE in this unit as kept. This function also
    150   /// marks variables as InDebugMap so that they appear in the
    151   /// reconstructed accelerator tables.
    152   void markEverythingAsKept();
    153 
    154   /// Compute the end offset for this unit. Must be called after the CU's DIEs
    155   /// have been cloned.  \returns the next unit offset (which is also the
    156   /// current debug_info section size).
    157   uint64_t computeNextUnitOffset();
    158 
    159   /// Keep track of a forward reference to DIE \p Die in \p RefUnit by \p
    160   /// Attr. The attribute should be fixed up later to point to the absolute
    161   /// offset of \p Die in the debug_info section or to the canonical offset of
    162   /// \p Ctxt if it is non-null.
    163   void noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
    164                             DeclContext *Ctxt, PatchLocation Attr);
    165 
    166   /// Apply all fixups recorded by noteForwardReference().
    167   void fixupForwardReferences();
    168 
    169   /// Add the low_pc of a label that is relocated by applying
    170   /// offset \p PCOffset.
    171   void addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset);
    172 
    173   /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying
    174   /// offset \p PCOffset.
    175   void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset);
    176 
    177   /// Keep track of a DW_AT_range attribute that we will need to patch up later.
    178   void noteRangeAttribute(const DIE &Die, PatchLocation Attr);
    179 
    180   /// Keep track of a location attribute pointing to a location list in the
    181   /// debug_loc section.
    182   void noteLocationAttribute(PatchLocation Attr, int64_t PcOffset);
    183 
    184   /// Add a name accelerator entry for \a Die with \a Name.
    185   void addNamespaceAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name);
    186 
    187   /// Add a name accelerator entry for \a Die with \a Name.
    188   void addNameAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name,
    189                           bool SkipPubnamesSection = false);
    190 
    191   /// Add various accelerator entries for \p Die with \p Name which is stored
    192   /// in the string table at \p Offset. \p Name must be an Objective-C
    193   /// selector.
    194   void addObjCAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name,
    195                           bool SkipPubnamesSection = false);
    196 
    197   /// Add a type accelerator entry for \p Die with \p Name which is stored in
    198   /// the string table at \p Offset.
    199   void addTypeAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name,
    200                           bool ObjcClassImplementation,
    201                           uint32_t QualifiedNameHash);
    202 
    203   struct AccelInfo {
    204     /// Name of the entry.
    205     DwarfStringPoolEntryRef Name;
    206 
    207     /// DIE this entry describes.
    208     const DIE *Die;
    209 
    210     /// Hash of the fully qualified name.
    211     uint32_t QualifiedNameHash;
    212 
    213     /// Emit this entry only in the apple_* sections.
    214     bool SkipPubSection;
    215 
    216     /// Is this an ObjC class implementation?
    217     bool ObjcClassImplementation;
    218 
    219     AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die,
    220               bool SkipPubSection = false)
    221         : Name(Name), Die(Die), SkipPubSection(SkipPubSection) {}
    222 
    223     AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die,
    224               uint32_t QualifiedNameHash, bool ObjCClassIsImplementation)
    225         : Name(Name), Die(Die), QualifiedNameHash(QualifiedNameHash),
    226           SkipPubSection(false),
    227           ObjcClassImplementation(ObjCClassIsImplementation) {}
    228   };
    229 
    230   const std::vector<AccelInfo> &getPubnames() const { return Pubnames; }
    231   const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; }
    232   const std::vector<AccelInfo> &getNamespaces() const { return Namespaces; }
    233   const std::vector<AccelInfo> &getObjC() const { return ObjC; }
    234 
    235   /// Get the full path for file \a FileNum in the line table
    236   StringRef getResolvedPath(unsigned FileNum) {
    237     if (FileNum >= ResolvedPaths.size())
    238       return StringRef();
    239     return ResolvedPaths[FileNum];
    240   }
    241 
    242   /// Set the fully resolved path for the line-table's file \a FileNum
    243   /// to \a Path.
    244   void setResolvedPath(unsigned FileNum, StringRef Path) {
    245     if (ResolvedPaths.size() <= FileNum)
    246       ResolvedPaths.resize(FileNum + 1);
    247     ResolvedPaths[FileNum] = Path;
    248   }
    249 
    250   MCSymbol *getLabelBegin() { return LabelBegin; }
    251   void setLabelBegin(MCSymbol *S) { LabelBegin = S; }
    252 
    253 private:
    254   DWARFUnit &OrigUnit;
    255   unsigned ID;
    256   std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
    257   Optional<BasicDIEUnit> NewUnit;
    258   MCSymbol *LabelBegin = nullptr;
    259 
    260   uint64_t StartOffset;
    261   uint64_t NextUnitOffset;
    262 
    263   uint64_t LowPc = std::numeric_limits<uint64_t>::max();
    264   uint64_t HighPc = 0;
    265 
    266   /// A list of attributes to fixup with the absolute offset of
    267   /// a DIE in the debug_info section.
    268   ///
    269   /// The offsets for the attributes in this array couldn't be set while
    270   /// cloning because for cross-cu forward references the target DIE's offset
    271   /// isn't known you emit the reference attribute.
    272   std::vector<
    273       std::tuple<DIE *, const CompileUnit *, DeclContext *, PatchLocation>>
    274       ForwardDIEReferences;
    275 
    276   FunctionIntervals::Allocator RangeAlloc;
    277 
    278   /// The ranges in that interval map are the PC ranges for
    279   /// functions in this unit, associated with the PC offset to apply
    280   /// to the addresses to get the linked address.
    281   FunctionIntervals Ranges;
    282 
    283   /// The DW_AT_low_pc of each DW_TAG_label.
    284   SmallDenseMap<uint64_t, uint64_t, 1> Labels;
    285 
    286   /// DW_AT_ranges attributes to patch after we have gathered
    287   /// all the unit's function addresses.
    288   /// @{
    289   std::vector<PatchLocation> RangeAttributes;
    290   Optional<PatchLocation> UnitRangeAttribute;
    291   /// @}
    292 
    293   /// Location attributes that need to be transferred from the
    294   /// original debug_loc section to the liked one. They are stored
    295   /// along with the PC offset that is to be applied to their
    296   /// function's address.
    297   std::vector<std::pair<PatchLocation, int64_t>> LocationAttributes;
    298 
    299   /// Accelerator entries for the unit, both for the pub*
    300   /// sections and the apple* ones.
    301   /// @{
    302   std::vector<AccelInfo> Pubnames;
    303   std::vector<AccelInfo> Pubtypes;
    304   std::vector<AccelInfo> Namespaces;
    305   std::vector<AccelInfo> ObjC;
    306   /// @}
    307 
    308   /// Cached resolved paths from the line table.
    309   /// Note, the StringRefs here point in to the intern (uniquing) string pool.
    310   /// This means that a StringRef returned here doesn't need to then be uniqued
    311   /// for the purposes of getting a unique address for each string.
    312   std::vector<StringRef> ResolvedPaths;
    313 
    314   /// Is this unit subject to the ODR rule?
    315   bool HasODR;
    316 
    317   /// Did a DIE actually contain a valid reloc?
    318   bool HasInterestingContent;
    319 
    320   /// If this is a Clang module, this holds the module's name.
    321   std::string ClangModuleName;
    322 };
    323 
    324 } // end namespace dsymutil
    325 } // end namespace llvm
    326 
    327 #endif // LLVM_TOOLS_DSYMUTIL_COMPILEUNIT_H
    328