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