| //===- InputFile.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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_DEBUGINFO_PDB_NATIVE_INPUTFILE_H |
| #define LLVM_DEBUGINFO_PDB_NATIVE_INPUTFILE_H |
| |
| #include "llvm/ADT/PointerUnion.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/iterator.h" |
| #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" |
| #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" |
| #include "llvm/DebugInfo/PDB/Native/LinePrinter.h" |
| #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" |
| #include "llvm/Object/Binary.h" |
| #include "llvm/Object/ObjectFile.h" |
| #include "llvm/Support/Error.h" |
| |
| namespace llvm { |
| namespace codeview { |
| class LazyRandomTypeCollection; |
| } |
| namespace object { |
| class COFFObjectFile; |
| } // namespace object |
| |
| namespace pdb { |
| class InputFile; |
| class LinePrinter; |
| class PDBFile; |
| class NativeSession; |
| class SymbolGroupIterator; |
| class SymbolGroup; |
| |
| class InputFile { |
| InputFile(); |
| |
| std::unique_ptr<NativeSession> PdbSession; |
| object::OwningBinary<object::Binary> CoffObject; |
| std::unique_ptr<MemoryBuffer> UnknownFile; |
| PointerUnion<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj; |
| |
| using TypeCollectionPtr = std::unique_ptr<codeview::LazyRandomTypeCollection>; |
| |
| TypeCollectionPtr Types; |
| TypeCollectionPtr Ids; |
| |
| enum TypeCollectionKind { kTypes, kIds }; |
| codeview::LazyRandomTypeCollection & |
| getOrCreateTypeCollection(TypeCollectionKind Kind); |
| |
| public: |
| InputFile(PDBFile *Pdb) { PdbOrObj = Pdb; } |
| InputFile(object::COFFObjectFile *Obj) { PdbOrObj = Obj; } |
| InputFile(MemoryBuffer *Buffer) { PdbOrObj = Buffer; } |
| ~InputFile(); |
| InputFile(InputFile &&Other) = default; |
| |
| static Expected<InputFile> open(StringRef Path, |
| bool AllowUnknownFile = false); |
| |
| PDBFile &pdb(); |
| const PDBFile &pdb() const; |
| object::COFFObjectFile &obj(); |
| const object::COFFObjectFile &obj() const; |
| MemoryBuffer &unknown(); |
| const MemoryBuffer &unknown() const; |
| |
| StringRef getFilePath() const; |
| |
| bool hasTypes() const; |
| bool hasIds() const; |
| |
| codeview::LazyRandomTypeCollection &types(); |
| codeview::LazyRandomTypeCollection &ids(); |
| |
| iterator_range<SymbolGroupIterator> symbol_groups(); |
| SymbolGroupIterator symbol_groups_begin(); |
| SymbolGroupIterator symbol_groups_end(); |
| |
| bool isPdb() const; |
| bool isObj() const; |
| bool isUnknown() const; |
| }; |
| |
| class SymbolGroup { |
| friend class SymbolGroupIterator; |
| |
| public: |
| explicit SymbolGroup(InputFile *File, uint32_t GroupIndex = 0); |
| |
| Expected<StringRef> getNameFromStringTable(uint32_t Offset) const; |
| Expected<StringRef> getNameFromChecksums(uint32_t Offset) const; |
| |
| void formatFromFileName(LinePrinter &Printer, StringRef File, |
| bool Append = false) const; |
| |
| void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset, |
| bool Append = false) const; |
| |
| StringRef name() const; |
| |
| codeview::DebugSubsectionArray getDebugSubsections() const { |
| return Subsections; |
| } |
| const ModuleDebugStreamRef &getPdbModuleStream() const; |
| |
| const InputFile &getFile() const { return *File; } |
| InputFile &getFile() { return *File; } |
| |
| bool hasDebugStream() const { return DebugStream != nullptr; } |
| |
| private: |
| void initializeForPdb(uint32_t Modi); |
| void updatePdbModi(uint32_t Modi); |
| void updateDebugS(const codeview::DebugSubsectionArray &SS); |
| |
| void rebuildChecksumMap(); |
| InputFile *File = nullptr; |
| StringRef Name; |
| codeview::DebugSubsectionArray Subsections; |
| std::shared_ptr<ModuleDebugStreamRef> DebugStream; |
| codeview::StringsAndChecksumsRef SC; |
| StringMap<codeview::FileChecksumEntry> ChecksumsByFile; |
| }; |
| |
| class SymbolGroupIterator |
| : public iterator_facade_base<SymbolGroupIterator, |
| std::forward_iterator_tag, SymbolGroup> { |
| public: |
| SymbolGroupIterator(); |
| explicit SymbolGroupIterator(InputFile &File); |
| SymbolGroupIterator(const SymbolGroupIterator &Other) = default; |
| SymbolGroupIterator &operator=(const SymbolGroupIterator &R) = default; |
| |
| const SymbolGroup &operator*() const; |
| SymbolGroup &operator*(); |
| |
| bool operator==(const SymbolGroupIterator &R) const; |
| SymbolGroupIterator &operator++(); |
| |
| private: |
| void scanToNextDebugS(); |
| bool isEnd() const; |
| |
| uint32_t Index = 0; |
| std::optional<object::section_iterator> SectionIter; |
| SymbolGroup Value; |
| }; |
| |
| Expected<ModuleDebugStreamRef> |
| getModuleDebugStream(PDBFile &File, StringRef &ModuleName, uint32_t Index); |
| Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File, |
| uint32_t Index); |
| |
| bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group, |
| const FilterOptions &Filters); |
| |
| // TODO: Change these callbacks to be function_refs (de-templatify them). |
| template <typename CallbackT> |
| Error iterateOneModule(InputFile &File, const PrintScope &HeaderScope, |
| const SymbolGroup &SG, uint32_t Modi, |
| CallbackT Callback) { |
| HeaderScope.P.formatLine( |
| "Mod {0:4} | `{1}`: ", |
| fmt_align(Modi, AlignStyle::Right, HeaderScope.LabelWidth), SG.name()); |
| |
| AutoIndent Indent(HeaderScope); |
| return Callback(Modi, SG); |
| } |
| |
| template <typename CallbackT> |
| Error iterateSymbolGroups(InputFile &Input, const PrintScope &HeaderScope, |
| CallbackT Callback) { |
| AutoIndent Indent(HeaderScope); |
| |
| FilterOptions Filters = HeaderScope.P.getFilters(); |
| if (Filters.DumpModi) { |
| uint32_t Modi = *Filters.DumpModi; |
| SymbolGroup SG(&Input, Modi); |
| return iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), |
| SG, Modi, Callback); |
| } |
| |
| uint32_t I = 0; |
| |
| for (const auto &SG : Input.symbol_groups()) { |
| if (shouldDumpSymbolGroup(I, SG, Filters)) |
| if (auto Err = |
| iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), |
| SG, I, Callback)) |
| return Err; |
| |
| ++I; |
| } |
| return Error::success(); |
| } |
| |
| template <typename SubsectionT> |
| Error iterateModuleSubsections( |
| InputFile &File, const PrintScope &HeaderScope, |
| llvm::function_ref<Error(uint32_t, const SymbolGroup &, SubsectionT &)> |
| Callback) { |
| |
| return iterateSymbolGroups( |
| File, HeaderScope, [&](uint32_t Modi, const SymbolGroup &SG) -> Error { |
| for (const auto &SS : SG.getDebugSubsections()) { |
| SubsectionT Subsection; |
| |
| if (SS.kind() != Subsection.kind()) |
| continue; |
| |
| BinaryStreamReader Reader(SS.getRecordData()); |
| if (auto Err = Subsection.initialize(Reader)) |
| continue; |
| if (auto Err = Callback(Modi, SG, Subsection)) |
| return Err; |
| } |
| return Error::success(); |
| }); |
| } |
| |
| } // namespace pdb |
| } // namespace llvm |
| |
| #endif |