181ad6265SDimitry Andric //===- InputFile.cpp ------------------------------------------ *- C++ --*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InputFile.h" 1081ad6265SDimitry Andric 1106c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 1281ad6265SDimitry Andric #include "llvm/BinaryFormat/Magic.h" 1381ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h" 1481ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 1581ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" 1681ad6265SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 1781ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 1881ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/FormatUtil.h" 1981ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/LinePrinter.h" 2081ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeSession.h" 2181ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 2281ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" 2381ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h" 2481ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 2581ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/PDB.h" 2681ad6265SDimitry Andric #include "llvm/Object/COFF.h" 2781ad6265SDimitry Andric #include "llvm/Support/FileSystem.h" 2881ad6265SDimitry Andric #include "llvm/Support/FormatVariadic.h" 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric using namespace llvm; 3181ad6265SDimitry Andric using namespace llvm::codeview; 3281ad6265SDimitry Andric using namespace llvm::object; 3381ad6265SDimitry Andric using namespace llvm::pdb; 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric InputFile::InputFile() = default; 3681ad6265SDimitry Andric InputFile::~InputFile() = default; 3781ad6265SDimitry Andric 3881ad6265SDimitry Andric Expected<ModuleDebugStreamRef> 3981ad6265SDimitry Andric llvm::pdb::getModuleDebugStream(PDBFile &File, StringRef &ModuleName, 4081ad6265SDimitry Andric uint32_t Index) { 4181ad6265SDimitry Andric Expected<DbiStream &> DbiOrErr = File.getPDBDbiStream(); 4281ad6265SDimitry Andric if (!DbiOrErr) 4381ad6265SDimitry Andric return DbiOrErr.takeError(); 4481ad6265SDimitry Andric DbiStream &Dbi = *DbiOrErr; 4581ad6265SDimitry Andric const auto &Modules = Dbi.modules(); 4681ad6265SDimitry Andric if (Index >= Modules.getModuleCount()) 4781ad6265SDimitry Andric return make_error<RawError>(raw_error_code::index_out_of_bounds, 4881ad6265SDimitry Andric "Invalid module index"); 4981ad6265SDimitry Andric 5081ad6265SDimitry Andric auto Modi = Modules.getModuleDescriptor(Index); 5181ad6265SDimitry Andric 5281ad6265SDimitry Andric ModuleName = Modi.getModuleName(); 5381ad6265SDimitry Andric 5481ad6265SDimitry Andric uint16_t ModiStream = Modi.getModuleStreamIndex(); 5581ad6265SDimitry Andric if (ModiStream == kInvalidStreamIndex) 5681ad6265SDimitry Andric return make_error<RawError>(raw_error_code::no_stream, 5781ad6265SDimitry Andric "Module stream not present"); 5881ad6265SDimitry Andric 5981ad6265SDimitry Andric auto ModStreamData = File.createIndexedStream(ModiStream); 6081ad6265SDimitry Andric 6181ad6265SDimitry Andric ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); 6281ad6265SDimitry Andric if (auto EC = ModS.reload()) 6381ad6265SDimitry Andric return make_error<RawError>(raw_error_code::corrupt_file, 6481ad6265SDimitry Andric "Invalid module stream"); 6581ad6265SDimitry Andric 6681ad6265SDimitry Andric return std::move(ModS); 6781ad6265SDimitry Andric } 6881ad6265SDimitry Andric 6981ad6265SDimitry Andric Expected<ModuleDebugStreamRef> llvm::pdb::getModuleDebugStream(PDBFile &File, 7081ad6265SDimitry Andric uint32_t Index) { 7181ad6265SDimitry Andric Expected<DbiStream &> DbiOrErr = File.getPDBDbiStream(); 7281ad6265SDimitry Andric if (!DbiOrErr) 7381ad6265SDimitry Andric return DbiOrErr.takeError(); 7481ad6265SDimitry Andric DbiStream &Dbi = *DbiOrErr; 7581ad6265SDimitry Andric const auto &Modules = Dbi.modules(); 7681ad6265SDimitry Andric auto Modi = Modules.getModuleDescriptor(Index); 7781ad6265SDimitry Andric 7881ad6265SDimitry Andric uint16_t ModiStream = Modi.getModuleStreamIndex(); 7981ad6265SDimitry Andric if (ModiStream == kInvalidStreamIndex) 8081ad6265SDimitry Andric return make_error<RawError>(raw_error_code::no_stream, 8181ad6265SDimitry Andric "Module stream not present"); 8281ad6265SDimitry Andric 8381ad6265SDimitry Andric auto ModStreamData = File.createIndexedStream(ModiStream); 8481ad6265SDimitry Andric 8581ad6265SDimitry Andric ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); 8681ad6265SDimitry Andric if (Error Err = ModS.reload()) 8781ad6265SDimitry Andric return make_error<RawError>(raw_error_code::corrupt_file, 8881ad6265SDimitry Andric "Invalid module stream"); 8981ad6265SDimitry Andric 9081ad6265SDimitry Andric return std::move(ModS); 9181ad6265SDimitry Andric } 9281ad6265SDimitry Andric 9381ad6265SDimitry Andric static inline bool isCodeViewDebugSubsection(object::SectionRef Section, 9481ad6265SDimitry Andric StringRef Name, 9581ad6265SDimitry Andric BinaryStreamReader &Reader) { 9681ad6265SDimitry Andric if (Expected<StringRef> NameOrErr = Section.getName()) { 9781ad6265SDimitry Andric if (*NameOrErr != Name) 9881ad6265SDimitry Andric return false; 9981ad6265SDimitry Andric } else { 10081ad6265SDimitry Andric consumeError(NameOrErr.takeError()); 10181ad6265SDimitry Andric return false; 10281ad6265SDimitry Andric } 10381ad6265SDimitry Andric 10481ad6265SDimitry Andric Expected<StringRef> ContentsOrErr = Section.getContents(); 10581ad6265SDimitry Andric if (!ContentsOrErr) { 10681ad6265SDimitry Andric consumeError(ContentsOrErr.takeError()); 10781ad6265SDimitry Andric return false; 10881ad6265SDimitry Andric } 10981ad6265SDimitry Andric 110*5f757f3fSDimitry Andric Reader = BinaryStreamReader(*ContentsOrErr, llvm::endianness::little); 11181ad6265SDimitry Andric uint32_t Magic; 11281ad6265SDimitry Andric if (Reader.bytesRemaining() < sizeof(uint32_t)) 11381ad6265SDimitry Andric return false; 11481ad6265SDimitry Andric cantFail(Reader.readInteger(Magic)); 11581ad6265SDimitry Andric if (Magic != COFF::DEBUG_SECTION_MAGIC) 11681ad6265SDimitry Andric return false; 11781ad6265SDimitry Andric return true; 11881ad6265SDimitry Andric } 11981ad6265SDimitry Andric 12081ad6265SDimitry Andric static inline bool isDebugSSection(object::SectionRef Section, 12181ad6265SDimitry Andric DebugSubsectionArray &Subsections) { 12281ad6265SDimitry Andric BinaryStreamReader Reader; 12381ad6265SDimitry Andric if (!isCodeViewDebugSubsection(Section, ".debug$S", Reader)) 12481ad6265SDimitry Andric return false; 12581ad6265SDimitry Andric 12681ad6265SDimitry Andric cantFail(Reader.readArray(Subsections, Reader.bytesRemaining())); 12781ad6265SDimitry Andric return true; 12881ad6265SDimitry Andric } 12981ad6265SDimitry Andric 13081ad6265SDimitry Andric static bool isDebugTSection(SectionRef Section, CVTypeArray &Types) { 13181ad6265SDimitry Andric BinaryStreamReader Reader; 13281ad6265SDimitry Andric if (!isCodeViewDebugSubsection(Section, ".debug$T", Reader) && 13381ad6265SDimitry Andric !isCodeViewDebugSubsection(Section, ".debug$P", Reader)) 13481ad6265SDimitry Andric return false; 13581ad6265SDimitry Andric cantFail(Reader.readArray(Types, Reader.bytesRemaining())); 13681ad6265SDimitry Andric return true; 13781ad6265SDimitry Andric } 13881ad6265SDimitry Andric 13981ad6265SDimitry Andric static std::string formatChecksumKind(FileChecksumKind Kind) { 14081ad6265SDimitry Andric switch (Kind) { 14181ad6265SDimitry Andric RETURN_CASE(FileChecksumKind, None, "None"); 14281ad6265SDimitry Andric RETURN_CASE(FileChecksumKind, MD5, "MD5"); 14381ad6265SDimitry Andric RETURN_CASE(FileChecksumKind, SHA1, "SHA-1"); 14481ad6265SDimitry Andric RETURN_CASE(FileChecksumKind, SHA256, "SHA-256"); 14581ad6265SDimitry Andric } 14681ad6265SDimitry Andric return formatUnknownEnum(Kind); 14781ad6265SDimitry Andric } 14881ad6265SDimitry Andric 14981ad6265SDimitry Andric template <typename... Args> 15081ad6265SDimitry Andric static void formatInternal(LinePrinter &Printer, bool Append, Args &&...args) { 15181ad6265SDimitry Andric if (Append) 15281ad6265SDimitry Andric Printer.format(std::forward<Args>(args)...); 15381ad6265SDimitry Andric else 15481ad6265SDimitry Andric Printer.formatLine(std::forward<Args>(args)...); 15581ad6265SDimitry Andric } 15681ad6265SDimitry Andric 15781ad6265SDimitry Andric SymbolGroup::SymbolGroup(InputFile *File, uint32_t GroupIndex) : File(File) { 15881ad6265SDimitry Andric if (!File) 15981ad6265SDimitry Andric return; 16081ad6265SDimitry Andric 16181ad6265SDimitry Andric if (File->isPdb()) 16281ad6265SDimitry Andric initializeForPdb(GroupIndex); 16381ad6265SDimitry Andric else { 16481ad6265SDimitry Andric Name = ".debug$S"; 16581ad6265SDimitry Andric uint32_t I = 0; 16681ad6265SDimitry Andric for (const auto &S : File->obj().sections()) { 16781ad6265SDimitry Andric DebugSubsectionArray SS; 16881ad6265SDimitry Andric if (!isDebugSSection(S, SS)) 16981ad6265SDimitry Andric continue; 17081ad6265SDimitry Andric 17181ad6265SDimitry Andric if (!SC.hasChecksums() || !SC.hasStrings()) 17281ad6265SDimitry Andric SC.initialize(SS); 17381ad6265SDimitry Andric 17481ad6265SDimitry Andric if (I == GroupIndex) 17581ad6265SDimitry Andric Subsections = SS; 17681ad6265SDimitry Andric 17781ad6265SDimitry Andric if (SC.hasChecksums() && SC.hasStrings()) 17881ad6265SDimitry Andric break; 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric rebuildChecksumMap(); 18181ad6265SDimitry Andric } 18281ad6265SDimitry Andric } 18381ad6265SDimitry Andric 18481ad6265SDimitry Andric StringRef SymbolGroup::name() const { return Name; } 18581ad6265SDimitry Andric 18681ad6265SDimitry Andric void SymbolGroup::updateDebugS(const codeview::DebugSubsectionArray &SS) { 18781ad6265SDimitry Andric Subsections = SS; 18881ad6265SDimitry Andric } 18981ad6265SDimitry Andric 19081ad6265SDimitry Andric void SymbolGroup::updatePdbModi(uint32_t Modi) { initializeForPdb(Modi); } 19181ad6265SDimitry Andric 19281ad6265SDimitry Andric void SymbolGroup::initializeForPdb(uint32_t Modi) { 19381ad6265SDimitry Andric assert(File && File->isPdb()); 19481ad6265SDimitry Andric 19581ad6265SDimitry Andric // PDB always uses the same string table, but each module has its own 19681ad6265SDimitry Andric // checksums. So we only set the strings if they're not already set. 19781ad6265SDimitry Andric if (!SC.hasStrings()) { 19881ad6265SDimitry Andric auto StringTable = File->pdb().getStringTable(); 19981ad6265SDimitry Andric if (StringTable) 20081ad6265SDimitry Andric SC.setStrings(StringTable->getStringTable()); 20181ad6265SDimitry Andric else 20281ad6265SDimitry Andric consumeError(StringTable.takeError()); 20381ad6265SDimitry Andric } 20481ad6265SDimitry Andric 20581ad6265SDimitry Andric SC.resetChecksums(); 20681ad6265SDimitry Andric auto MDS = getModuleDebugStream(File->pdb(), Name, Modi); 20781ad6265SDimitry Andric if (!MDS) { 20881ad6265SDimitry Andric consumeError(MDS.takeError()); 20981ad6265SDimitry Andric return; 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric 21281ad6265SDimitry Andric DebugStream = std::make_shared<ModuleDebugStreamRef>(std::move(*MDS)); 21381ad6265SDimitry Andric Subsections = DebugStream->getSubsectionsArray(); 21481ad6265SDimitry Andric SC.initialize(Subsections); 21581ad6265SDimitry Andric rebuildChecksumMap(); 21681ad6265SDimitry Andric } 21781ad6265SDimitry Andric 21881ad6265SDimitry Andric void SymbolGroup::rebuildChecksumMap() { 21981ad6265SDimitry Andric if (!SC.hasChecksums()) 22081ad6265SDimitry Andric return; 22181ad6265SDimitry Andric 22281ad6265SDimitry Andric for (const auto &Entry : SC.checksums()) { 22381ad6265SDimitry Andric auto S = SC.strings().getString(Entry.FileNameOffset); 22481ad6265SDimitry Andric if (!S) 22581ad6265SDimitry Andric continue; 22681ad6265SDimitry Andric ChecksumsByFile[*S] = Entry; 22781ad6265SDimitry Andric } 22881ad6265SDimitry Andric } 22981ad6265SDimitry Andric 23081ad6265SDimitry Andric const ModuleDebugStreamRef &SymbolGroup::getPdbModuleStream() const { 23181ad6265SDimitry Andric assert(File && File->isPdb() && DebugStream); 23281ad6265SDimitry Andric return *DebugStream; 23381ad6265SDimitry Andric } 23481ad6265SDimitry Andric 23581ad6265SDimitry Andric Expected<StringRef> SymbolGroup::getNameFromStringTable(uint32_t Offset) const { 23681ad6265SDimitry Andric return SC.strings().getString(Offset); 23781ad6265SDimitry Andric } 23881ad6265SDimitry Andric 23981ad6265SDimitry Andric Expected<StringRef> SymbolGroup::getNameFromChecksums(uint32_t Offset) const { 24081ad6265SDimitry Andric StringRef Name; 24181ad6265SDimitry Andric if (!SC.hasChecksums()) { 24281ad6265SDimitry Andric return std::move(Name); 24381ad6265SDimitry Andric } 24481ad6265SDimitry Andric 24581ad6265SDimitry Andric auto Iter = SC.checksums().getArray().at(Offset); 24681ad6265SDimitry Andric if (Iter == SC.checksums().getArray().end()) { 24781ad6265SDimitry Andric return std::move(Name); 24881ad6265SDimitry Andric } 24981ad6265SDimitry Andric 25081ad6265SDimitry Andric uint32_t FO = Iter->FileNameOffset; 25181ad6265SDimitry Andric auto ExpectedFile = getNameFromStringTable(FO); 25281ad6265SDimitry Andric if (!ExpectedFile) { 25381ad6265SDimitry Andric return std::move(Name); 25481ad6265SDimitry Andric } 25581ad6265SDimitry Andric 25681ad6265SDimitry Andric return *ExpectedFile; 25781ad6265SDimitry Andric } 25881ad6265SDimitry Andric 25981ad6265SDimitry Andric void SymbolGroup::formatFromFileName(LinePrinter &Printer, StringRef File, 26081ad6265SDimitry Andric bool Append) const { 26181ad6265SDimitry Andric auto FC = ChecksumsByFile.find(File); 26281ad6265SDimitry Andric if (FC == ChecksumsByFile.end()) { 26381ad6265SDimitry Andric formatInternal(Printer, Append, "- (no checksum) {0}", File); 26481ad6265SDimitry Andric return; 26581ad6265SDimitry Andric } 26681ad6265SDimitry Andric 26781ad6265SDimitry Andric formatInternal(Printer, Append, "- ({0}: {1}) {2}", 26881ad6265SDimitry Andric formatChecksumKind(FC->getValue().Kind), 26981ad6265SDimitry Andric toHex(FC->getValue().Checksum), File); 27081ad6265SDimitry Andric } 27181ad6265SDimitry Andric 27281ad6265SDimitry Andric void SymbolGroup::formatFromChecksumsOffset(LinePrinter &Printer, 27381ad6265SDimitry Andric uint32_t Offset, 27481ad6265SDimitry Andric bool Append) const { 27581ad6265SDimitry Andric if (!SC.hasChecksums()) { 27681ad6265SDimitry Andric formatInternal(Printer, Append, "(unknown file name offset {0})", Offset); 27781ad6265SDimitry Andric return; 27881ad6265SDimitry Andric } 27981ad6265SDimitry Andric 28081ad6265SDimitry Andric auto Iter = SC.checksums().getArray().at(Offset); 28181ad6265SDimitry Andric if (Iter == SC.checksums().getArray().end()) { 28281ad6265SDimitry Andric formatInternal(Printer, Append, "(unknown file name offset {0})", Offset); 28381ad6265SDimitry Andric return; 28481ad6265SDimitry Andric } 28581ad6265SDimitry Andric 28681ad6265SDimitry Andric uint32_t FO = Iter->FileNameOffset; 28781ad6265SDimitry Andric auto ExpectedFile = getNameFromStringTable(FO); 28881ad6265SDimitry Andric if (!ExpectedFile) { 28981ad6265SDimitry Andric formatInternal(Printer, Append, "(unknown file name offset {0})", Offset); 29081ad6265SDimitry Andric consumeError(ExpectedFile.takeError()); 29181ad6265SDimitry Andric return; 29281ad6265SDimitry Andric } 29381ad6265SDimitry Andric if (Iter->Kind == FileChecksumKind::None) { 29481ad6265SDimitry Andric formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile); 29581ad6265SDimitry Andric } else { 29681ad6265SDimitry Andric formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile, 29781ad6265SDimitry Andric formatChecksumKind(Iter->Kind), toHex(Iter->Checksum)); 29881ad6265SDimitry Andric } 29981ad6265SDimitry Andric } 30081ad6265SDimitry Andric 30181ad6265SDimitry Andric Expected<InputFile> InputFile::open(StringRef Path, bool AllowUnknownFile) { 30281ad6265SDimitry Andric InputFile IF; 30381ad6265SDimitry Andric if (!llvm::sys::fs::exists(Path)) 30481ad6265SDimitry Andric return make_error<StringError>(formatv("File {0} not found", Path), 30581ad6265SDimitry Andric inconvertibleErrorCode()); 30681ad6265SDimitry Andric 30781ad6265SDimitry Andric file_magic Magic; 30881ad6265SDimitry Andric if (auto EC = identify_magic(Path, Magic)) 30981ad6265SDimitry Andric return make_error<StringError>( 31081ad6265SDimitry Andric formatv("Unable to identify file type for file {0}", Path), EC); 31181ad6265SDimitry Andric 31281ad6265SDimitry Andric if (Magic == file_magic::coff_object) { 31381ad6265SDimitry Andric Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Path); 31481ad6265SDimitry Andric if (!BinaryOrErr) 31581ad6265SDimitry Andric return BinaryOrErr.takeError(); 31681ad6265SDimitry Andric 31781ad6265SDimitry Andric IF.CoffObject = std::move(*BinaryOrErr); 31881ad6265SDimitry Andric IF.PdbOrObj = llvm::cast<COFFObjectFile>(IF.CoffObject.getBinary()); 31981ad6265SDimitry Andric return std::move(IF); 32081ad6265SDimitry Andric } 32181ad6265SDimitry Andric 32281ad6265SDimitry Andric if (Magic == file_magic::pdb) { 32381ad6265SDimitry Andric std::unique_ptr<IPDBSession> Session; 32481ad6265SDimitry Andric if (auto Err = loadDataForPDB(PDB_ReaderType::Native, Path, Session)) 32581ad6265SDimitry Andric return std::move(Err); 32681ad6265SDimitry Andric 32781ad6265SDimitry Andric IF.PdbSession.reset(static_cast<NativeSession *>(Session.release())); 32881ad6265SDimitry Andric IF.PdbOrObj = &IF.PdbSession->getPDBFile(); 32981ad6265SDimitry Andric 33081ad6265SDimitry Andric return std::move(IF); 33181ad6265SDimitry Andric } 33281ad6265SDimitry Andric 33381ad6265SDimitry Andric if (!AllowUnknownFile) 33481ad6265SDimitry Andric return make_error<StringError>( 33581ad6265SDimitry Andric formatv("File {0} is not a supported file type", Path), 33681ad6265SDimitry Andric inconvertibleErrorCode()); 33781ad6265SDimitry Andric 33881ad6265SDimitry Andric auto Result = MemoryBuffer::getFile(Path, /*IsText=*/false, 33981ad6265SDimitry Andric /*RequiresNullTerminator=*/false); 34081ad6265SDimitry Andric if (!Result) 34181ad6265SDimitry Andric return make_error<StringError>( 34281ad6265SDimitry Andric formatv("File {0} could not be opened", Path), Result.getError()); 34381ad6265SDimitry Andric 34481ad6265SDimitry Andric IF.UnknownFile = std::move(*Result); 34581ad6265SDimitry Andric IF.PdbOrObj = IF.UnknownFile.get(); 34681ad6265SDimitry Andric return std::move(IF); 34781ad6265SDimitry Andric } 34881ad6265SDimitry Andric 34981ad6265SDimitry Andric PDBFile &InputFile::pdb() { 35081ad6265SDimitry Andric assert(isPdb()); 35106c3fb27SDimitry Andric return *cast<PDBFile *>(PdbOrObj); 35281ad6265SDimitry Andric } 35381ad6265SDimitry Andric 35481ad6265SDimitry Andric const PDBFile &InputFile::pdb() const { 35581ad6265SDimitry Andric assert(isPdb()); 35606c3fb27SDimitry Andric return *cast<PDBFile *>(PdbOrObj); 35781ad6265SDimitry Andric } 35881ad6265SDimitry Andric 35981ad6265SDimitry Andric object::COFFObjectFile &InputFile::obj() { 36081ad6265SDimitry Andric assert(isObj()); 36106c3fb27SDimitry Andric return *cast<object::COFFObjectFile *>(PdbOrObj); 36281ad6265SDimitry Andric } 36381ad6265SDimitry Andric 36481ad6265SDimitry Andric const object::COFFObjectFile &InputFile::obj() const { 36581ad6265SDimitry Andric assert(isObj()); 36606c3fb27SDimitry Andric return *cast<object::COFFObjectFile *>(PdbOrObj); 36781ad6265SDimitry Andric } 36881ad6265SDimitry Andric 36981ad6265SDimitry Andric MemoryBuffer &InputFile::unknown() { 37081ad6265SDimitry Andric assert(isUnknown()); 37106c3fb27SDimitry Andric return *cast<MemoryBuffer *>(PdbOrObj); 37281ad6265SDimitry Andric } 37381ad6265SDimitry Andric 37481ad6265SDimitry Andric const MemoryBuffer &InputFile::unknown() const { 37581ad6265SDimitry Andric assert(isUnknown()); 37606c3fb27SDimitry Andric return *cast<MemoryBuffer *>(PdbOrObj); 37781ad6265SDimitry Andric } 37881ad6265SDimitry Andric 37981ad6265SDimitry Andric StringRef InputFile::getFilePath() const { 38081ad6265SDimitry Andric if (isPdb()) 38181ad6265SDimitry Andric return pdb().getFilePath(); 38281ad6265SDimitry Andric if (isObj()) 38381ad6265SDimitry Andric return obj().getFileName(); 38481ad6265SDimitry Andric assert(isUnknown()); 38581ad6265SDimitry Andric return unknown().getBufferIdentifier(); 38681ad6265SDimitry Andric } 38781ad6265SDimitry Andric 38881ad6265SDimitry Andric bool InputFile::hasTypes() const { 38981ad6265SDimitry Andric if (isPdb()) 39081ad6265SDimitry Andric return pdb().hasPDBTpiStream(); 39181ad6265SDimitry Andric 39281ad6265SDimitry Andric for (const auto &Section : obj().sections()) { 39381ad6265SDimitry Andric CVTypeArray Types; 39481ad6265SDimitry Andric if (isDebugTSection(Section, Types)) 39581ad6265SDimitry Andric return true; 39681ad6265SDimitry Andric } 39781ad6265SDimitry Andric return false; 39881ad6265SDimitry Andric } 39981ad6265SDimitry Andric 40081ad6265SDimitry Andric bool InputFile::hasIds() const { 40181ad6265SDimitry Andric if (isObj()) 40281ad6265SDimitry Andric return false; 40381ad6265SDimitry Andric return pdb().hasPDBIpiStream(); 40481ad6265SDimitry Andric } 40581ad6265SDimitry Andric 40606c3fb27SDimitry Andric bool InputFile::isPdb() const { return isa<PDBFile *>(PdbOrObj); } 40781ad6265SDimitry Andric 40881ad6265SDimitry Andric bool InputFile::isObj() const { 40906c3fb27SDimitry Andric return isa<object::COFFObjectFile *>(PdbOrObj); 41081ad6265SDimitry Andric } 41181ad6265SDimitry Andric 41206c3fb27SDimitry Andric bool InputFile::isUnknown() const { return isa<MemoryBuffer *>(PdbOrObj); } 41381ad6265SDimitry Andric 41481ad6265SDimitry Andric codeview::LazyRandomTypeCollection & 41581ad6265SDimitry Andric InputFile::getOrCreateTypeCollection(TypeCollectionKind Kind) { 41681ad6265SDimitry Andric if (Types && Kind == kTypes) 41781ad6265SDimitry Andric return *Types; 41881ad6265SDimitry Andric if (Ids && Kind == kIds) 41981ad6265SDimitry Andric return *Ids; 42081ad6265SDimitry Andric 42181ad6265SDimitry Andric if (Kind == kIds) { 42281ad6265SDimitry Andric assert(isPdb() && pdb().hasPDBIpiStream()); 42381ad6265SDimitry Andric } 42481ad6265SDimitry Andric 42581ad6265SDimitry Andric // If the collection was already initialized, we should have just returned it 42681ad6265SDimitry Andric // in step 1. 42781ad6265SDimitry Andric if (isPdb()) { 42881ad6265SDimitry Andric TypeCollectionPtr &Collection = (Kind == kIds) ? Ids : Types; 42981ad6265SDimitry Andric auto &Stream = cantFail((Kind == kIds) ? pdb().getPDBIpiStream() 43081ad6265SDimitry Andric : pdb().getPDBTpiStream()); 43181ad6265SDimitry Andric 43281ad6265SDimitry Andric auto &Array = Stream.typeArray(); 43381ad6265SDimitry Andric uint32_t Count = Stream.getNumTypeRecords(); 43481ad6265SDimitry Andric auto Offsets = Stream.getTypeIndexOffsets(); 43581ad6265SDimitry Andric Collection = 43681ad6265SDimitry Andric std::make_unique<LazyRandomTypeCollection>(Array, Count, Offsets); 43781ad6265SDimitry Andric return *Collection; 43881ad6265SDimitry Andric } 43981ad6265SDimitry Andric 44081ad6265SDimitry Andric assert(isObj()); 44181ad6265SDimitry Andric assert(Kind == kTypes); 44281ad6265SDimitry Andric assert(!Types); 44381ad6265SDimitry Andric 44481ad6265SDimitry Andric for (const auto &Section : obj().sections()) { 44581ad6265SDimitry Andric CVTypeArray Records; 44681ad6265SDimitry Andric if (!isDebugTSection(Section, Records)) 44781ad6265SDimitry Andric continue; 44881ad6265SDimitry Andric 44981ad6265SDimitry Andric Types = std::make_unique<LazyRandomTypeCollection>(Records, 100); 45081ad6265SDimitry Andric return *Types; 45181ad6265SDimitry Andric } 45281ad6265SDimitry Andric 45381ad6265SDimitry Andric Types = std::make_unique<LazyRandomTypeCollection>(100); 45481ad6265SDimitry Andric return *Types; 45581ad6265SDimitry Andric } 45681ad6265SDimitry Andric 45781ad6265SDimitry Andric codeview::LazyRandomTypeCollection &InputFile::types() { 45881ad6265SDimitry Andric return getOrCreateTypeCollection(kTypes); 45981ad6265SDimitry Andric } 46081ad6265SDimitry Andric 46181ad6265SDimitry Andric codeview::LazyRandomTypeCollection &InputFile::ids() { 46281ad6265SDimitry Andric // Object files have only one type stream that contains both types and ids. 46381ad6265SDimitry Andric // Similarly, some PDBs don't contain an IPI stream, and for those both types 46481ad6265SDimitry Andric // and IDs are in the same stream. 46581ad6265SDimitry Andric if (isObj() || !pdb().hasPDBIpiStream()) 46681ad6265SDimitry Andric return types(); 46781ad6265SDimitry Andric 46881ad6265SDimitry Andric return getOrCreateTypeCollection(kIds); 46981ad6265SDimitry Andric } 47081ad6265SDimitry Andric 47181ad6265SDimitry Andric iterator_range<SymbolGroupIterator> InputFile::symbol_groups() { 47281ad6265SDimitry Andric return make_range<SymbolGroupIterator>(symbol_groups_begin(), 47381ad6265SDimitry Andric symbol_groups_end()); 47481ad6265SDimitry Andric } 47581ad6265SDimitry Andric 47681ad6265SDimitry Andric SymbolGroupIterator InputFile::symbol_groups_begin() { 47781ad6265SDimitry Andric return SymbolGroupIterator(*this); 47881ad6265SDimitry Andric } 47981ad6265SDimitry Andric 48081ad6265SDimitry Andric SymbolGroupIterator InputFile::symbol_groups_end() { 48181ad6265SDimitry Andric return SymbolGroupIterator(); 48281ad6265SDimitry Andric } 48381ad6265SDimitry Andric 48481ad6265SDimitry Andric SymbolGroupIterator::SymbolGroupIterator() : Value(nullptr) {} 48581ad6265SDimitry Andric 48681ad6265SDimitry Andric SymbolGroupIterator::SymbolGroupIterator(InputFile &File) : Value(&File) { 48781ad6265SDimitry Andric if (File.isObj()) { 48881ad6265SDimitry Andric SectionIter = File.obj().section_begin(); 48981ad6265SDimitry Andric scanToNextDebugS(); 49081ad6265SDimitry Andric } 49181ad6265SDimitry Andric } 49281ad6265SDimitry Andric 49381ad6265SDimitry Andric bool SymbolGroupIterator::operator==(const SymbolGroupIterator &R) const { 49481ad6265SDimitry Andric bool E = isEnd(); 49581ad6265SDimitry Andric bool RE = R.isEnd(); 49681ad6265SDimitry Andric if (E || RE) 49781ad6265SDimitry Andric return E == RE; 49881ad6265SDimitry Andric 49981ad6265SDimitry Andric if (Value.File != R.Value.File) 50081ad6265SDimitry Andric return false; 50181ad6265SDimitry Andric return Index == R.Index; 50281ad6265SDimitry Andric } 50381ad6265SDimitry Andric 50481ad6265SDimitry Andric const SymbolGroup &SymbolGroupIterator::operator*() const { 50581ad6265SDimitry Andric assert(!isEnd()); 50681ad6265SDimitry Andric return Value; 50781ad6265SDimitry Andric } 50881ad6265SDimitry Andric SymbolGroup &SymbolGroupIterator::operator*() { 50981ad6265SDimitry Andric assert(!isEnd()); 51081ad6265SDimitry Andric return Value; 51181ad6265SDimitry Andric } 51281ad6265SDimitry Andric 51381ad6265SDimitry Andric SymbolGroupIterator &SymbolGroupIterator::operator++() { 51481ad6265SDimitry Andric assert(Value.File && !isEnd()); 51581ad6265SDimitry Andric ++Index; 51681ad6265SDimitry Andric if (isEnd()) 51781ad6265SDimitry Andric return *this; 51881ad6265SDimitry Andric 51981ad6265SDimitry Andric if (Value.File->isPdb()) { 52081ad6265SDimitry Andric Value.updatePdbModi(Index); 52181ad6265SDimitry Andric return *this; 52281ad6265SDimitry Andric } 52381ad6265SDimitry Andric 52481ad6265SDimitry Andric scanToNextDebugS(); 52581ad6265SDimitry Andric return *this; 52681ad6265SDimitry Andric } 52781ad6265SDimitry Andric 52881ad6265SDimitry Andric void SymbolGroupIterator::scanToNextDebugS() { 52981ad6265SDimitry Andric assert(SectionIter); 53081ad6265SDimitry Andric auto End = Value.File->obj().section_end(); 53181ad6265SDimitry Andric auto &Iter = *SectionIter; 53281ad6265SDimitry Andric assert(!isEnd()); 53381ad6265SDimitry Andric 53481ad6265SDimitry Andric while (++Iter != End) { 53581ad6265SDimitry Andric DebugSubsectionArray SS; 53681ad6265SDimitry Andric SectionRef SR = *Iter; 53781ad6265SDimitry Andric if (!isDebugSSection(SR, SS)) 53881ad6265SDimitry Andric continue; 53981ad6265SDimitry Andric 54081ad6265SDimitry Andric Value.updateDebugS(SS); 54181ad6265SDimitry Andric return; 54281ad6265SDimitry Andric } 54381ad6265SDimitry Andric } 54481ad6265SDimitry Andric 54581ad6265SDimitry Andric bool SymbolGroupIterator::isEnd() const { 54681ad6265SDimitry Andric if (!Value.File) 54781ad6265SDimitry Andric return true; 54881ad6265SDimitry Andric if (Value.File->isPdb()) { 54981ad6265SDimitry Andric DbiStream &Dbi = cantFail(Value.File->pdb().getPDBDbiStream()); 55081ad6265SDimitry Andric uint32_t Count = Dbi.modules().getModuleCount(); 55181ad6265SDimitry Andric assert(Index <= Count); 55281ad6265SDimitry Andric return Index == Count; 55381ad6265SDimitry Andric } 55481ad6265SDimitry Andric 55581ad6265SDimitry Andric assert(SectionIter); 55681ad6265SDimitry Andric return *SectionIter == Value.File->obj().section_end(); 55781ad6265SDimitry Andric } 55881ad6265SDimitry Andric 55981ad6265SDimitry Andric static bool isMyCode(const SymbolGroup &Group) { 56081ad6265SDimitry Andric if (Group.getFile().isObj()) 56181ad6265SDimitry Andric return true; 56281ad6265SDimitry Andric 56381ad6265SDimitry Andric StringRef Name = Group.name(); 564*5f757f3fSDimitry Andric if (Name.starts_with("Import:")) 56581ad6265SDimitry Andric return false; 56606c3fb27SDimitry Andric if (Name.ends_with_insensitive(".dll")) 56781ad6265SDimitry Andric return false; 56881ad6265SDimitry Andric if (Name.equals_insensitive("* linker *")) 56981ad6265SDimitry Andric return false; 57006c3fb27SDimitry Andric if (Name.starts_with_insensitive("f:\\binaries\\Intermediate\\vctools")) 57181ad6265SDimitry Andric return false; 57206c3fb27SDimitry Andric if (Name.starts_with_insensitive("f:\\dd\\vctools\\crt")) 57381ad6265SDimitry Andric return false; 57481ad6265SDimitry Andric return true; 57581ad6265SDimitry Andric } 57681ad6265SDimitry Andric 57781ad6265SDimitry Andric bool llvm::pdb::shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group, 57881ad6265SDimitry Andric const FilterOptions &Filters) { 57981ad6265SDimitry Andric if (Filters.JustMyCode && !isMyCode(Group)) 58081ad6265SDimitry Andric return false; 58181ad6265SDimitry Andric 58281ad6265SDimitry Andric // If the arg was not specified on the command line, always dump all modules. 58381ad6265SDimitry Andric if (!Filters.DumpModi) 58481ad6265SDimitry Andric return true; 58581ad6265SDimitry Andric 58681ad6265SDimitry Andric // Otherwise, only dump if this is the same module specified. 58781ad6265SDimitry Andric return (Filters.DumpModi == Idx); 58881ad6265SDimitry Andric } 589