diff options
Diffstat (limited to 'COFF/PDB.cpp')
-rw-r--r-- | COFF/PDB.cpp | 426 |
1 files changed, 294 insertions, 132 deletions
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index 508f59e3af1fd..89462da934546 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -14,28 +14,29 @@ #include "SymbolTable.h" #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" -#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/SymbolSerializer.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" -#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/Object/COFF.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Endian.h" @@ -53,8 +54,81 @@ using llvm::object::coff_section; static ExitOnError ExitOnErr; +namespace { +/// Map from type index and item index in a type server PDB to the +/// corresponding index in the destination PDB. +struct CVIndexMap { + SmallVector<TypeIndex, 0> TPIMap; + SmallVector<TypeIndex, 0> IPIMap; + bool IsTypeServerMap = false; +}; + +class PDBLinker { +public: + PDBLinker(SymbolTable *Symtab) + : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc), + IDTable(Alloc) {} + + /// Emit the basic PDB structure: initial streams, headers, etc. + void initialize(const llvm::codeview::DebugInfo *DI); + + /// Link CodeView from each object file in the symbol table into the PDB. + void addObjectsToPDB(); + + /// Link CodeView from a single object file into the PDB. + void addObjectFile(ObjectFile *File); + + /// Produce a mapping from the type and item indices used in the object + /// file to those in the destination PDB. + /// + /// If the object file uses a type server PDB (compiled with /Zi), merge TPI + /// and IPI from the type server PDB and return a map for it. Each unique type + /// server PDB is merged at most once, so this may return an existing index + /// mapping. + /// + /// If the object does not use a type server PDB (compiled with /Z7), we merge + /// all the type and item records from the .debug$S stream and fill in the + /// caller-provided ObjectIndexMap. + const CVIndexMap &mergeDebugT(ObjectFile *File, CVIndexMap &ObjectIndexMap); + + const CVIndexMap &maybeMergeTypeServerPDB(ObjectFile *File, + TypeServer2Record &TS); + + /// Add the section map and section contributions to the PDB. + void addSections(ArrayRef<uint8_t> SectionTable); + + /// Write the PDB to disk. + void commit(); + +private: + BumpPtrAllocator Alloc; + + SymbolTable *Symtab; + + pdb::PDBFileBuilder Builder; + + /// Type records that will go into the PDB TPI stream. + TypeTableBuilder TypeTable; + + /// Item records that will go into the PDB IPI stream. + TypeTableBuilder IDTable; + + /// PDBs use a single global string table for filenames in the file checksum + /// table. + DebugStringTableSubsection PDBStrTab; + + llvm::SmallString<128> NativePath; + + std::vector<pdb::SecMapEntry> SectionMap; + + /// Type index mappings of type server PDBs that we've loaded so far. + std::map<GUID, CVIndexMap> TypeServerIndexMappings; +}; +} + // Returns a list of all SectionChunks. -static void addSectionContribs(SymbolTable *Symtab, pdb::DbiStreamBuilder &DbiBuilder) { +static void addSectionContribs(SymbolTable *Symtab, + pdb::DbiStreamBuilder &DbiBuilder) { for (Chunk *C : Symtab->getChunks()) if (auto *SC = dyn_cast<SectionChunk>(C)) DbiBuilder.addSectionContrib(SC->File->ModuleDBI, SC->Header); @@ -96,24 +170,115 @@ static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, }); } -static void mergeDebugT(ObjectFile *File, - TypeTableBuilder &IDTable, - TypeTableBuilder &TypeTable, - SmallVectorImpl<TypeIndex> &TypeIndexMap, - pdb::PDBTypeServerHandler &Handler) { +static Optional<TypeServer2Record> +maybeReadTypeServerRecord(CVTypeArray &Types) { + auto I = Types.begin(); + if (I == Types.end()) + return None; + const CVType &Type = *I; + if (Type.kind() != LF_TYPESERVER2) + return None; + TypeServer2Record TS; + if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type), TS)) + fatal(EC, "error reading type server record"); + return std::move(TS); +} + +const CVIndexMap &PDBLinker::mergeDebugT(ObjectFile *File, + CVIndexMap &ObjectIndexMap) { ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T"); if (Data.empty()) - return; + return ObjectIndexMap; BinaryByteStream Stream(Data, support::little); CVTypeArray Types; BinaryStreamReader Reader(Stream); - Handler.addSearchPath(sys::path::parent_path(File->getName())); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal(EC, "Reader::readArray failed"); + + // Look through type servers. If we've already seen this type server, don't + // merge any type information. + if (Optional<TypeServer2Record> TS = maybeReadTypeServerRecord(Types)) + return maybeMergeTypeServerPDB(File, *TS); + + // This is a /Z7 object. Fill in the temporary, caller-provided + // ObjectIndexMap. if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, - TypeIndexMap, &Handler, Types)) - fatal(Err, "codeview::mergeTypeStreams failed"); + ObjectIndexMap.TPIMap, Types)) + fatal(Err, "codeview::mergeTypeAndIdRecords failed"); + return ObjectIndexMap; +} + +static Expected<std::unique_ptr<pdb::NativeSession>> +tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) { + std::unique_ptr<pdb::IPDBSession> ThisSession; + if (auto EC = + pdb::loadDataForPDB(pdb::PDB_ReaderType::Native, TSPath, ThisSession)) + return std::move(EC); + + std::unique_ptr<pdb::NativeSession> NS( + static_cast<pdb::NativeSession *>(ThisSession.release())); + pdb::PDBFile &File = NS->getPDBFile(); + auto ExpectedInfo = File.getPDBInfoStream(); + // All PDB Files should have an Info stream. + if (!ExpectedInfo) + return ExpectedInfo.takeError(); + + // Just because a file with a matching name was found and it was an actual + // PDB file doesn't mean it matches. For it to match the InfoStream's GUID + // must match the GUID specified in the TypeServer2 record. + if (ExpectedInfo->getGuid() != GuidFromObj) + return make_error<pdb::GenericError>( + pdb::generic_error_code::type_server_not_found, TSPath); + + return std::move(NS); +} + +const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjectFile *File, + TypeServer2Record &TS) { + // First, check if we already loaded a PDB with this GUID. Return the type + // index mapping if we have it. + auto Insertion = TypeServerIndexMappings.insert({TS.getGuid(), CVIndexMap()}); + CVIndexMap &IndexMap = Insertion.first->second; + if (!Insertion.second) + return IndexMap; + + // Mark this map as a type server map. + IndexMap.IsTypeServerMap = true; + + // Check for a PDB at: + // 1. The given file path + // 2. Next to the object file or archive file + auto ExpectedSession = tryToLoadPDB(TS.getGuid(), TS.getName()); + if (!ExpectedSession) { + consumeError(ExpectedSession.takeError()); + StringRef LocalPath = + !File->ParentName.empty() ? File->ParentName : File->getName(); + SmallString<128> Path = sys::path::parent_path(LocalPath); + sys::path::append( + Path, sys::path::filename(TS.getName(), sys::path::Style::windows)); + ExpectedSession = tryToLoadPDB(TS.getGuid(), Path); + } + if (auto E = ExpectedSession.takeError()) + fatal(E, "Type server PDB was not found"); + + // Merge TPI first, because the IPI stream will reference type indices. + auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream(); + if (auto E = ExpectedTpi.takeError()) + fatal(E, "Type server does not have TPI stream"); + if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap, + ExpectedTpi->typeArray())) + fatal(Err, "codeview::mergeTypeRecords failed"); + + // Merge IPI. + auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream(); + if (auto E = ExpectedIpi.takeError()) + fatal(E, "Type server does not have TPI stream"); + if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap, + ExpectedIpi->typeArray())) + fatal(Err, "codeview::mergeIdRecords failed"); + + return IndexMap; } static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) { @@ -127,16 +292,22 @@ static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) { static void remapTypesInSymbolRecord(ObjectFile *File, MutableArrayRef<uint8_t> Contents, - ArrayRef<TypeIndex> TypeIndexMap, + const CVIndexMap &IndexMap, ArrayRef<TiReference> TypeRefs) { for (const TiReference &Ref : TypeRefs) { unsigned ByteSize = Ref.Count * sizeof(TypeIndex); if (Contents.size() < Ref.Offset + ByteSize) fatal("symbol record too short"); + + // This can be an item index or a type index. Choose the appropriate map. + ArrayRef<TypeIndex> TypeOrItemMap = IndexMap.TPIMap; + if (Ref.Kind == TiRefKind::IndexRef && IndexMap.IsTypeServerMap) + TypeOrItemMap = IndexMap.IPIMap; + MutableArrayRef<TypeIndex> TIs( reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count); for (TypeIndex &TI : TIs) { - if (!remapTypeIndex(TI, TypeIndexMap)) { + if (!remapTypeIndex(TI, TypeOrItemMap)) { TI = TypeIndex(SimpleTypeKind::NotTranslated); log("ignoring symbol record in " + File->getName() + " with bad type index 0x" + utohexstr(TI.getIndex())); @@ -241,7 +412,7 @@ static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack, } static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, - ArrayRef<TypeIndex> TypeIndexMap, + const CVIndexMap &IndexMap, BinaryStreamRef SymData) { // FIXME: Improve error recovery by warning and skipping records when // possible. @@ -264,7 +435,7 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, // Re-map all the type index references. MutableArrayRef<uint8_t> Contents = NewData.drop_front(sizeof(RecordPrefix)); - remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs); + remapTypesInSymbolRecord(File, Contents, IndexMap, TypeRefs); // Fill in "Parent" and "End" fields by maintaining a stack of scopes. CVSymbol NewSym(Sym.kind(), NewData); @@ -289,110 +460,105 @@ static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc, ".debug$S"); } -// Add all object files to the PDB. Merge .debug$T sections into IpiData and -// TpiData. -static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab, - pdb::PDBFileBuilder &Builder, - TypeTableBuilder &TypeTable, - TypeTableBuilder &IDTable) { - // Follow type servers. If the same type server is encountered more than - // once for this instance of `PDBTypeServerHandler` (for example if many - // object files reference the same TypeServer), the types from the - // TypeServer will only be visited once. - pdb::PDBTypeServerHandler Handler; - - // PDBs use a single global string table for filenames in the file checksum - // table. - auto PDBStrTab = std::make_shared<DebugStringTableSubsection>(); - - // Visit all .debug$T sections to add them to Builder. - for (ObjectFile *File : Symtab->ObjectFiles) { - // Add a module descriptor for every object file. We need to put an absolute - // path to the object into the PDB. If this is a plain object, we make its - // path absolute. If it's an object in an archive, we make the archive path - // absolute. - bool InArchive = !File->ParentName.empty(); - SmallString<128> Path = InArchive ? File->ParentName : File->getName(); - sys::fs::make_absolute(Path); - sys::path::native(Path, llvm::sys::path::Style::windows); - StringRef Name = InArchive ? File->getName() : StringRef(Path); - - File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); - File->ModuleDBI->setObjFileName(Path); - - // Before we can process symbol substreams from .debug$S, we need to process - // type information, file checksums, and the string table. Add type info to - // the PDB first, so that we can get the map from object file type and item - // indices to PDB type and item indices. - SmallVector<TypeIndex, 128> TypeIndexMap; - mergeDebugT(File, IDTable, TypeTable, TypeIndexMap, Handler); - - // Now do all line info. - for (SectionChunk *DebugChunk : File->getDebugChunks()) { - if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") - continue; +void PDBLinker::addObjectFile(ObjectFile *File) { + // Add a module descriptor for every object file. We need to put an absolute + // path to the object into the PDB. If this is a plain object, we make its + // path absolute. If it's an object in an archive, we make the archive path + // absolute. + bool InArchive = !File->ParentName.empty(); + SmallString<128> Path = InArchive ? File->ParentName : File->getName(); + sys::fs::make_absolute(Path); + sys::path::native(Path, sys::path::Style::windows); + StringRef Name = InArchive ? File->getName() : StringRef(Path); + + File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); + File->ModuleDBI->setObjFileName(Path); + + // Before we can process symbol substreams from .debug$S, we need to process + // type information, file checksums, and the string table. Add type info to + // the PDB first, so that we can get the map from object file type and item + // indices to PDB type and item indices. + CVIndexMap ObjectIndexMap; + const CVIndexMap &IndexMap = mergeDebugT(File, ObjectIndexMap); + + // Now do all live .debug$S sections. + for (SectionChunk *DebugChunk : File->getDebugChunks()) { + if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") + continue; - ArrayRef<uint8_t> RelocatedDebugContents = - relocateDebugChunk(Alloc, DebugChunk); - if (RelocatedDebugContents.empty()) - continue; + ArrayRef<uint8_t> RelocatedDebugContents = + relocateDebugChunk(Alloc, DebugChunk); + if (RelocatedDebugContents.empty()) + continue; - DebugSubsectionArray Subsections; - BinaryStreamReader Reader(RelocatedDebugContents, support::little); - ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); - - DebugStringTableSubsectionRef CVStrTab; - DebugChecksumsSubsectionRef Checksums; - for (const DebugSubsectionRecord &SS : Subsections) { - switch (SS.kind()) { - case DebugSubsectionKind::StringTable: - ExitOnErr(CVStrTab.initialize(SS.getRecordData())); - break; - case DebugSubsectionKind::FileChecksums: - ExitOnErr(Checksums.initialize(SS.getRecordData())); - break; - case DebugSubsectionKind::Lines: - // We can add the relocated line table directly to the PDB without - // modification because the file checksum offsets will stay the same. - File->ModuleDBI->addDebugSubsection(SS); - break; - case DebugSubsectionKind::Symbols: - mergeSymbolRecords(Alloc, File, TypeIndexMap, SS.getRecordData()); - break; - default: - // FIXME: Process the rest of the subsections. - break; - } + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); + + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + for (const DebugSubsectionRecord &SS : Subsections) { + switch (SS.kind()) { + case DebugSubsectionKind::StringTable: + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::FileChecksums: + ExitOnErr(Checksums.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::Lines: + // We can add the relocated line table directly to the PDB without + // modification because the file checksum offsets will stay the same. + File->ModuleDBI->addDebugSubsection(SS); + break; + case DebugSubsectionKind::Symbols: + mergeSymbolRecords(Alloc, File, IndexMap, SS.getRecordData()); + break; + default: + // FIXME: Process the rest of the subsections. + break; } + } - if (Checksums.valid()) { - // Make a new file checksum table that refers to offsets in the PDB-wide - // string table. Generally the string table subsection appears after the - // checksum table, so we have to do this after looping over all the - // subsections. - if (!CVStrTab.valid()) - fatal(".debug$S sections must have both a string table subsection " - "and a checksum subsection table or neither"); - auto NewChecksums = - make_unique<DebugChecksumsSubsection>(*PDBStrTab); - for (FileChecksumEntry &FC : Checksums) { - StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); - ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile( - *File->ModuleDBI, FileName)); - NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); - } - File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); + if (Checksums.valid()) { + // Make a new file checksum table that refers to offsets in the PDB-wide + // string table. Generally the string table subsection appears after the + // checksum table, so we have to do this after looping over all the + // subsections. + if (!CVStrTab.valid()) + fatal(".debug$S sections must have both a string table subsection " + "and a checksum subsection table or neither"); + auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab); + for (FileChecksumEntry &FC : Checksums) { + StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI, + FileName)); + NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); } + File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); } } +} + +// Add all object files to the PDB. Merge .debug$T sections into IpiData and +// TpiData. +void PDBLinker::addObjectsToPDB() { + for (ObjectFile *File : Symtab->ObjectFiles) + addObjectFile(File); - Builder.getStringTableBuilder().setStrings(*PDBStrTab); + Builder.getStringTableBuilder().setStrings(PDBStrTab); // Construct TPI stream contents. addTypeInfo(Builder.getTpiBuilder(), TypeTable); // Construct IPI stream contents. addTypeInfo(Builder.getIpiBuilder(), IDTable); + + // Add public and symbol records stream. + + // For now we don't actually write any thing useful to the publics stream, but + // the act of "getting" it also creates it lazily so that we write an empty + // stream. + (void)Builder.getPublicsBuilder(); } static void addLinkerModuleSymbols(StringRef Path, @@ -423,7 +589,7 @@ static void addLinkerModuleSymbols(StringRef Path, std::string ArgStr = llvm::join(Args, " "); EBS.Fields.push_back("cwd"); SmallString<64> cwd; - llvm::sys::fs::current_path(cwd); + sys::fs::current_path(cwd); EBS.Fields.push_back(cwd); EBS.Fields.push_back("exe"); EBS.Fields.push_back(Config->Argv[0]); @@ -442,8 +608,14 @@ static void addLinkerModuleSymbols(StringRef Path, // Creates a PDB file. void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable, const llvm::codeview::DebugInfo *DI) { - BumpPtrAllocator Alloc; - pdb::PDBFileBuilder Builder(Alloc); + PDBLinker PDB(Symtab); + PDB.initialize(DI); + PDB.addObjectsToPDB(); + PDB.addSections(SectionTable); + PDB.commit(); +} + +void PDBLinker::initialize(const llvm::codeview::DebugInfo *DI) { ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize // Create streams in MSF for predefined streams, namely @@ -455,12 +627,7 @@ void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable, auto &InfoBuilder = Builder.getInfoBuilder(); InfoBuilder.setAge(DI ? DI->PDB70.Age : 0); - llvm::SmallString<128> NativePath(Config->PDBPath.begin(), - Config->PDBPath.end()); - llvm::sys::fs::make_absolute(NativePath); - llvm::sys::path::native(NativePath, llvm::sys::path::Style::windows); - - pdb::PDB_UniqueId uuid{}; + GUID uuid{}; if (DI) memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid)); InfoBuilder.setGuid(uuid); @@ -471,32 +638,25 @@ void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable, pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setVersionHeader(pdb::PdbDbiV70); ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {})); +} - // It's not entirely clear what this is, but the * Linker * module uses it. - uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); - - TypeTableBuilder TypeTable(BAlloc); - TypeTableBuilder IDTable(BAlloc); - addObjectsToPDB(Alloc, Symtab, Builder, TypeTable, IDTable); - - // Add public and symbol records stream. - - // For now we don't actually write any thing useful to the publics stream, but - // the act of "getting" it also creates it lazily so that we write an empty - // stream. - (void)Builder.getPublicsBuilder(); - +void PDBLinker::addSections(ArrayRef<uint8_t> SectionTable) { // Add Section Contributions. + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); addSectionContribs(Symtab, DbiBuilder); // Add Section Map stream. ArrayRef<object::coff_section> Sections = { (const object::coff_section *)SectionTable.data(), SectionTable.size() / sizeof(object::coff_section)}; - std::vector<pdb::SecMapEntry> SectionMap = - pdb::DbiStreamBuilder::createSectionMap(Sections); + SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); + // It's not entirely clear what this is, but the * Linker * module uses it. + NativePath = Config->PDBPath; + sys::fs::make_absolute(NativePath); + sys::path::native(NativePath, sys::path::Style::windows); + uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); LinkerModule.setPdbFilePathNI(PdbFilePathNI); addLinkerModuleSymbols(NativePath, LinkerModule, Alloc); @@ -504,7 +664,9 @@ void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable, // Add COFF section header stream. ExitOnErr( DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); +} +void PDBLinker::commit() { // Write to a file. ExitOnErr(Builder.commit(Config->PDBPath)); } |