1044eb2f6SDimitry Andric //===- InputFile.cpp ------------------------------------------ *- C++ --*-===//
2044eb2f6SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6044eb2f6SDimitry Andric //
7044eb2f6SDimitry Andric //===----------------------------------------------------------------------===//
8044eb2f6SDimitry Andric
9145449b1SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InputFile.h"
10044eb2f6SDimitry Andric
117fa27ce4SDimitry Andric #include "llvm/ADT/StringExtras.h"
12044eb2f6SDimitry Andric #include "llvm/BinaryFormat/Magic.h"
13044eb2f6SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
14044eb2f6SDimitry Andric #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
15044eb2f6SDimitry Andric #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
16145449b1SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
17044eb2f6SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
18145449b1SDimitry Andric #include "llvm/DebugInfo/PDB/Native/FormatUtil.h"
19145449b1SDimitry Andric #include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
20044eb2f6SDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
21044eb2f6SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
22044eb2f6SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
23044eb2f6SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
24044eb2f6SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
25044eb2f6SDimitry Andric #include "llvm/DebugInfo/PDB/PDB.h"
26044eb2f6SDimitry Andric #include "llvm/Object/COFF.h"
27044eb2f6SDimitry Andric #include "llvm/Support/FileSystem.h"
28044eb2f6SDimitry Andric #include "llvm/Support/FormatVariadic.h"
29044eb2f6SDimitry Andric
30044eb2f6SDimitry Andric using namespace llvm;
31044eb2f6SDimitry Andric using namespace llvm::codeview;
32044eb2f6SDimitry Andric using namespace llvm::object;
33044eb2f6SDimitry Andric using namespace llvm::pdb;
34044eb2f6SDimitry Andric
35145449b1SDimitry Andric InputFile::InputFile() = default;
36145449b1SDimitry Andric InputFile::~InputFile() = default;
37044eb2f6SDimitry Andric
38145449b1SDimitry Andric Expected<ModuleDebugStreamRef>
getModuleDebugStream(PDBFile & File,StringRef & ModuleName,uint32_t Index)39145449b1SDimitry Andric llvm::pdb::getModuleDebugStream(PDBFile &File, StringRef &ModuleName,
40145449b1SDimitry Andric uint32_t Index) {
41145449b1SDimitry Andric Expected<DbiStream &> DbiOrErr = File.getPDBDbiStream();
42145449b1SDimitry Andric if (!DbiOrErr)
43145449b1SDimitry Andric return DbiOrErr.takeError();
44145449b1SDimitry Andric DbiStream &Dbi = *DbiOrErr;
45044eb2f6SDimitry Andric const auto &Modules = Dbi.modules();
46d8e91e46SDimitry Andric if (Index >= Modules.getModuleCount())
47d8e91e46SDimitry Andric return make_error<RawError>(raw_error_code::index_out_of_bounds,
48d8e91e46SDimitry Andric "Invalid module index");
49d8e91e46SDimitry Andric
50044eb2f6SDimitry Andric auto Modi = Modules.getModuleDescriptor(Index);
51044eb2f6SDimitry Andric
52044eb2f6SDimitry Andric ModuleName = Modi.getModuleName();
53044eb2f6SDimitry Andric
54044eb2f6SDimitry Andric uint16_t ModiStream = Modi.getModuleStreamIndex();
55044eb2f6SDimitry Andric if (ModiStream == kInvalidStreamIndex)
56044eb2f6SDimitry Andric return make_error<RawError>(raw_error_code::no_stream,
57044eb2f6SDimitry Andric "Module stream not present");
58044eb2f6SDimitry Andric
59044eb2f6SDimitry Andric auto ModStreamData = File.createIndexedStream(ModiStream);
60044eb2f6SDimitry Andric
61044eb2f6SDimitry Andric ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
62044eb2f6SDimitry Andric if (auto EC = ModS.reload())
63044eb2f6SDimitry Andric return make_error<RawError>(raw_error_code::corrupt_file,
64044eb2f6SDimitry Andric "Invalid module stream");
65044eb2f6SDimitry Andric
66044eb2f6SDimitry Andric return std::move(ModS);
67044eb2f6SDimitry Andric }
68044eb2f6SDimitry Andric
getModuleDebugStream(PDBFile & File,uint32_t Index)69145449b1SDimitry Andric Expected<ModuleDebugStreamRef> llvm::pdb::getModuleDebugStream(PDBFile &File,
70145449b1SDimitry Andric uint32_t Index) {
71145449b1SDimitry Andric Expected<DbiStream &> DbiOrErr = File.getPDBDbiStream();
72145449b1SDimitry Andric if (!DbiOrErr)
73145449b1SDimitry Andric return DbiOrErr.takeError();
74145449b1SDimitry Andric DbiStream &Dbi = *DbiOrErr;
75145449b1SDimitry Andric const auto &Modules = Dbi.modules();
76145449b1SDimitry Andric auto Modi = Modules.getModuleDescriptor(Index);
77145449b1SDimitry Andric
78145449b1SDimitry Andric uint16_t ModiStream = Modi.getModuleStreamIndex();
79145449b1SDimitry Andric if (ModiStream == kInvalidStreamIndex)
80145449b1SDimitry Andric return make_error<RawError>(raw_error_code::no_stream,
81145449b1SDimitry Andric "Module stream not present");
82145449b1SDimitry Andric
83145449b1SDimitry Andric auto ModStreamData = File.createIndexedStream(ModiStream);
84145449b1SDimitry Andric
85145449b1SDimitry Andric ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
86145449b1SDimitry Andric if (Error Err = ModS.reload())
87145449b1SDimitry Andric return make_error<RawError>(raw_error_code::corrupt_file,
88145449b1SDimitry Andric "Invalid module stream");
89145449b1SDimitry Andric
90145449b1SDimitry Andric return std::move(ModS);
91145449b1SDimitry Andric }
92145449b1SDimitry Andric
isCodeViewDebugSubsection(object::SectionRef Section,StringRef Name,BinaryStreamReader & Reader)93044eb2f6SDimitry Andric static inline bool isCodeViewDebugSubsection(object::SectionRef Section,
94044eb2f6SDimitry Andric StringRef Name,
95044eb2f6SDimitry Andric BinaryStreamReader &Reader) {
961d5ae102SDimitry Andric if (Expected<StringRef> NameOrErr = Section.getName()) {
971d5ae102SDimitry Andric if (*NameOrErr != Name)
98044eb2f6SDimitry Andric return false;
991d5ae102SDimitry Andric } else {
1001d5ae102SDimitry Andric consumeError(NameOrErr.takeError());
101044eb2f6SDimitry Andric return false;
1021d5ae102SDimitry Andric }
103044eb2f6SDimitry Andric
104e6d15924SDimitry Andric Expected<StringRef> ContentsOrErr = Section.getContents();
105e6d15924SDimitry Andric if (!ContentsOrErr) {
106e6d15924SDimitry Andric consumeError(ContentsOrErr.takeError());
107044eb2f6SDimitry Andric return false;
108e6d15924SDimitry Andric }
109044eb2f6SDimitry Andric
110b1c73532SDimitry Andric Reader = BinaryStreamReader(*ContentsOrErr, llvm::endianness::little);
111044eb2f6SDimitry Andric uint32_t Magic;
112044eb2f6SDimitry Andric if (Reader.bytesRemaining() < sizeof(uint32_t))
113044eb2f6SDimitry Andric return false;
114044eb2f6SDimitry Andric cantFail(Reader.readInteger(Magic));
115044eb2f6SDimitry Andric if (Magic != COFF::DEBUG_SECTION_MAGIC)
116044eb2f6SDimitry Andric return false;
117044eb2f6SDimitry Andric return true;
118044eb2f6SDimitry Andric }
119044eb2f6SDimitry Andric
isDebugSSection(object::SectionRef Section,DebugSubsectionArray & Subsections)120044eb2f6SDimitry Andric static inline bool isDebugSSection(object::SectionRef Section,
121044eb2f6SDimitry Andric DebugSubsectionArray &Subsections) {
122044eb2f6SDimitry Andric BinaryStreamReader Reader;
123044eb2f6SDimitry Andric if (!isCodeViewDebugSubsection(Section, ".debug$S", Reader))
124044eb2f6SDimitry Andric return false;
125044eb2f6SDimitry Andric
126044eb2f6SDimitry Andric cantFail(Reader.readArray(Subsections, Reader.bytesRemaining()));
127044eb2f6SDimitry Andric return true;
128044eb2f6SDimitry Andric }
129044eb2f6SDimitry Andric
isDebugTSection(SectionRef Section,CVTypeArray & Types)130044eb2f6SDimitry Andric static bool isDebugTSection(SectionRef Section, CVTypeArray &Types) {
131044eb2f6SDimitry Andric BinaryStreamReader Reader;
132eb11fae6SDimitry Andric if (!isCodeViewDebugSubsection(Section, ".debug$T", Reader) &&
133eb11fae6SDimitry Andric !isCodeViewDebugSubsection(Section, ".debug$P", Reader))
134044eb2f6SDimitry Andric return false;
135044eb2f6SDimitry Andric cantFail(Reader.readArray(Types, Reader.bytesRemaining()));
136044eb2f6SDimitry Andric return true;
137044eb2f6SDimitry Andric }
138044eb2f6SDimitry Andric
formatChecksumKind(FileChecksumKind Kind)139044eb2f6SDimitry Andric static std::string formatChecksumKind(FileChecksumKind Kind) {
140044eb2f6SDimitry Andric switch (Kind) {
141044eb2f6SDimitry Andric RETURN_CASE(FileChecksumKind, None, "None");
142044eb2f6SDimitry Andric RETURN_CASE(FileChecksumKind, MD5, "MD5");
143044eb2f6SDimitry Andric RETURN_CASE(FileChecksumKind, SHA1, "SHA-1");
144044eb2f6SDimitry Andric RETURN_CASE(FileChecksumKind, SHA256, "SHA-256");
145044eb2f6SDimitry Andric }
146044eb2f6SDimitry Andric return formatUnknownEnum(Kind);
147044eb2f6SDimitry Andric }
148044eb2f6SDimitry Andric
149044eb2f6SDimitry Andric template <typename... Args>
formatInternal(LinePrinter & Printer,bool Append,Args &&...args)150044eb2f6SDimitry Andric static void formatInternal(LinePrinter &Printer, bool Append, Args &&...args) {
151044eb2f6SDimitry Andric if (Append)
152044eb2f6SDimitry Andric Printer.format(std::forward<Args>(args)...);
153044eb2f6SDimitry Andric else
154044eb2f6SDimitry Andric Printer.formatLine(std::forward<Args>(args)...);
155044eb2f6SDimitry Andric }
156044eb2f6SDimitry Andric
SymbolGroup(InputFile * File,uint32_t GroupIndex)157044eb2f6SDimitry Andric SymbolGroup::SymbolGroup(InputFile *File, uint32_t GroupIndex) : File(File) {
158044eb2f6SDimitry Andric if (!File)
159044eb2f6SDimitry Andric return;
160044eb2f6SDimitry Andric
161044eb2f6SDimitry Andric if (File->isPdb())
162044eb2f6SDimitry Andric initializeForPdb(GroupIndex);
163044eb2f6SDimitry Andric else {
164044eb2f6SDimitry Andric Name = ".debug$S";
165044eb2f6SDimitry Andric uint32_t I = 0;
166044eb2f6SDimitry Andric for (const auto &S : File->obj().sections()) {
167044eb2f6SDimitry Andric DebugSubsectionArray SS;
168044eb2f6SDimitry Andric if (!isDebugSSection(S, SS))
169044eb2f6SDimitry Andric continue;
170044eb2f6SDimitry Andric
171044eb2f6SDimitry Andric if (!SC.hasChecksums() || !SC.hasStrings())
172044eb2f6SDimitry Andric SC.initialize(SS);
173044eb2f6SDimitry Andric
174044eb2f6SDimitry Andric if (I == GroupIndex)
175044eb2f6SDimitry Andric Subsections = SS;
176044eb2f6SDimitry Andric
177044eb2f6SDimitry Andric if (SC.hasChecksums() && SC.hasStrings())
178044eb2f6SDimitry Andric break;
179044eb2f6SDimitry Andric }
180044eb2f6SDimitry Andric rebuildChecksumMap();
181044eb2f6SDimitry Andric }
182044eb2f6SDimitry Andric }
183044eb2f6SDimitry Andric
name() const184044eb2f6SDimitry Andric StringRef SymbolGroup::name() const { return Name; }
185044eb2f6SDimitry Andric
updateDebugS(const codeview::DebugSubsectionArray & SS)186044eb2f6SDimitry Andric void SymbolGroup::updateDebugS(const codeview::DebugSubsectionArray &SS) {
187044eb2f6SDimitry Andric Subsections = SS;
188044eb2f6SDimitry Andric }
189044eb2f6SDimitry Andric
updatePdbModi(uint32_t Modi)190044eb2f6SDimitry Andric void SymbolGroup::updatePdbModi(uint32_t Modi) { initializeForPdb(Modi); }
191044eb2f6SDimitry Andric
initializeForPdb(uint32_t Modi)192044eb2f6SDimitry Andric void SymbolGroup::initializeForPdb(uint32_t Modi) {
193044eb2f6SDimitry Andric assert(File && File->isPdb());
194044eb2f6SDimitry Andric
195044eb2f6SDimitry Andric // PDB always uses the same string table, but each module has its own
196044eb2f6SDimitry Andric // checksums. So we only set the strings if they're not already set.
197d8e91e46SDimitry Andric if (!SC.hasStrings()) {
198d8e91e46SDimitry Andric auto StringTable = File->pdb().getStringTable();
199d8e91e46SDimitry Andric if (StringTable)
200d8e91e46SDimitry Andric SC.setStrings(StringTable->getStringTable());
201d8e91e46SDimitry Andric else
202d8e91e46SDimitry Andric consumeError(StringTable.takeError());
203d8e91e46SDimitry Andric }
204044eb2f6SDimitry Andric
205044eb2f6SDimitry Andric SC.resetChecksums();
206044eb2f6SDimitry Andric auto MDS = getModuleDebugStream(File->pdb(), Name, Modi);
207044eb2f6SDimitry Andric if (!MDS) {
208044eb2f6SDimitry Andric consumeError(MDS.takeError());
209044eb2f6SDimitry Andric return;
210044eb2f6SDimitry Andric }
211044eb2f6SDimitry Andric
212044eb2f6SDimitry Andric DebugStream = std::make_shared<ModuleDebugStreamRef>(std::move(*MDS));
213044eb2f6SDimitry Andric Subsections = DebugStream->getSubsectionsArray();
214044eb2f6SDimitry Andric SC.initialize(Subsections);
215044eb2f6SDimitry Andric rebuildChecksumMap();
216044eb2f6SDimitry Andric }
217044eb2f6SDimitry Andric
rebuildChecksumMap()218044eb2f6SDimitry Andric void SymbolGroup::rebuildChecksumMap() {
219044eb2f6SDimitry Andric if (!SC.hasChecksums())
220044eb2f6SDimitry Andric return;
221044eb2f6SDimitry Andric
222044eb2f6SDimitry Andric for (const auto &Entry : SC.checksums()) {
223044eb2f6SDimitry Andric auto S = SC.strings().getString(Entry.FileNameOffset);
224044eb2f6SDimitry Andric if (!S)
225044eb2f6SDimitry Andric continue;
226044eb2f6SDimitry Andric ChecksumsByFile[*S] = Entry;
227044eb2f6SDimitry Andric }
228044eb2f6SDimitry Andric }
229044eb2f6SDimitry Andric
getPdbModuleStream() const230044eb2f6SDimitry Andric const ModuleDebugStreamRef &SymbolGroup::getPdbModuleStream() const {
231044eb2f6SDimitry Andric assert(File && File->isPdb() && DebugStream);
232044eb2f6SDimitry Andric return *DebugStream;
233044eb2f6SDimitry Andric }
234044eb2f6SDimitry Andric
getNameFromStringTable(uint32_t Offset) const235044eb2f6SDimitry Andric Expected<StringRef> SymbolGroup::getNameFromStringTable(uint32_t Offset) const {
236044eb2f6SDimitry Andric return SC.strings().getString(Offset);
237044eb2f6SDimitry Andric }
238044eb2f6SDimitry Andric
getNameFromChecksums(uint32_t Offset) const239145449b1SDimitry Andric Expected<StringRef> SymbolGroup::getNameFromChecksums(uint32_t Offset) const {
240145449b1SDimitry Andric StringRef Name;
241145449b1SDimitry Andric if (!SC.hasChecksums()) {
242145449b1SDimitry Andric return std::move(Name);
243145449b1SDimitry Andric }
244145449b1SDimitry Andric
245145449b1SDimitry Andric auto Iter = SC.checksums().getArray().at(Offset);
246145449b1SDimitry Andric if (Iter == SC.checksums().getArray().end()) {
247145449b1SDimitry Andric return std::move(Name);
248145449b1SDimitry Andric }
249145449b1SDimitry Andric
250145449b1SDimitry Andric uint32_t FO = Iter->FileNameOffset;
251145449b1SDimitry Andric auto ExpectedFile = getNameFromStringTable(FO);
252145449b1SDimitry Andric if (!ExpectedFile) {
253145449b1SDimitry Andric return std::move(Name);
254145449b1SDimitry Andric }
255145449b1SDimitry Andric
256145449b1SDimitry Andric return *ExpectedFile;
257145449b1SDimitry Andric }
258145449b1SDimitry Andric
formatFromFileName(LinePrinter & Printer,StringRef File,bool Append) const259044eb2f6SDimitry Andric void SymbolGroup::formatFromFileName(LinePrinter &Printer, StringRef File,
260044eb2f6SDimitry Andric bool Append) const {
261044eb2f6SDimitry Andric auto FC = ChecksumsByFile.find(File);
262044eb2f6SDimitry Andric if (FC == ChecksumsByFile.end()) {
263044eb2f6SDimitry Andric formatInternal(Printer, Append, "- (no checksum) {0}", File);
264044eb2f6SDimitry Andric return;
265044eb2f6SDimitry Andric }
266044eb2f6SDimitry Andric
267044eb2f6SDimitry Andric formatInternal(Printer, Append, "- ({0}: {1}) {2}",
268044eb2f6SDimitry Andric formatChecksumKind(FC->getValue().Kind),
269044eb2f6SDimitry Andric toHex(FC->getValue().Checksum), File);
270044eb2f6SDimitry Andric }
271044eb2f6SDimitry Andric
formatFromChecksumsOffset(LinePrinter & Printer,uint32_t Offset,bool Append) const272044eb2f6SDimitry Andric void SymbolGroup::formatFromChecksumsOffset(LinePrinter &Printer,
273044eb2f6SDimitry Andric uint32_t Offset,
274044eb2f6SDimitry Andric bool Append) const {
275044eb2f6SDimitry Andric if (!SC.hasChecksums()) {
276044eb2f6SDimitry Andric formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
277044eb2f6SDimitry Andric return;
278044eb2f6SDimitry Andric }
279044eb2f6SDimitry Andric
280044eb2f6SDimitry Andric auto Iter = SC.checksums().getArray().at(Offset);
281044eb2f6SDimitry Andric if (Iter == SC.checksums().getArray().end()) {
282044eb2f6SDimitry Andric formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
283044eb2f6SDimitry Andric return;
284044eb2f6SDimitry Andric }
285044eb2f6SDimitry Andric
286044eb2f6SDimitry Andric uint32_t FO = Iter->FileNameOffset;
287044eb2f6SDimitry Andric auto ExpectedFile = getNameFromStringTable(FO);
288044eb2f6SDimitry Andric if (!ExpectedFile) {
289044eb2f6SDimitry Andric formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
290044eb2f6SDimitry Andric consumeError(ExpectedFile.takeError());
291044eb2f6SDimitry Andric return;
292044eb2f6SDimitry Andric }
293044eb2f6SDimitry Andric if (Iter->Kind == FileChecksumKind::None) {
294044eb2f6SDimitry Andric formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile);
295044eb2f6SDimitry Andric } else {
296044eb2f6SDimitry Andric formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile,
297044eb2f6SDimitry Andric formatChecksumKind(Iter->Kind), toHex(Iter->Checksum));
298044eb2f6SDimitry Andric }
299044eb2f6SDimitry Andric }
300044eb2f6SDimitry Andric
open(StringRef Path,bool AllowUnknownFile)301eb11fae6SDimitry Andric Expected<InputFile> InputFile::open(StringRef Path, bool AllowUnknownFile) {
302044eb2f6SDimitry Andric InputFile IF;
303044eb2f6SDimitry Andric if (!llvm::sys::fs::exists(Path))
304044eb2f6SDimitry Andric return make_error<StringError>(formatv("File {0} not found", Path),
305044eb2f6SDimitry Andric inconvertibleErrorCode());
306044eb2f6SDimitry Andric
307044eb2f6SDimitry Andric file_magic Magic;
308044eb2f6SDimitry Andric if (auto EC = identify_magic(Path, Magic))
309044eb2f6SDimitry Andric return make_error<StringError>(
310044eb2f6SDimitry Andric formatv("Unable to identify file type for file {0}", Path), EC);
311044eb2f6SDimitry Andric
312044eb2f6SDimitry Andric if (Magic == file_magic::coff_object) {
313044eb2f6SDimitry Andric Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Path);
314044eb2f6SDimitry Andric if (!BinaryOrErr)
315044eb2f6SDimitry Andric return BinaryOrErr.takeError();
316044eb2f6SDimitry Andric
317044eb2f6SDimitry Andric IF.CoffObject = std::move(*BinaryOrErr);
318044eb2f6SDimitry Andric IF.PdbOrObj = llvm::cast<COFFObjectFile>(IF.CoffObject.getBinary());
319044eb2f6SDimitry Andric return std::move(IF);
320044eb2f6SDimitry Andric }
321044eb2f6SDimitry Andric
322eb11fae6SDimitry Andric if (Magic == file_magic::pdb) {
323044eb2f6SDimitry Andric std::unique_ptr<IPDBSession> Session;
324044eb2f6SDimitry Andric if (auto Err = loadDataForPDB(PDB_ReaderType::Native, Path, Session))
325044eb2f6SDimitry Andric return std::move(Err);
326044eb2f6SDimitry Andric
327044eb2f6SDimitry Andric IF.PdbSession.reset(static_cast<NativeSession *>(Session.release()));
328044eb2f6SDimitry Andric IF.PdbOrObj = &IF.PdbSession->getPDBFile();
329044eb2f6SDimitry Andric
330044eb2f6SDimitry Andric return std::move(IF);
331044eb2f6SDimitry Andric }
332044eb2f6SDimitry Andric
333eb11fae6SDimitry Andric if (!AllowUnknownFile)
334044eb2f6SDimitry Andric return make_error<StringError>(
335044eb2f6SDimitry Andric formatv("File {0} is not a supported file type", Path),
336044eb2f6SDimitry Andric inconvertibleErrorCode());
337eb11fae6SDimitry Andric
338344a3780SDimitry Andric auto Result = MemoryBuffer::getFile(Path, /*IsText=*/false,
339344a3780SDimitry Andric /*RequiresNullTerminator=*/false);
340eb11fae6SDimitry Andric if (!Result)
341eb11fae6SDimitry Andric return make_error<StringError>(
342eb11fae6SDimitry Andric formatv("File {0} could not be opened", Path), Result.getError());
343eb11fae6SDimitry Andric
344eb11fae6SDimitry Andric IF.UnknownFile = std::move(*Result);
345eb11fae6SDimitry Andric IF.PdbOrObj = IF.UnknownFile.get();
346eb11fae6SDimitry Andric return std::move(IF);
347044eb2f6SDimitry Andric }
348044eb2f6SDimitry Andric
pdb()349044eb2f6SDimitry Andric PDBFile &InputFile::pdb() {
350044eb2f6SDimitry Andric assert(isPdb());
3517fa27ce4SDimitry Andric return *cast<PDBFile *>(PdbOrObj);
352044eb2f6SDimitry Andric }
353044eb2f6SDimitry Andric
pdb() const354044eb2f6SDimitry Andric const PDBFile &InputFile::pdb() const {
355044eb2f6SDimitry Andric assert(isPdb());
3567fa27ce4SDimitry Andric return *cast<PDBFile *>(PdbOrObj);
357044eb2f6SDimitry Andric }
358044eb2f6SDimitry Andric
obj()359044eb2f6SDimitry Andric object::COFFObjectFile &InputFile::obj() {
360044eb2f6SDimitry Andric assert(isObj());
3617fa27ce4SDimitry Andric return *cast<object::COFFObjectFile *>(PdbOrObj);
362044eb2f6SDimitry Andric }
363044eb2f6SDimitry Andric
obj() const364044eb2f6SDimitry Andric const object::COFFObjectFile &InputFile::obj() const {
365044eb2f6SDimitry Andric assert(isObj());
3667fa27ce4SDimitry Andric return *cast<object::COFFObjectFile *>(PdbOrObj);
367044eb2f6SDimitry Andric }
368044eb2f6SDimitry Andric
unknown()369eb11fae6SDimitry Andric MemoryBuffer &InputFile::unknown() {
370eb11fae6SDimitry Andric assert(isUnknown());
3717fa27ce4SDimitry Andric return *cast<MemoryBuffer *>(PdbOrObj);
372eb11fae6SDimitry Andric }
373eb11fae6SDimitry Andric
unknown() const374eb11fae6SDimitry Andric const MemoryBuffer &InputFile::unknown() const {
375eb11fae6SDimitry Andric assert(isUnknown());
3767fa27ce4SDimitry Andric return *cast<MemoryBuffer *>(PdbOrObj);
377eb11fae6SDimitry Andric }
378eb11fae6SDimitry Andric
getFilePath() const379eb11fae6SDimitry Andric StringRef InputFile::getFilePath() const {
380eb11fae6SDimitry Andric if (isPdb())
381eb11fae6SDimitry Andric return pdb().getFilePath();
382eb11fae6SDimitry Andric if (isObj())
383eb11fae6SDimitry Andric return obj().getFileName();
384eb11fae6SDimitry Andric assert(isUnknown());
385eb11fae6SDimitry Andric return unknown().getBufferIdentifier();
386eb11fae6SDimitry Andric }
387eb11fae6SDimitry Andric
hasTypes() const388044eb2f6SDimitry Andric bool InputFile::hasTypes() const {
389044eb2f6SDimitry Andric if (isPdb())
390044eb2f6SDimitry Andric return pdb().hasPDBTpiStream();
391044eb2f6SDimitry Andric
392044eb2f6SDimitry Andric for (const auto &Section : obj().sections()) {
393044eb2f6SDimitry Andric CVTypeArray Types;
394044eb2f6SDimitry Andric if (isDebugTSection(Section, Types))
395044eb2f6SDimitry Andric return true;
396044eb2f6SDimitry Andric }
397044eb2f6SDimitry Andric return false;
398044eb2f6SDimitry Andric }
399044eb2f6SDimitry Andric
hasIds() const400044eb2f6SDimitry Andric bool InputFile::hasIds() const {
401044eb2f6SDimitry Andric if (isObj())
402044eb2f6SDimitry Andric return false;
403044eb2f6SDimitry Andric return pdb().hasPDBIpiStream();
404044eb2f6SDimitry Andric }
405044eb2f6SDimitry Andric
isPdb() const4067fa27ce4SDimitry Andric bool InputFile::isPdb() const { return isa<PDBFile *>(PdbOrObj); }
407044eb2f6SDimitry Andric
isObj() const408044eb2f6SDimitry Andric bool InputFile::isObj() const {
4097fa27ce4SDimitry Andric return isa<object::COFFObjectFile *>(PdbOrObj);
410044eb2f6SDimitry Andric }
411044eb2f6SDimitry Andric
isUnknown() const4127fa27ce4SDimitry Andric bool InputFile::isUnknown() const { return isa<MemoryBuffer *>(PdbOrObj); }
413eb11fae6SDimitry Andric
414044eb2f6SDimitry Andric codeview::LazyRandomTypeCollection &
getOrCreateTypeCollection(TypeCollectionKind Kind)415044eb2f6SDimitry Andric InputFile::getOrCreateTypeCollection(TypeCollectionKind Kind) {
416044eb2f6SDimitry Andric if (Types && Kind == kTypes)
417044eb2f6SDimitry Andric return *Types;
418044eb2f6SDimitry Andric if (Ids && Kind == kIds)
419044eb2f6SDimitry Andric return *Ids;
420044eb2f6SDimitry Andric
421044eb2f6SDimitry Andric if (Kind == kIds) {
422044eb2f6SDimitry Andric assert(isPdb() && pdb().hasPDBIpiStream());
423044eb2f6SDimitry Andric }
424044eb2f6SDimitry Andric
425044eb2f6SDimitry Andric // If the collection was already initialized, we should have just returned it
426044eb2f6SDimitry Andric // in step 1.
427044eb2f6SDimitry Andric if (isPdb()) {
428044eb2f6SDimitry Andric TypeCollectionPtr &Collection = (Kind == kIds) ? Ids : Types;
429044eb2f6SDimitry Andric auto &Stream = cantFail((Kind == kIds) ? pdb().getPDBIpiStream()
430044eb2f6SDimitry Andric : pdb().getPDBTpiStream());
431044eb2f6SDimitry Andric
432044eb2f6SDimitry Andric auto &Array = Stream.typeArray();
433044eb2f6SDimitry Andric uint32_t Count = Stream.getNumTypeRecords();
434044eb2f6SDimitry Andric auto Offsets = Stream.getTypeIndexOffsets();
435044eb2f6SDimitry Andric Collection =
4361d5ae102SDimitry Andric std::make_unique<LazyRandomTypeCollection>(Array, Count, Offsets);
437044eb2f6SDimitry Andric return *Collection;
438044eb2f6SDimitry Andric }
439044eb2f6SDimitry Andric
440044eb2f6SDimitry Andric assert(isObj());
441044eb2f6SDimitry Andric assert(Kind == kTypes);
442044eb2f6SDimitry Andric assert(!Types);
443044eb2f6SDimitry Andric
444044eb2f6SDimitry Andric for (const auto &Section : obj().sections()) {
445044eb2f6SDimitry Andric CVTypeArray Records;
446044eb2f6SDimitry Andric if (!isDebugTSection(Section, Records))
447044eb2f6SDimitry Andric continue;
448044eb2f6SDimitry Andric
4491d5ae102SDimitry Andric Types = std::make_unique<LazyRandomTypeCollection>(Records, 100);
450044eb2f6SDimitry Andric return *Types;
451044eb2f6SDimitry Andric }
452044eb2f6SDimitry Andric
4531d5ae102SDimitry Andric Types = std::make_unique<LazyRandomTypeCollection>(100);
454044eb2f6SDimitry Andric return *Types;
455044eb2f6SDimitry Andric }
456044eb2f6SDimitry Andric
types()457044eb2f6SDimitry Andric codeview::LazyRandomTypeCollection &InputFile::types() {
458044eb2f6SDimitry Andric return getOrCreateTypeCollection(kTypes);
459044eb2f6SDimitry Andric }
460044eb2f6SDimitry Andric
ids()461044eb2f6SDimitry Andric codeview::LazyRandomTypeCollection &InputFile::ids() {
462044eb2f6SDimitry Andric // Object files have only one type stream that contains both types and ids.
463044eb2f6SDimitry Andric // Similarly, some PDBs don't contain an IPI stream, and for those both types
464044eb2f6SDimitry Andric // and IDs are in the same stream.
465044eb2f6SDimitry Andric if (isObj() || !pdb().hasPDBIpiStream())
466044eb2f6SDimitry Andric return types();
467044eb2f6SDimitry Andric
468044eb2f6SDimitry Andric return getOrCreateTypeCollection(kIds);
469044eb2f6SDimitry Andric }
470044eb2f6SDimitry Andric
symbol_groups()471044eb2f6SDimitry Andric iterator_range<SymbolGroupIterator> InputFile::symbol_groups() {
472044eb2f6SDimitry Andric return make_range<SymbolGroupIterator>(symbol_groups_begin(),
473044eb2f6SDimitry Andric symbol_groups_end());
474044eb2f6SDimitry Andric }
475044eb2f6SDimitry Andric
symbol_groups_begin()476044eb2f6SDimitry Andric SymbolGroupIterator InputFile::symbol_groups_begin() {
477044eb2f6SDimitry Andric return SymbolGroupIterator(*this);
478044eb2f6SDimitry Andric }
479044eb2f6SDimitry Andric
symbol_groups_end()480044eb2f6SDimitry Andric SymbolGroupIterator InputFile::symbol_groups_end() {
481044eb2f6SDimitry Andric return SymbolGroupIterator();
482044eb2f6SDimitry Andric }
483044eb2f6SDimitry Andric
SymbolGroupIterator()484044eb2f6SDimitry Andric SymbolGroupIterator::SymbolGroupIterator() : Value(nullptr) {}
485044eb2f6SDimitry Andric
SymbolGroupIterator(InputFile & File)486044eb2f6SDimitry Andric SymbolGroupIterator::SymbolGroupIterator(InputFile &File) : Value(&File) {
487044eb2f6SDimitry Andric if (File.isObj()) {
488044eb2f6SDimitry Andric SectionIter = File.obj().section_begin();
489044eb2f6SDimitry Andric scanToNextDebugS();
490044eb2f6SDimitry Andric }
491044eb2f6SDimitry Andric }
492044eb2f6SDimitry Andric
operator ==(const SymbolGroupIterator & R) const493044eb2f6SDimitry Andric bool SymbolGroupIterator::operator==(const SymbolGroupIterator &R) const {
494044eb2f6SDimitry Andric bool E = isEnd();
495044eb2f6SDimitry Andric bool RE = R.isEnd();
496044eb2f6SDimitry Andric if (E || RE)
497044eb2f6SDimitry Andric return E == RE;
498044eb2f6SDimitry Andric
499044eb2f6SDimitry Andric if (Value.File != R.Value.File)
500044eb2f6SDimitry Andric return false;
501044eb2f6SDimitry Andric return Index == R.Index;
502044eb2f6SDimitry Andric }
503044eb2f6SDimitry Andric
operator *() const504044eb2f6SDimitry Andric const SymbolGroup &SymbolGroupIterator::operator*() const {
505044eb2f6SDimitry Andric assert(!isEnd());
506044eb2f6SDimitry Andric return Value;
507044eb2f6SDimitry Andric }
operator *()508044eb2f6SDimitry Andric SymbolGroup &SymbolGroupIterator::operator*() {
509044eb2f6SDimitry Andric assert(!isEnd());
510044eb2f6SDimitry Andric return Value;
511044eb2f6SDimitry Andric }
512044eb2f6SDimitry Andric
operator ++()513044eb2f6SDimitry Andric SymbolGroupIterator &SymbolGroupIterator::operator++() {
514044eb2f6SDimitry Andric assert(Value.File && !isEnd());
515044eb2f6SDimitry Andric ++Index;
516044eb2f6SDimitry Andric if (isEnd())
517044eb2f6SDimitry Andric return *this;
518044eb2f6SDimitry Andric
519044eb2f6SDimitry Andric if (Value.File->isPdb()) {
520044eb2f6SDimitry Andric Value.updatePdbModi(Index);
521044eb2f6SDimitry Andric return *this;
522044eb2f6SDimitry Andric }
523044eb2f6SDimitry Andric
524044eb2f6SDimitry Andric scanToNextDebugS();
525044eb2f6SDimitry Andric return *this;
526044eb2f6SDimitry Andric }
527044eb2f6SDimitry Andric
scanToNextDebugS()528044eb2f6SDimitry Andric void SymbolGroupIterator::scanToNextDebugS() {
529145449b1SDimitry Andric assert(SectionIter);
530044eb2f6SDimitry Andric auto End = Value.File->obj().section_end();
531044eb2f6SDimitry Andric auto &Iter = *SectionIter;
532044eb2f6SDimitry Andric assert(!isEnd());
533044eb2f6SDimitry Andric
534044eb2f6SDimitry Andric while (++Iter != End) {
535044eb2f6SDimitry Andric DebugSubsectionArray SS;
536044eb2f6SDimitry Andric SectionRef SR = *Iter;
537044eb2f6SDimitry Andric if (!isDebugSSection(SR, SS))
538044eb2f6SDimitry Andric continue;
539044eb2f6SDimitry Andric
540044eb2f6SDimitry Andric Value.updateDebugS(SS);
541044eb2f6SDimitry Andric return;
542044eb2f6SDimitry Andric }
543044eb2f6SDimitry Andric }
544044eb2f6SDimitry Andric
isEnd() const545044eb2f6SDimitry Andric bool SymbolGroupIterator::isEnd() const {
546044eb2f6SDimitry Andric if (!Value.File)
547044eb2f6SDimitry Andric return true;
548044eb2f6SDimitry Andric if (Value.File->isPdb()) {
549145449b1SDimitry Andric DbiStream &Dbi = cantFail(Value.File->pdb().getPDBDbiStream());
550044eb2f6SDimitry Andric uint32_t Count = Dbi.modules().getModuleCount();
551044eb2f6SDimitry Andric assert(Index <= Count);
552044eb2f6SDimitry Andric return Index == Count;
553044eb2f6SDimitry Andric }
554044eb2f6SDimitry Andric
555145449b1SDimitry Andric assert(SectionIter);
556044eb2f6SDimitry Andric return *SectionIter == Value.File->obj().section_end();
557044eb2f6SDimitry Andric }
558145449b1SDimitry Andric
isMyCode(const SymbolGroup & Group)559145449b1SDimitry Andric static bool isMyCode(const SymbolGroup &Group) {
560145449b1SDimitry Andric if (Group.getFile().isObj())
561145449b1SDimitry Andric return true;
562145449b1SDimitry Andric
563145449b1SDimitry Andric StringRef Name = Group.name();
564b1c73532SDimitry Andric if (Name.starts_with("Import:"))
565145449b1SDimitry Andric return false;
5667fa27ce4SDimitry Andric if (Name.ends_with_insensitive(".dll"))
567145449b1SDimitry Andric return false;
568145449b1SDimitry Andric if (Name.equals_insensitive("* linker *"))
569145449b1SDimitry Andric return false;
5707fa27ce4SDimitry Andric if (Name.starts_with_insensitive("f:\\binaries\\Intermediate\\vctools"))
571145449b1SDimitry Andric return false;
5727fa27ce4SDimitry Andric if (Name.starts_with_insensitive("f:\\dd\\vctools\\crt"))
573145449b1SDimitry Andric return false;
574145449b1SDimitry Andric return true;
575145449b1SDimitry Andric }
576145449b1SDimitry Andric
shouldDumpSymbolGroup(uint32_t Idx,const SymbolGroup & Group,const FilterOptions & Filters)577145449b1SDimitry Andric bool llvm::pdb::shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group,
578145449b1SDimitry Andric const FilterOptions &Filters) {
579145449b1SDimitry Andric if (Filters.JustMyCode && !isMyCode(Group))
580145449b1SDimitry Andric return false;
581145449b1SDimitry Andric
582145449b1SDimitry Andric // If the arg was not specified on the command line, always dump all modules.
583145449b1SDimitry Andric if (!Filters.DumpModi)
584145449b1SDimitry Andric return true;
585145449b1SDimitry Andric
586145449b1SDimitry Andric // Otherwise, only dump if this is the same module specified.
587145449b1SDimitry Andric return (Filters.DumpModi == Idx);
588145449b1SDimitry Andric }
589