//===-- LVCodeViewReader.h --------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the LVCodeViewReader class, which is used to describe a // debug information (COFF) reader. // //===----------------------------------------------------------------------===// #ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWREADER_H #define LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWREADER_H #include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h" #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryItemStream.h" #include "llvm/Support/BinaryStreamArray.h" namespace llvm { template <> struct BinaryItemTraits { static size_t length(const codeview::CVType &Item) { return Item.length(); } static ArrayRef bytes(const codeview::CVType &Item) { return Item.data(); } }; namespace codeview { class LazyRandomTypeCollection; } namespace object { struct coff_section; } namespace pdb { class SymbolGroup; } namespace logicalview { class LVElement; class LVLine; class LVScope; class LVScopeCompileUnit; class LVSymbol; class LVType; class LVTypeVisitor; class LVSymbolVisitor; class LVSymbolVisitorDelegate; using LVNames = SmallVector; // The ELF reader uses the DWARF constants to create the logical elements. // The DW_TAG_* and DW_AT_* are used to select the logical object and to // set specific attributes, such as name, type, etc. // As the CodeView constants are different to the DWARF constants, the // CodeView reader will map them to the DWARF ones. class LVCodeViewReader final : public LVBinaryReader { friend class LVTypeVisitor; friend class LVSymbolVisitor; friend class LVSymbolVisitorDelegate; using LVModules = std::vector; LVModules Modules; // Encapsulates access to the input file and any dependent type server, // including any precompiled header object. llvm::pdb::InputFile Input; std::shared_ptr TypeServer; std::shared_ptr PrecompHeader; // Persistance data when loading a type server. ErrorOr> BuffOrErr = nullptr; std::unique_ptr MemBuffer; std::unique_ptr Session; std::unique_ptr PdbSession; // Persistance data when loading a precompiled header. BumpPtrAllocator BuilderAllocator; std::unique_ptr Builder; std::unique_ptr> ItemStream; std::unique_ptr ReaderPrecomp; std::vector TypeArray; CVTypeArray TypeStream; CVTypeArray CVTypesPrecomp; // Persistance data when loading an executable file. std::unique_ptr BinaryBuffer; std::unique_ptr BinaryExecutable; Error loadTargetInfo(const object::ObjectFile &Obj); Error loadTargetInfo(const llvm::pdb::PDBFile &Pdb); void mapRangeAddress(const object::ObjectFile &Obj, const object::SectionRef &Section, bool IsComdat) override; llvm::object::COFFObjectFile &getObj() { return Input.obj(); } llvm::pdb::PDBFile &getPdb() { return Input.pdb(); } bool isObj() const { return Input.isObj(); } bool isPdb() const { return Input.isPdb(); } StringRef getFileName() { return Input.getFilePath(); } // Pathname to executable image. std::string ExePath; LVOffset CurrentOffset = 0; int32_t CurrentModule = -1; using RelocMapTy = DenseMap>; RelocMapTy RelocMap; // Object files have only one type stream that contains both types and ids. // Precompiled header objects don't contain an IPI stream. Use the TPI. LazyRandomTypeCollection &types() { return TypeServer ? TypeServer->types() : (PrecompHeader ? *PrecompHeader : Input.types()); } LazyRandomTypeCollection &ids() { return TypeServer ? TypeServer->ids() : (PrecompHeader ? *PrecompHeader : Input.ids()); } LVLogicalVisitor LogicalVisitor; Expected getFileNameForFileOffset(uint32_t FileOffset, const llvm::pdb::SymbolGroup *SG = nullptr); void printRelocatedField(StringRef Label, const llvm::object::coff_section *CoffSection, uint32_t RelocOffset, uint32_t Offset, StringRef *RelocSym); Error printFileNameForOffset(StringRef Label, uint32_t FileOffset, const llvm::pdb::SymbolGroup *SG = nullptr); Error loadPrecompiledObject(PrecompRecord &Precomp, CVTypeArray &CVTypesObj); Error loadTypeServer(TypeServer2Record &TS); Error traverseTypes(llvm::pdb::PDBFile &Pdb, LazyRandomTypeCollection &Types, LazyRandomTypeCollection &Ids); Error collectInlineeInfo(DebugInlineeLinesSubsectionRef &Lines, const llvm::pdb::SymbolGroup *SG = nullptr); void cacheRelocations(); Error resolveSymbol(const llvm::object::coff_section *CoffSection, uint64_t Offset, llvm::object::SymbolRef &Sym); Error resolveSymbolName(const llvm::object::coff_section *CoffSection, uint64_t Offset, StringRef &Name); Error traverseTypeSection(StringRef SectionName, const llvm::object::SectionRef &Section); Error traverseSymbolSection(StringRef SectionName, const llvm::object::SectionRef &Section); Error traverseInlineeLines(StringRef Subsection); DebugChecksumsSubsectionRef CVFileChecksumTable; DebugStringTableSubsectionRef CVStringTable; Error traverseSymbolsSubsection(StringRef Subsection, const llvm::object::SectionRef &Section, StringRef SectionContents); /// Given a .debug$S section, find the string table and file checksum table. /// This function taken from (COFFDumper.cpp). /// TODO: It can be moved to the COFF library. Error initializeFileAndStringTables(BinaryStreamReader &Reader); Error createLines(const FixedStreamArray &LineNumbers, LVAddress Addendum, uint32_t Segment, uint32_t Begin, uint32_t Size, uint32_t NameIndex, const llvm::pdb::SymbolGroup *SG = nullptr); Error createScopes(llvm::object::COFFObjectFile &Obj); Error createScopes(llvm::pdb::PDBFile &Pdb); Error processModule(); protected: Error createScopes() override; void sortScopes() override; public: LVCodeViewReader() = delete; LVCodeViewReader(StringRef Filename, StringRef FileFormatName, llvm::object::COFFObjectFile &Obj, ScopedPrinter &W, StringRef ExePath) : LVBinaryReader(Filename, FileFormatName, W, LVBinaryType::COFF), Input(&Obj), ExePath(ExePath), LogicalVisitor(this, W, Input) {} LVCodeViewReader(StringRef Filename, StringRef FileFormatName, llvm::pdb::PDBFile &Pdb, ScopedPrinter &W, StringRef ExePath) : LVBinaryReader(Filename, FileFormatName, W, LVBinaryType::COFF), Input(&Pdb), ExePath(ExePath), LogicalVisitor(this, W, Input) {} LVCodeViewReader(const LVCodeViewReader &) = delete; LVCodeViewReader &operator=(const LVCodeViewReader &) = delete; ~LVCodeViewReader() = default; void getLinkageName(const llvm::object::coff_section *CoffSection, uint32_t RelocOffset, uint32_t Offset, StringRef *RelocSym); void addModule(LVScope *Scope) { Modules.push_back(Scope); } LVScope *getScopeForModule(uint32_t Modi) { return Modi >= Modules.size() ? nullptr : Modules[Modi]; } // Get the string representation for the CodeView symbols. static StringRef getSymbolKindName(SymbolKind Kind); static std::string formatRegisterId(RegisterId Register, CPUType CPU); std::string getRegisterName(LVSmall Opcode, ArrayRef Operands) override; bool isSystemEntry(LVElement *Element, StringRef Name) const override; void print(raw_ostream &OS) const; void printRecords(raw_ostream &OS) const override { LogicalVisitor.printRecords(OS); }; #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void dump() const { print(dbgs()); } #endif }; } // end namespace logicalview } // end namespace llvm #endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWREADER_H