Index: COFF/InputFiles.h =================================================================== --- COFF/InputFiles.h +++ COFF/InputFiles.h @@ -161,6 +161,22 @@ // Tells whether this file was compiled with /hotpatch bool HotPatchable = false; + enum TypeStreamKind { Regular, PCH, UsingPCH, UsingPDB }; + + // If the OBJ has a .debug$T stream, this tells which kind is it. + llvm::Optional DebugTypesKind; + + // The .debug$T stream if there's one. + llvm::Optional DebugTypes; + + // Information about dependent PDB, that needs to be loaded in before merging + // this OBJ. Only valid when DebugTypesKind is UsingPDB + llvm::Optional TypeServerDependency; + + // Information about dependent PCH, that needs to be loaded in before merging + // this OBJ. Only valid when DebugTypesKind is UsingPCH + llvm::Optional PrecompDependency; + private: const coff_section* getSection(uint32_t I); const coff_section *getSection(COFFSymbolRef Sym) { @@ -170,6 +186,7 @@ void initializeChunks(); void initializeSymbols(); void initializeFlags(); + void initializeDependencies(); SectionChunk * readSection(uint32_t SectionNumber, Index: COFF/InputFiles.cpp =================================================================== --- COFF/InputFiles.cpp +++ COFF/InputFiles.cpp @@ -22,6 +22,7 @@ #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Casting.h" @@ -129,6 +130,7 @@ initializeChunks(); initializeSymbols(); initializeFlags(); + initializeDependencies(); } const coff_section* ObjFile::getSection(uint32_t I) { @@ -656,6 +658,52 @@ } } +void ObjFile::initializeDependencies() { + if (!Config->Debug) + return; + + bool IsPCH = false; + + auto Data = getDebugSection(".debug$P"); + if (!Data.empty()) + IsPCH = true; + else + Data = getDebugSection(".debug$T"); + + if (Data.empty()) + return; + + CVTypeArray Types; + BinaryStreamReader Reader(Data, support::little); + cantFail(Reader.readArray(Types, Reader.getLength())); + + auto FirstType = Types.begin(); + if (FirstType == Types.end()) + return; + + DebugTypes.emplace(Types); + + if (IsPCH) { + DebugTypesKind.emplace(PCH); + return; + } + if (FirstType->kind() == LF_TYPESERVER2) { + TypeServerDependency.emplace( + cantFail(TypeDeserializer::deserializeAs( + FirstType->data()))); + DebugTypesKind.emplace(UsingPDB); + return; + } + if (FirstType->kind() == LF_PRECOMP) { + PrecompDependency.emplace( + cantFail(TypeDeserializer::deserializeAs( + FirstType->data()))); + DebugTypesKind.emplace(UsingPCH); + return; + } + DebugTypesKind.emplace(Regular); +} + StringRef ltrim1(StringRef S, const char *Chars) { if (!S.empty() && strchr(Chars, S[0])) return S.substr(1); Index: COFF/PDB.cpp =================================================================== --- COFF/PDB.cpp +++ COFF/PDB.cpp @@ -129,15 +129,13 @@ CVIndexMap *ObjectIndexMap); /// Reads and makes available a PDB. - Expected maybeMergeTypeServerPDB(ObjFile *File, - const CVType &FirstType); + Expected maybeMergeTypeServerPDB(ObjFile *File); /// Merges a precompiled headers TPI map into the current TPI map. The /// precompiled headers object will also be loaded and remapped in the /// process. Expected - mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType, - CVIndexMap *ObjectIndexMap); + mergeInPrecompHeaderObj(ObjFile *File, CVIndexMap *ObjectIndexMap); /// Reads and makes available a precompiled headers object. /// @@ -148,8 +146,7 @@ /// /// If the precompiled headers object was already loaded, this function will /// simply return its (remapped) TPI map. - Expected aquirePrecompObj(ObjFile *File, - PrecompRecord Precomp); + Expected aquirePrecompObj(ObjFile *File); /// Adds a precompiled headers object signature -> TPI mapping. std::pair @@ -362,21 +359,12 @@ PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap *ObjectIndexMap) { ScopedTimer T(TypeMergingTimer); - bool IsPrecompiledHeader = false; - - ArrayRef Data = File->getDebugSection(".debug$T"); - if (Data.empty()) { - // Try again, Microsoft precompiled headers use .debug$P instead of - // .debug$T - Data = File->getDebugSection(".debug$P"); - IsPrecompiledHeader = true; - } - if (Data.empty()) - return *ObjectIndexMap; // no debug info + if (!File->DebugTypesKind) + return *ObjectIndexMap; // no Types stream // Precompiled headers objects need to save the index map for further // reference by other objects which use the precompiled headers. - if (IsPrecompiledHeader) { + if (File->DebugTypesKind == ObjFile::PCH) { uint32_t PCHSignature = File->PCHSignature.getValueOr(0); if (PCHSignature == 0) fatal("No signature found for the precompiled headers OBJ (" + @@ -398,33 +386,28 @@ } } - BinaryByteStream Stream(Data, support::little); - CVTypeArray Types; - BinaryStreamReader Reader(Stream); - if (auto EC = Reader.readArray(Types, Reader.getLength())) - fatal("Reader::readArray failed: " + toString(std::move(EC))); - - auto FirstType = Types.begin(); - if (FirstType == Types.end()) - return *ObjectIndexMap; - - if (FirstType->kind() == LF_TYPESERVER2) { + if (File->DebugTypesKind == ObjFile::UsingPDB) { // Look through type servers. If we've already seen this type server, // don't merge any type information. - return maybeMergeTypeServerPDB(File, *FirstType); - } else if (FirstType->kind() == LF_PRECOMP) { + return maybeMergeTypeServerPDB(File); + } + + auto &Types = *File->DebugTypes; + + if (File->DebugTypesKind == ObjFile::UsingPCH) { // This object was compiled with /Yu, so process the corresponding // precompiled headers object (/Yc) first. Some type indices in the current // object are referencing data in the precompiled headers object, so we need // both to be loaded. - auto E = mergeInPrecompHeaderObj(File, *FirstType, ObjectIndexMap); + auto E = mergeInPrecompHeaderObj(File, ObjectIndexMap); if (!E) return E.takeError(); - // Drop LF_PRECOMP record from the input stream, as it needs to be replaced - // with the precompiled headers object type stream. - // Note that we can't just call Types.drop_front(), as we explicitly want to - // rebase the stream. + // Drop LF_PRECOMP record from the input stream, as it has been replaced + // with the precompiled headers Type stream in the mergeInPrecompHeaderObj() + // call above. Note that we can't just call Types.drop_front(), as we + // explicitly want to rebase the stream. + auto FirstType = Types.begin(); Types.setUnderlyingStream( Types.getUnderlyingStream().drop_front(FirstType->RecordData.size())); } @@ -492,13 +475,8 @@ return std::move(NS); } -Expected -PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, const CVType &FirstType) { - TypeServer2Record TS; - if (auto EC = - TypeDeserializer::deserializeAs(const_cast(FirstType), TS)) - fatal("error reading record: " + toString(std::move(EC))); - +Expected PDBLinker::maybeMergeTypeServerPDB(ObjFile *File) { + auto &TS = *File->TypeServerDependency; const codeview::GUID &TSId = TS.getGuid(); StringRef TSPath = TS.getName(); @@ -607,14 +585,8 @@ } Expected -PDBLinker::mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType, - CVIndexMap *ObjectIndexMap) { - PrecompRecord Precomp; - if (auto EC = TypeDeserializer::deserializeAs(const_cast(FirstType), - Precomp)) - fatal("error reading record: " + toString(std::move(EC))); - - auto E = aquirePrecompObj(File, Precomp); +PDBLinker::mergeInPrecompHeaderObj(ObjFile *File, CVIndexMap *ObjectIndexMap) { + auto E = aquirePrecompObj(File); if (!E) return E.takeError(); @@ -624,6 +596,7 @@ if (PrecompIndexMap.TPIMap.empty()) return PrecompIndexMap; + auto &Precomp = *File->PrecompDependency; assert(Precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex); assert(Precomp.getTypesCount() <= PrecompIndexMap.TPIMap.size()); // Use the previously remapped index map from the precompiled headers. @@ -666,8 +639,8 @@ return {IndexMap, false}; } -Expected -PDBLinker::aquirePrecompObj(ObjFile *File, PrecompRecord Precomp) { +Expected PDBLinker::aquirePrecompObj(ObjFile *File) { + auto &Precomp = *File->PrecompDependency; // First, check if we already loaded the precompiled headers object with this // signature. Return the type index mapping if we've already seen it. auto R = registerPrecompiledHeaders(Precomp.getSignature());