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