Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:46

0001 //===- DIContext.h ----------------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file defines DIContext, an abstract data structure that holds
0010 // debug information data.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_DEBUGINFO_DICONTEXT_H
0015 #define LLVM_DEBUGINFO_DICONTEXT_H
0016 
0017 #include "llvm/ADT/SmallVector.h"
0018 #include "llvm/Object/ObjectFile.h"
0019 #include "llvm/Support/WithColor.h"
0020 #include "llvm/Support/raw_ostream.h"
0021 #include <cassert>
0022 #include <cstdint>
0023 #include <memory>
0024 #include <optional>
0025 #include <string>
0026 #include <tuple>
0027 #include <utility>
0028 
0029 namespace llvm {
0030 
0031 /// A format-neutral container for source line information.
0032 struct DILineInfo {
0033   static constexpr const char *const ApproxString = "(approximate)";
0034   // DILineInfo contains "<invalid>" for function/filename it cannot fetch.
0035   static constexpr const char *const BadString = "<invalid>";
0036   // Use "??" instead of "<invalid>" to make our output closer to addr2line.
0037   static constexpr const char *const Addr2LineBadString = "??";
0038   std::string FileName;
0039   std::string FunctionName;
0040   std::string StartFileName;
0041   // Full source corresponding to `FileName`
0042   std::optional<StringRef> Source;
0043   // Source code for this particular line
0044   // (in case if `Source` is not available)
0045   std::optional<StringRef> LineSource;
0046   uint32_t Line = 0;
0047   uint32_t Column = 0;
0048   uint32_t StartLine = 0;
0049   std::optional<uint64_t> StartAddress;
0050 
0051   // DWARF-specific.
0052   uint32_t Discriminator = 0;
0053 
0054   bool IsApproximateLine = false;
0055   DILineInfo()
0056       : FileName(BadString), FunctionName(BadString), StartFileName(BadString) {
0057   }
0058 
0059   bool operator==(const DILineInfo &RHS) const {
0060     return Line == RHS.Line && Column == RHS.Column &&
0061            FileName == RHS.FileName && FunctionName == RHS.FunctionName &&
0062            StartFileName == RHS.StartFileName && StartLine == RHS.StartLine &&
0063            Discriminator == RHS.Discriminator;
0064   }
0065 
0066   bool operator!=(const DILineInfo &RHS) const { return !(*this == RHS); }
0067 
0068   bool operator<(const DILineInfo &RHS) const {
0069     return std::tie(FileName, FunctionName, StartFileName, Line, Column,
0070                     StartLine, Discriminator) <
0071            std::tie(RHS.FileName, RHS.FunctionName, RHS.StartFileName, RHS.Line,
0072                     RHS.Column, RHS.StartLine, RHS.Discriminator);
0073   }
0074 
0075   explicit operator bool() const { return *this != DILineInfo(); }
0076 
0077   void dump(raw_ostream &OS) {
0078     OS << "Line info: ";
0079     if (FileName != BadString)
0080       OS << "file '" << FileName << "', ";
0081     if (FunctionName != BadString)
0082       OS << "function '" << FunctionName << "', ";
0083     OS << "line " << Line << ", ";
0084     OS << "column " << Column << ", ";
0085     if (StartFileName != BadString)
0086       OS << "start file '" << StartFileName << "', ";
0087     OS << "start line " << StartLine << '\n';
0088   }
0089 };
0090 
0091 using DILineInfoTable = SmallVector<std::pair<uint64_t, DILineInfo>, 16>;
0092 
0093 /// A format-neutral container for inlined code description.
0094 class DIInliningInfo {
0095   SmallVector<DILineInfo, 4> Frames;
0096 
0097 public:
0098   DIInliningInfo() = default;
0099 
0100   /// Returns the frame at `Index`. Frames are stored in bottom-up
0101   /// (leaf-to-root) order with increasing index.
0102   const DILineInfo &getFrame(unsigned Index) const {
0103     assert(Index < Frames.size());
0104     return Frames[Index];
0105   }
0106 
0107   DILineInfo *getMutableFrame(unsigned Index) {
0108     assert(Index < Frames.size());
0109     return &Frames[Index];
0110   }
0111 
0112   uint32_t getNumberOfFrames() const { return Frames.size(); }
0113 
0114   void addFrame(const DILineInfo &Frame) { Frames.push_back(Frame); }
0115 
0116   void resize(unsigned i) { Frames.resize(i); }
0117 };
0118 
0119 /// Container for description of a global variable.
0120 struct DIGlobal {
0121   std::string Name;
0122   uint64_t Start = 0;
0123   uint64_t Size = 0;
0124   std::string DeclFile;
0125   uint64_t DeclLine = 0;
0126 
0127   DIGlobal() : Name(DILineInfo::BadString) {}
0128 };
0129 
0130 struct DILocal {
0131   std::string FunctionName;
0132   std::string Name;
0133   std::string DeclFile;
0134   uint64_t DeclLine = 0;
0135   std::optional<int64_t> FrameOffset;
0136   std::optional<uint64_t> Size;
0137   std::optional<uint64_t> TagOffset;
0138 };
0139 
0140 /// A DINameKind is passed to name search methods to specify a
0141 /// preference regarding the type of name resolution the caller wants.
0142 enum class DINameKind { None, ShortName, LinkageName };
0143 
0144 /// Controls which fields of DILineInfo container should be filled
0145 /// with data.
0146 struct DILineInfoSpecifier {
0147   enum class FileLineInfoKind {
0148     None,
0149     // RawValue is whatever the compiler stored in the filename table.  Could be
0150     // a full path, could be something else.
0151     RawValue,
0152     BaseNameOnly,
0153     // Relative to the compilation directory.
0154     RelativeFilePath,
0155     AbsoluteFilePath
0156   };
0157   using FunctionNameKind = DINameKind;
0158   FileLineInfoKind FLIKind;
0159   FunctionNameKind FNKind;
0160   bool ApproximateLine;
0161 
0162   DILineInfoSpecifier(FileLineInfoKind FLIKind = FileLineInfoKind::RawValue,
0163                       FunctionNameKind FNKind = FunctionNameKind::None,
0164                       bool ApproximateLine = false)
0165       : FLIKind(FLIKind), FNKind(FNKind), ApproximateLine(ApproximateLine) {}
0166 
0167   inline bool operator==(const DILineInfoSpecifier &RHS) const {
0168     return FLIKind == RHS.FLIKind && FNKind == RHS.FNKind;
0169   }
0170 };
0171 
0172 /// This is just a helper to programmatically construct DIDumpType.
0173 enum DIDumpTypeCounter {
0174 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
0175   DIDT_ID_##ENUM_NAME,
0176 #include "llvm/BinaryFormat/Dwarf.def"
0177 #undef HANDLE_DWARF_SECTION
0178   DIDT_ID_UUID,
0179   DIDT_ID_Count
0180 };
0181 static_assert(DIDT_ID_Count <= 32, "section types overflow storage");
0182 
0183 /// Selects which debug sections get dumped.
0184 enum DIDumpType : unsigned {
0185   DIDT_Null,
0186   DIDT_All = ~0U,
0187 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
0188   DIDT_##ENUM_NAME = 1U << DIDT_ID_##ENUM_NAME,
0189 #include "llvm/BinaryFormat/Dwarf.def"
0190 #undef HANDLE_DWARF_SECTION
0191   DIDT_UUID = 1 << DIDT_ID_UUID,
0192 };
0193 
0194 /// Container for dump options that control which debug information will be
0195 /// dumped.
0196 struct DIDumpOptions {
0197   unsigned DumpType = DIDT_All;
0198   unsigned ChildRecurseDepth = -1U;
0199   unsigned ParentRecurseDepth = -1U;
0200   uint16_t Version = 0; // DWARF version to assume when extracting.
0201   uint8_t AddrSize = 4; // Address byte size to assume when extracting.
0202   bool ShowAddresses = true;
0203   bool ShowChildren = false;
0204   bool ShowParents = false;
0205   bool ShowForm = false;
0206   bool SummarizeTypes = false;
0207   bool Verbose = false;
0208   bool DisplayRawContents = false;
0209   bool IsEH = false;
0210   bool DumpNonSkeleton = false;
0211   bool ShowAggregateErrors = false;
0212   std::string JsonErrSummaryFile;
0213   std::function<llvm::StringRef(uint64_t DwarfRegNum, bool IsEH)>
0214       GetNameForDWARFReg;
0215 
0216   /// Return default option set for printing a single DIE without children.
0217   static DIDumpOptions getForSingleDIE() {
0218     DIDumpOptions Opts;
0219     Opts.ChildRecurseDepth = 0;
0220     Opts.ParentRecurseDepth = 0;
0221     return Opts;
0222   }
0223 
0224   /// Return the options with RecurseDepth set to 0 unless explicitly required.
0225   DIDumpOptions noImplicitRecursion() const {
0226     DIDumpOptions Opts = *this;
0227     if (ChildRecurseDepth == -1U && !ShowChildren)
0228       Opts.ChildRecurseDepth = 0;
0229     if (ParentRecurseDepth == -1U && !ShowParents)
0230       Opts.ParentRecurseDepth = 0;
0231     return Opts;
0232   }
0233 
0234   std::function<void(Error)> RecoverableErrorHandler =
0235       WithColor::defaultErrorHandler;
0236   std::function<void(Error)> WarningHandler = WithColor::defaultWarningHandler;
0237 };
0238 
0239 class DIContext {
0240 public:
0241   enum DIContextKind { CK_DWARF, CK_PDB, CK_BTF };
0242 
0243   DIContext(DIContextKind K) : Kind(K) {}
0244   virtual ~DIContext() = default;
0245 
0246   DIContextKind getKind() const { return Kind; }
0247 
0248   virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0;
0249 
0250   virtual bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) {
0251     // No verifier? Just say things went well.
0252     return true;
0253   }
0254 
0255   virtual DILineInfo getLineInfoForAddress(
0256       object::SectionedAddress Address,
0257       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
0258   virtual DILineInfo
0259   getLineInfoForDataAddress(object::SectionedAddress Address) = 0;
0260   virtual DILineInfoTable getLineInfoForAddressRange(
0261       object::SectionedAddress Address, uint64_t Size,
0262       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
0263   virtual DIInliningInfo getInliningInfoForAddress(
0264       object::SectionedAddress Address,
0265       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
0266 
0267   virtual std::vector<DILocal>
0268   getLocalsForAddress(object::SectionedAddress Address) = 0;
0269 
0270 private:
0271   const DIContextKind Kind;
0272 };
0273 
0274 /// An inferface for inquiring the load address of a loaded object file
0275 /// to be used by the DIContext implementations when applying relocations
0276 /// on the fly.
0277 class LoadedObjectInfo {
0278 protected:
0279   LoadedObjectInfo() = default;
0280   LoadedObjectInfo(const LoadedObjectInfo &) = default;
0281 
0282 public:
0283   virtual ~LoadedObjectInfo() = default;
0284 
0285   /// Obtain the Load Address of a section by SectionRef.
0286   ///
0287   /// Calculate the address of the given section.
0288   /// The section need not be present in the local address space. The addresses
0289   /// need to be consistent with the addresses used to query the DIContext and
0290   /// the output of this function should be deterministic, i.e. repeated calls
0291   /// with the same Sec should give the same address.
0292   virtual uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const {
0293     return 0;
0294   }
0295 
0296   /// If conveniently available, return the content of the given Section.
0297   ///
0298   /// When the section is available in the local address space, in relocated
0299   /// (loaded) form, e.g. because it was relocated by a JIT for execution, this
0300   /// function should provide the contents of said section in `Data`. If the
0301   /// loaded section is not available, or the cost of retrieving it would be
0302   /// prohibitive, this function should return false. In that case, relocations
0303   /// will be read from the local (unrelocated) object file and applied on the
0304   /// fly. Note that this method is used purely for optimzation purposes in the
0305   /// common case of JITting in the local address space, so returning false
0306   /// should always be correct.
0307   virtual bool getLoadedSectionContents(const object::SectionRef &Sec,
0308                                         StringRef &Data) const {
0309     return false;
0310   }
0311 
0312   // FIXME: This is untested and unused anywhere in the LLVM project, it's
0313   // used/needed by Julia (an external project). It should have some coverage
0314   // (at least tests, but ideally example functionality).
0315   /// Obtain a copy of this LoadedObjectInfo.
0316   virtual std::unique_ptr<LoadedObjectInfo> clone() const = 0;
0317 };
0318 
0319 template <typename Derived, typename Base = LoadedObjectInfo>
0320 struct LoadedObjectInfoHelper : Base {
0321 protected:
0322   LoadedObjectInfoHelper(const LoadedObjectInfoHelper &) = default;
0323   LoadedObjectInfoHelper() = default;
0324 
0325 public:
0326   template <typename... Ts>
0327   LoadedObjectInfoHelper(Ts &&...Args) : Base(std::forward<Ts>(Args)...) {}
0328 
0329   std::unique_ptr<llvm::LoadedObjectInfo> clone() const override {
0330     return std::make_unique<Derived>(static_cast<const Derived &>(*this));
0331   }
0332 };
0333 
0334 } // end namespace llvm
0335 
0336 #endif // LLVM_DEBUGINFO_DICONTEXT_H