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