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