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