1 //===- DIContext.h ----------------------------------------------*- 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 // This file defines DIContext, an abstract data structure that holds 11 // debug information data. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_DEBUGINFO_DICONTEXT_H 16 #define LLVM_DEBUGINFO_DICONTEXT_H 17 18 #include "llvm/ADT/SmallVector.h" 19 #include "llvm/Object/ObjectFile.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <cassert> 22 #include <cstdint> 23 #include <memory> 24 #include <string> 25 #include <tuple> 26 #include <utility> 27 28 namespace llvm { 29 30 /// A format-neutral container for source line information. 31 struct DILineInfo { 32 std::string FileName; 33 std::string FunctionName; 34 Optional<StringRef> Source; 35 uint32_t Line = 0; 36 uint32_t Column = 0; 37 uint32_t StartLine = 0; 38 39 // DWARF-specific. 40 uint32_t Discriminator = 0; 41 DILineInfoDILineInfo42 DILineInfo() : FileName("<invalid>"), FunctionName("<invalid>") {} 43 44 bool operator==(const DILineInfo &RHS) const { 45 return Line == RHS.Line && Column == RHS.Column && 46 FileName == RHS.FileName && FunctionName == RHS.FunctionName && 47 StartLine == RHS.StartLine && Discriminator == RHS.Discriminator; 48 } 49 50 bool operator!=(const DILineInfo &RHS) const { 51 return !(*this == RHS); 52 } 53 54 bool operator<(const DILineInfo &RHS) const { 55 return std::tie(FileName, FunctionName, Line, Column, StartLine, 56 Discriminator) < 57 std::tie(RHS.FileName, RHS.FunctionName, RHS.Line, RHS.Column, 58 RHS.StartLine, RHS.Discriminator); 59 } 60 61 explicit operator bool() const { return *this != DILineInfo(); } 62 dumpDILineInfo63 void dump(raw_ostream &OS) { 64 OS << "Line info: "; 65 if (FileName != "<invalid>") 66 OS << "file '" << FileName << "', "; 67 if (FunctionName != "<invalid>") 68 OS << "function '" << FunctionName << "', "; 69 OS << "line " << Line << ", "; 70 OS << "column " << Column << ", "; 71 OS << "start line " << StartLine << '\n'; 72 } 73 }; 74 75 using DILineInfoTable = SmallVector<std::pair<uint64_t, DILineInfo>, 16>; 76 77 /// A format-neutral container for inlined code description. 78 class DIInliningInfo { 79 SmallVector<DILineInfo, 4> Frames; 80 81 public: 82 DIInliningInfo() = default; 83 getFrame(unsigned Index)84 const DILineInfo & getFrame(unsigned Index) const { 85 assert(Index < Frames.size()); 86 return Frames[Index]; 87 } 88 getMutableFrame(unsigned Index)89 DILineInfo *getMutableFrame(unsigned Index) { 90 assert(Index < Frames.size()); 91 return &Frames[Index]; 92 } 93 getNumberOfFrames()94 uint32_t getNumberOfFrames() const { 95 return Frames.size(); 96 } 97 addFrame(const DILineInfo & Frame)98 void addFrame(const DILineInfo &Frame) { 99 Frames.push_back(Frame); 100 } 101 resize(unsigned i)102 void resize(unsigned i) { 103 Frames.resize(i); 104 } 105 106 }; 107 108 /// Container for description of a global variable. 109 struct DIGlobal { 110 std::string Name; 111 uint64_t Start = 0; 112 uint64_t Size = 0; 113 DIGlobalDIGlobal114 DIGlobal() : Name("<invalid>") {} 115 }; 116 117 /// A DINameKind is passed to name search methods to specify a 118 /// preference regarding the type of name resolution the caller wants. 119 enum class DINameKind { None, ShortName, LinkageName }; 120 121 /// Controls which fields of DILineInfo container should be filled 122 /// with data. 123 struct DILineInfoSpecifier { 124 enum class FileLineInfoKind { None, Default, AbsoluteFilePath }; 125 using FunctionNameKind = DINameKind; 126 127 FileLineInfoKind FLIKind; 128 FunctionNameKind FNKind; 129 130 DILineInfoSpecifier(FileLineInfoKind FLIKind = FileLineInfoKind::Default, 131 FunctionNameKind FNKind = FunctionNameKind::None) FLIKindDILineInfoSpecifier132 : FLIKind(FLIKind), FNKind(FNKind) {} 133 }; 134 135 /// This is just a helper to programmatically construct DIDumpType. 136 enum DIDumpTypeCounter { 137 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \ 138 DIDT_ID_##ENUM_NAME, 139 #include "llvm/BinaryFormat/Dwarf.def" 140 #undef HANDLE_DWARF_SECTION 141 DIDT_ID_UUID, 142 DIDT_ID_Count 143 }; 144 static_assert(DIDT_ID_Count <= 32, "section types overflow storage"); 145 146 /// Selects which debug sections get dumped. 147 enum DIDumpType : unsigned { 148 DIDT_Null, 149 DIDT_All = ~0U, 150 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \ 151 DIDT_##ENUM_NAME = 1U << DIDT_ID_##ENUM_NAME, 152 #include "llvm/BinaryFormat/Dwarf.def" 153 #undef HANDLE_DWARF_SECTION 154 DIDT_UUID = 1 << DIDT_ID_UUID, 155 }; 156 157 /// Container for dump options that control which debug information will be 158 /// dumped. 159 struct DIDumpOptions { 160 unsigned DumpType = DIDT_All; 161 unsigned RecurseDepth = -1U; 162 uint16_t Version = 0; // DWARF version to assume when extracting. 163 uint8_t AddrSize = 4; // Address byte size to assume when extracting. 164 bool ShowAddresses = true; 165 bool ShowChildren = false; 166 bool ShowParents = false; 167 bool ShowForm = false; 168 bool SummarizeTypes = false; 169 bool Verbose = false; 170 bool DisplayRawContents = false; 171 172 /// Return default option set for printing a single DIE without children. getForSingleDIEDIDumpOptions173 static DIDumpOptions getForSingleDIE() { 174 DIDumpOptions Opts; 175 Opts.RecurseDepth = 0; 176 return Opts; 177 } 178 179 /// Return the options with RecurseDepth set to 0 unless explicitly required. noImplicitRecursionDIDumpOptions180 DIDumpOptions noImplicitRecursion() const { 181 DIDumpOptions Opts = *this; 182 if (RecurseDepth == -1U && !ShowChildren) 183 Opts.RecurseDepth = 0; 184 return Opts; 185 } 186 }; 187 188 class DIContext { 189 public: 190 enum DIContextKind { 191 CK_DWARF, 192 CK_PDB 193 }; 194 DIContext(DIContextKind K)195 DIContext(DIContextKind K) : Kind(K) {} 196 virtual ~DIContext() = default; 197 getKind()198 DIContextKind getKind() const { return Kind; } 199 200 virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0; 201 202 virtual bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) { 203 // No verifier? Just say things went well. 204 return true; 205 } 206 207 virtual DILineInfo getLineInfoForAddress(uint64_t Address, 208 DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; 209 virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address, 210 uint64_t Size, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; 211 virtual DIInliningInfo getInliningInfoForAddress(uint64_t Address, 212 DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; 213 214 private: 215 const DIContextKind Kind; 216 }; 217 218 /// An inferface for inquiring the load address of a loaded object file 219 /// to be used by the DIContext implementations when applying relocations 220 /// on the fly. 221 class LoadedObjectInfo { 222 protected: 223 LoadedObjectInfo() = default; 224 LoadedObjectInfo(const LoadedObjectInfo &) = default; 225 226 public: 227 virtual ~LoadedObjectInfo() = default; 228 229 /// Obtain the Load Address of a section by SectionRef. 230 /// 231 /// Calculate the address of the given section. 232 /// The section need not be present in the local address space. The addresses 233 /// need to be consistent with the addresses used to query the DIContext and 234 /// the output of this function should be deterministic, i.e. repeated calls 235 /// with the same Sec should give the same address. getSectionLoadAddress(const object::SectionRef & Sec)236 virtual uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const { 237 return 0; 238 } 239 240 /// If conveniently available, return the content of the given Section. 241 /// 242 /// When the section is available in the local address space, in relocated 243 /// (loaded) form, e.g. because it was relocated by a JIT for execution, this 244 /// function should provide the contents of said section in `Data`. If the 245 /// loaded section is not available, or the cost of retrieving it would be 246 /// prohibitive, this function should return false. In that case, relocations 247 /// will be read from the local (unrelocated) object file and applied on the 248 /// fly. Note that this method is used purely for optimzation purposes in the 249 /// common case of JITting in the local address space, so returning false 250 /// should always be correct. getLoadedSectionContents(const object::SectionRef & Sec,StringRef & Data)251 virtual bool getLoadedSectionContents(const object::SectionRef &Sec, 252 StringRef &Data) const { 253 return false; 254 } 255 256 // FIXME: This is untested and unused anywhere in the LLVM project, it's 257 // used/needed by Julia (an external project). It should have some coverage 258 // (at least tests, but ideally example functionality). 259 /// Obtain a copy of this LoadedObjectInfo. 260 virtual std::unique_ptr<LoadedObjectInfo> clone() const = 0; 261 }; 262 263 template <typename Derived, typename Base = LoadedObjectInfo> 264 struct LoadedObjectInfoHelper : Base { 265 protected: 266 LoadedObjectInfoHelper(const LoadedObjectInfoHelper &) = default; 267 LoadedObjectInfoHelper() = default; 268 269 public: 270 template <typename... Ts> LoadedObjectInfoHelperLoadedObjectInfoHelper271 LoadedObjectInfoHelper(Ts &&... Args) : Base(std::forward<Ts>(Args)...) {} 272 cloneLoadedObjectInfoHelper273 std::unique_ptr<llvm::LoadedObjectInfo> clone() const override { 274 return llvm::make_unique<Derived>(static_cast<const Derived &>(*this)); 275 } 276 }; 277 278 } // end namespace llvm 279 280 #endif // LLVM_DEBUGINFO_DICONTEXT_H 281