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