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