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