1 //===- InputFile.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 #ifndef LLVM_DEBUGINFO_PDB_NATIVE_INPUTFILE_H 10 #define LLVM_DEBUGINFO_PDB_NATIVE_INPUTFILE_H 11 12 #include "llvm/ADT/Optional.h" 13 #include "llvm/ADT/PointerUnion.h" 14 #include "llvm/ADT/StringMap.h" 15 #include "llvm/ADT/iterator.h" 16 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 17 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" 18 #include "llvm/DebugInfo/PDB/Native/LinePrinter.h" 19 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 20 #include "llvm/Object/Binary.h" 21 #include "llvm/Object/ObjectFile.h" 22 #include "llvm/Support/Error.h" 23 24 namespace llvm { 25 namespace codeview { 26 class LazyRandomTypeCollection; 27 } 28 namespace object { 29 class COFFObjectFile; 30 } // namespace object 31 32 namespace pdb { 33 class InputFile; 34 class LinePrinter; 35 class PDBFile; 36 class NativeSession; 37 class SymbolGroupIterator; 38 class SymbolGroup; 39 40 class InputFile { 41 InputFile(); 42 43 std::unique_ptr<NativeSession> PdbSession; 44 object::OwningBinary<object::Binary> CoffObject; 45 std::unique_ptr<MemoryBuffer> UnknownFile; 46 PointerUnion<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj; 47 48 using TypeCollectionPtr = std::unique_ptr<codeview::LazyRandomTypeCollection>; 49 50 TypeCollectionPtr Types; 51 TypeCollectionPtr Ids; 52 53 enum TypeCollectionKind { kTypes, kIds }; 54 codeview::LazyRandomTypeCollection & 55 getOrCreateTypeCollection(TypeCollectionKind Kind); 56 57 public: 58 InputFile(PDBFile *Pdb) { PdbOrObj = Pdb; } 59 InputFile(object::COFFObjectFile *Obj) { PdbOrObj = Obj; } 60 InputFile(MemoryBuffer *Buffer) { PdbOrObj = Buffer; } 61 ~InputFile(); 62 InputFile(InputFile &&Other) = default; 63 64 static Expected<InputFile> open(StringRef Path, 65 bool AllowUnknownFile = false); 66 67 PDBFile &pdb(); 68 const PDBFile &pdb() const; 69 object::COFFObjectFile &obj(); 70 const object::COFFObjectFile &obj() const; 71 MemoryBuffer &unknown(); 72 const MemoryBuffer &unknown() const; 73 74 StringRef getFilePath() const; 75 76 bool hasTypes() const; 77 bool hasIds() const; 78 79 codeview::LazyRandomTypeCollection &types(); 80 codeview::LazyRandomTypeCollection &ids(); 81 82 iterator_range<SymbolGroupIterator> symbol_groups(); 83 SymbolGroupIterator symbol_groups_begin(); 84 SymbolGroupIterator symbol_groups_end(); 85 86 bool isPdb() const; 87 bool isObj() const; 88 bool isUnknown() const; 89 }; 90 91 class SymbolGroup { 92 friend class SymbolGroupIterator; 93 94 public: 95 explicit SymbolGroup(InputFile *File, uint32_t GroupIndex = 0); 96 97 Expected<StringRef> getNameFromStringTable(uint32_t Offset) const; 98 Expected<StringRef> getNameFromChecksums(uint32_t Offset) const; 99 100 void formatFromFileName(LinePrinter &Printer, StringRef File, 101 bool Append = false) const; 102 103 void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset, 104 bool Append = false) const; 105 106 StringRef name() const; 107 108 codeview::DebugSubsectionArray getDebugSubsections() const { 109 return Subsections; 110 } 111 const ModuleDebugStreamRef &getPdbModuleStream() const; 112 113 const InputFile &getFile() const { return *File; } 114 InputFile &getFile() { return *File; } 115 116 bool hasDebugStream() const { return DebugStream != nullptr; } 117 118 private: 119 void initializeForPdb(uint32_t Modi); 120 void updatePdbModi(uint32_t Modi); 121 void updateDebugS(const codeview::DebugSubsectionArray &SS); 122 123 void rebuildChecksumMap(); 124 InputFile *File = nullptr; 125 StringRef Name; 126 codeview::DebugSubsectionArray Subsections; 127 std::shared_ptr<ModuleDebugStreamRef> DebugStream; 128 codeview::StringsAndChecksumsRef SC; 129 StringMap<codeview::FileChecksumEntry> ChecksumsByFile; 130 }; 131 132 class SymbolGroupIterator 133 : public iterator_facade_base<SymbolGroupIterator, 134 std::forward_iterator_tag, SymbolGroup> { 135 public: 136 SymbolGroupIterator(); 137 explicit SymbolGroupIterator(InputFile &File); 138 SymbolGroupIterator(const SymbolGroupIterator &Other) = default; 139 SymbolGroupIterator &operator=(const SymbolGroupIterator &R) = default; 140 141 const SymbolGroup &operator*() const; 142 SymbolGroup &operator*(); 143 144 bool operator==(const SymbolGroupIterator &R) const; 145 SymbolGroupIterator &operator++(); 146 147 private: 148 void scanToNextDebugS(); 149 bool isEnd() const; 150 151 uint32_t Index = 0; 152 Optional<object::section_iterator> SectionIter; 153 SymbolGroup Value; 154 }; 155 156 Expected<ModuleDebugStreamRef> 157 getModuleDebugStream(PDBFile &File, StringRef &ModuleName, uint32_t Index); 158 Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File, 159 uint32_t Index); 160 161 bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group, 162 const FilterOptions &Filters); 163 164 // TODO: Change these callbacks to be function_refs (de-templatify them). 165 template <typename CallbackT> 166 Error iterateOneModule(InputFile &File, const PrintScope &HeaderScope, 167 const SymbolGroup &SG, uint32_t Modi, 168 CallbackT Callback) { 169 HeaderScope.P.formatLine( 170 "Mod {0:4} | `{1}`: ", 171 fmt_align(Modi, AlignStyle::Right, HeaderScope.LabelWidth), SG.name()); 172 173 AutoIndent Indent(HeaderScope); 174 return Callback(Modi, SG); 175 } 176 177 template <typename CallbackT> 178 Error iterateSymbolGroups(InputFile &Input, const PrintScope &HeaderScope, 179 CallbackT Callback) { 180 AutoIndent Indent(HeaderScope); 181 182 FilterOptions Filters = HeaderScope.P.getFilters(); 183 if (Filters.DumpModi) { 184 uint32_t Modi = *Filters.DumpModi; 185 SymbolGroup SG(&Input, Modi); 186 return iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), 187 SG, Modi, Callback); 188 } 189 190 uint32_t I = 0; 191 192 for (const auto &SG : Input.symbol_groups()) { 193 if (shouldDumpSymbolGroup(I, SG, Filters)) 194 if (auto Err = 195 iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), 196 SG, I, Callback)) 197 return Err; 198 199 ++I; 200 } 201 return Error::success(); 202 } 203 204 template <typename SubsectionT> 205 Error iterateModuleSubsections( 206 InputFile &File, const PrintScope &HeaderScope, 207 llvm::function_ref<Error(uint32_t, const SymbolGroup &, SubsectionT &)> 208 Callback) { 209 210 return iterateSymbolGroups( 211 File, HeaderScope, [&](uint32_t Modi, const SymbolGroup &SG) -> Error { 212 for (const auto &SS : SG.getDebugSubsections()) { 213 SubsectionT Subsection; 214 215 if (SS.kind() != Subsection.kind()) 216 continue; 217 218 BinaryStreamReader Reader(SS.getRecordData()); 219 if (auto Err = Subsection.initialize(Reader)) 220 continue; 221 if (auto Err = Callback(Modi, SG, Subsection)) 222 return Err; 223 } 224 return Error::success(); 225 }); 226 } 227 228 } // namespace pdb 229 } // namespace llvm 230 231 #endif 232