Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -228,7 +228,7 @@ pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); - ExitOnErr(DbiBuilder.addModuleInfo("", "* Linker *")); + ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); // Add COFF section header stream. ExitOnErr( Index: llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -31,11 +31,13 @@ namespace pdb { class DbiStream; struct DbiStreamHeader; +class ModInfoBuilder; class PDBFile; class DbiStreamBuilder { public: DbiStreamBuilder(msf::MSFBuilder &Msf); + ~DbiStreamBuilder(); DbiStreamBuilder(const DbiStreamBuilder &) = delete; DbiStreamBuilder &operator=(const DbiStreamBuilder &) = delete; @@ -55,12 +57,12 @@ uint32_t calculateSerializedLength() const; - Error addModuleInfo(StringRef ObjFile, StringRef Module); + Expected addModuleInfo(StringRef ModuleName); Error addModuleSourceFile(StringRef Module, StringRef File); Error finalizeMsfLayout(); - Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer); + Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef MsfBuffer); // A helper function to create Section Contributions from COFF input // section headers. @@ -88,12 +90,6 @@ Error generateModiSubstream(); Error generateFileInfoSubstream(); - struct ModuleInfo { - std::vector SourceFiles; - StringRef Obj; - StringRef Mod; - }; - msf::MSFBuilder &Msf; BumpPtrAllocator &Allocator; @@ -107,13 +103,12 @@ const DbiStreamHeader *Header; - StringMap> ModuleInfos; - std::vector ModuleInfoList; + StringMap> ModiMap; + std::vector ModiList; StringMap SourceFileNames; WritableBinaryStreamRef NamesBuffer; - MutableBinaryByteStream ModInfoBuffer; MutableBinaryByteStream FileInfoBuffer; ArrayRef SectionContribs; ArrayRef SectionMap; Index: llvm/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h @@ -0,0 +1,74 @@ +//===- ModInfoBuilder.h - PDB module information ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_MODINFOBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_MODINFOBUILDER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/Error.h" +#include +#include +#include + +namespace llvm { +class BinaryStreamWriter; + +namespace msf { +class MSFBuilder; +struct MSFLayout; +} +namespace pdb { + +class ModInfoBuilder { + friend class DbiStreamBuilder; + +public: + ModInfoBuilder(StringRef ModuleName, uint32_t ModIndex, msf::MSFBuilder &Msf); + + ModInfoBuilder(const ModInfoBuilder &) = delete; + ModInfoBuilder &operator=(const ModInfoBuilder &) = delete; + + void setObjFileName(StringRef Name); + void addSymbol(codeview::CVSymbol Symbol); + + uint16_t getStreamIndex() const; + StringRef getModuleName() const { return ModuleName; } + StringRef getObjFileName() const { return ObjFileName; } + + ArrayRef source_files() const { + return makeArrayRef(SourceFiles); + } + + uint32_t calculateSerializedLength() const; + + void finalize(); + Error finalizeMsfLayout(); + + Error commit(BinaryStreamWriter &ModiWriter, const msf::MSFLayout &MsfLayout, + WritableBinaryStreamRef MsfBuffer); + +private: + void addSourceFile(StringRef Path); + msf::MSFBuilder &MSF; + + uint32_t SymbolByteSize = 0; + std::string ModuleName; + std::string ObjFileName; + std::vector SourceFiles; + std::vector Symbols; + ModuleInfoHeader Layout; +}; + +} // end namespace pdb + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_MODINFOBUILDER_H Index: llvm/include/llvm/DebugInfo/PDB/Native/RawError.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/RawError.h +++ llvm/include/llvm/DebugInfo/PDB/Native/RawError.h @@ -28,6 +28,7 @@ duplicate_entry, no_entry, not_writable, + stream_too_long, invalid_tpi_hash, }; Index: llvm/include/llvm/Support/BinaryStreamWriter.h =================================================================== --- llvm/include/llvm/Support/BinaryStreamWriter.h +++ llvm/include/llvm/Support/BinaryStreamWriter.h @@ -154,6 +154,7 @@ uint32_t getOffset() const { return Offset; } uint32_t getLength() const { return Stream.getLength(); } uint32_t bytesRemaining() const { return getLength() - getOffset(); } + Error padToAlignment(uint32_t Align); protected: WritableBinaryStreamRef Stream; Index: llvm/lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- llvm/lib/DebugInfo/PDB/CMakeLists.txt +++ llvm/lib/DebugInfo/PDB/CMakeLists.txt @@ -38,6 +38,7 @@ Native/InfoStream.cpp Native/InfoStreamBuilder.cpp Native/ModInfo.cpp + Native/ModInfoBuilder.cpp Native/ModStream.cpp Native/NativeRawSymbol.cpp Native/NamedStreamMap.cpp Index: llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Object/COFF.h" #include "llvm/Support/BinaryStreamWriter.h" @@ -23,15 +24,13 @@ using namespace llvm::msf; using namespace llvm::pdb; -namespace { -class ModiSubstreamBuilder {}; -} - DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf) : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0), PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86), Header(nullptr), DbgStreams((int)DbgHeaderType::Max) {} +DbiStreamBuilder::~DbiStreamBuilder() {} + void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; } void DbiStreamBuilder::setAge(uint32_t A) { Age = A; } @@ -75,39 +74,37 @@ calculateSectionMapStreamSize() + calculateDbgStreamsSize(); } -Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) { - auto Entry = llvm::make_unique(); - ModuleInfo *M = Entry.get(); - Entry->Mod = Module; - Entry->Obj = ObjFile; - auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry))); +Expected +DbiStreamBuilder::addModuleInfo(StringRef ModuleName) { + uint32_t Index = ModiList.size(); + auto MIB = llvm::make_unique(ModuleName, Index, Msf); + auto M = MIB.get(); + auto Result = ModiMap.insert(std::make_pair(ModuleName, std::move(MIB))); + if (!Result.second) return make_error(raw_error_code::duplicate_entry, "The specified module already exists"); - ModuleInfoList.push_back(M); - return Error::success(); + ModiList.push_back(M); + return *M; } Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) { - auto ModIter = ModuleInfos.find(Module); - if (ModIter == ModuleInfos.end()) + auto ModIter = ModiMap.find(Module); + if (ModIter == ModiMap.end()) return make_error(raw_error_code::no_entry, "The specified module was not found"); uint32_t Index = SourceFileNames.size(); SourceFileNames.insert(std::make_pair(File, Index)); auto &ModEntry = *ModIter; - ModEntry.second->SourceFiles.push_back(File); + ModEntry.second->addSourceFile(File); return Error::success(); } uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const { uint32_t Size = 0; - for (const auto &M : ModuleInfoList) { - Size += sizeof(ModuleInfoHeader); - Size += M->Mod.size() + 1; - Size += M->Obj.size() + 1; - } - return alignTo(Size, sizeof(uint32_t)); + for (const auto &M : ModiList) + Size += M->calculateSerializedLength(); + return Size; } uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const { @@ -127,11 +124,11 @@ uint32_t Size = 0; Size += sizeof(ulittle16_t); // NumModules Size += sizeof(ulittle16_t); // NumSourceFiles - Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices - Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts + Size += ModiList.size() * sizeof(ulittle16_t); // ModIndices + Size += ModiList.size() * sizeof(ulittle16_t); // ModFileCounts uint32_t NumFileInfos = 0; - for (const auto &M : ModuleInfoList) - NumFileInfos += M->SourceFiles.size(); + for (const auto &M : ModiList) + NumFileInfos += M->source_files().size(); Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets Size += calculateNamesBufferSize(); return alignTo(Size, sizeof(uint32_t)); @@ -149,31 +146,6 @@ return DbgStreams.size() * sizeof(uint16_t); } -Error DbiStreamBuilder::generateModiSubstream() { - uint32_t Size = calculateModiSubstreamSize(); - auto Data = Allocator.Allocate(Size); - - ModInfoBuffer = MutableBinaryByteStream(MutableArrayRef(Data, Size), - llvm::support::little); - - BinaryStreamWriter ModiWriter(ModInfoBuffer); - for (const auto &M : ModuleInfoList) { - ModuleInfoHeader Layout = {}; - Layout.ModDiStream = kInvalidStreamIndex; - Layout.NumFiles = M->SourceFiles.size(); - if (auto EC = ModiWriter.writeObject(Layout)) - return EC; - if (auto EC = ModiWriter.writeCString(M->Mod)) - return EC; - if (auto EC = ModiWriter.writeCString(M->Obj)) - return EC; - } - if (ModiWriter.bytesRemaining() > sizeof(uint32_t)) - return make_error(raw_error_code::invalid_format, - "Unexpected bytes in Modi Stream Data"); - return Error::success(); -} - Error DbiStreamBuilder::generateFileInfoSubstream() { uint32_t Size = calculateFileInfoSubstreamSize(); uint32_t NameSize = calculateNamesBufferSize(); @@ -187,7 +159,7 @@ WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset); BinaryStreamWriter MetadataWriter(MetadataBuffer); - uint16_t ModiCount = std::min(UINT16_MAX, ModuleInfos.size()); + uint16_t ModiCount = std::min(UINT16_MAX, ModiList.size()); uint16_t FileCount = std::min(UINT16_MAX, SourceFileNames.size()); if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules return EC; @@ -197,8 +169,8 @@ if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices return EC; } - for (const auto MI : ModuleInfoList) { - FileCount = static_cast(MI->SourceFiles.size()); + for (const auto &MI : ModiList) { + FileCount = static_cast(MI->source_files().size()); if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts return EC; } @@ -215,8 +187,8 @@ return EC; } - for (const auto MI : ModuleInfoList) { - for (StringRef Name : MI->SourceFiles) { + for (const auto &MI : ModiList) { + for (StringRef Name : MI->source_files()) { auto Result = SourceFileNames.find(Name); if (Result == SourceFileNames.end()) return make_error(raw_error_code::no_entry, @@ -242,13 +214,13 @@ if (Header) return Error::success(); - DbiStreamHeader *H = Allocator.Allocate(); + for (auto &MI : ModiList) + MI->finalize(); - if (auto EC = generateModiSubstream()) - return EC; if (auto EC = generateFileInfoSubstream()) return EC; + DbiStreamHeader *H = Allocator.Allocate(); H->VersionHeader = *VerHeader; H->VersionSignature = -1; H->Age = Age; @@ -260,7 +232,7 @@ H->ECSubstreamSize = 0; H->FileInfoSize = FileInfoBuffer.getLength(); - H->ModiSubstreamSize = ModInfoBuffer.getLength(); + H->ModiSubstreamSize = calculateModiSubstreamSize(); H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t); H->SecContrSubstreamSize = calculateSectionContribsStreamSize(); H->SectionMapSize = calculateSectionMapStreamSize(); @@ -275,6 +247,11 @@ } Error DbiStreamBuilder::finalizeMsfLayout() { + for (auto &MI : ModiList) { + if (auto EC = MI->finalizeMsfLayout()) + return EC; + } + uint32_t Length = calculateSerializedLength(); if (auto EC = Msf.setStreamSize(StreamDBI, Length)) return EC; @@ -360,19 +337,21 @@ } Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, - WritableBinaryStreamRef Buffer) { + WritableBinaryStreamRef MsfBuffer) { if (auto EC = finalize()) return EC; - auto InfoS = - WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI); + auto DbiS = WritableMappedBlockStream::createIndexedStream(Layout, MsfBuffer, + StreamDBI); - BinaryStreamWriter Writer(*InfoS); + BinaryStreamWriter Writer(*DbiS); if (auto EC = Writer.writeObject(*Header)) return EC; - if (auto EC = Writer.writeStreamRef(ModInfoBuffer)) - return EC; + for (auto &M : ModiList) { + if (auto EC = M->commit(Writer, Layout, MsfBuffer)) + return EC; + } if (!SectionContribs.empty()) { if (auto EC = Writer.writeEnum(DbiSecContribVer60)) @@ -401,7 +380,7 @@ if (Stream.StreamNumber == kInvalidStreamIndex) continue; auto WritableStream = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, Stream.StreamNumber); + Layout, MsfBuffer, Stream.StreamNumber); BinaryStreamWriter DbgStreamWriter(*WritableStream); if (auto EC = DbgStreamWriter.writeArray(Stream.Data)) return EC; Index: llvm/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp @@ -0,0 +1,136 @@ +//===- ModInfoBuilder.cpp - PDB Module Info Stream Creation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/COFF.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +namespace llvm { +template <> struct BinaryItemTraits { + static size_t length(const CVSymbol &Item) { return Item.RecordData.size(); } + + static ArrayRef bytes(const CVSymbol &Item) { + return Item.RecordData; + } +}; +} + +static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize) { + uint32_t Size = sizeof(uint32_t); // Signature + Size += SymbolByteSize; // Symbol Data + Size += 0; // TODO: Layout.LineBytes + Size += 0; // TODO: Layout.C13Bytes + Size += sizeof(uint32_t); // GlobalRefs substream size (always 0) + Size += 0; // GlobalRefs substream bytes + return Size; +} + +ModInfoBuilder::ModInfoBuilder(StringRef ModuleName, uint32_t ModIndex, + msf::MSFBuilder &Msf) + : MSF(Msf), ModuleName(ModuleName) { + Layout.Mod = ModIndex; +} + +uint16_t ModInfoBuilder::getStreamIndex() const { return Layout.ModDiStream; } + +void ModInfoBuilder::setObjFileName(StringRef Name) { ObjFileName = Name; } + +void ModInfoBuilder::addSymbol(CVSymbol Symbol) { + Symbols.push_back(Symbol); + SymbolByteSize += Symbol.data().size(); +} + +void ModInfoBuilder::addSourceFile(StringRef Path) { + SourceFiles.push_back(Path); +} + +uint32_t ModInfoBuilder::calculateSerializedLength() const { + uint32_t L = sizeof(Layout); + uint32_t M = ModuleName.size() + 1; + uint32_t O = ObjFileName.size() + 1; + return alignTo(L + M + O, sizeof(uint32_t)); +} + +void ModInfoBuilder::finalize() { + Layout.C13Bytes = 0; + Layout.FileNameOffs = 0; // TODO: Fix this + Layout.Flags = 0; // TODO: Fix this + Layout.LineBytes = 0; + (void)Layout.Mod; // Set in constructor + (void)Layout.ModDiStream; // Set in finalizeMsfLayout + Layout.NumFiles = SourceFiles.size(); + Layout.PdbFilePathNI = 0; + Layout.SrcFileNameNI = 0; + + // This value includes both the signature field as well as the record bytes + // from the symbol stream. + Layout.SymBytes = SymbolByteSize + sizeof(uint32_t); +} + +Error ModInfoBuilder::finalizeMsfLayout() { + this->Layout.ModDiStream = kInvalidStreamIndex; + auto ExpectedSN = MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize)); + if (!ExpectedSN) + return ExpectedSN.takeError(); + Layout.ModDiStream = *ExpectedSN; + return Error::success(); +} + +Error ModInfoBuilder::commit(BinaryStreamWriter &ModiWriter, + const msf::MSFLayout &MsfLayout, + WritableBinaryStreamRef MsfBuffer) { + // We write the Modi record to the `ModiWriter`, but we additionally write its + // symbol stream to a brand new stream. + if (auto EC = ModiWriter.writeObject(Layout)) + return EC; + if (auto EC = ModiWriter.writeCString(ModuleName)) + return EC; + if (auto EC = ModiWriter.writeCString(ObjFileName)) + return EC; + if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t))) + return EC; + + if (Layout.ModDiStream != kInvalidStreamIndex) { + auto NS = WritableMappedBlockStream::createIndexedStream( + MsfLayout, MsfBuffer, Layout.ModDiStream); + WritableBinaryStreamRef Ref(*NS); + BinaryStreamWriter SymbolWriter(Ref); + // Write the symbols. + if (auto EC = + SymbolWriter.writeInteger(COFF::DEBUG_SECTION_MAGIC)) + return EC; + BinaryItemStream Records(llvm::support::endianness::little); + Records.setItems(Symbols); + BinaryStreamRef RecordsRef(Records); + if (auto EC = SymbolWriter.writeStreamRef(RecordsRef)) + return EC; + // TODO: Write C11 Line data + // TODO: Write C13 Line data + // TODO: Figure out what GlobalRefs substream actually is and populate it. + if (auto EC = SymbolWriter.writeInteger(0)) + return EC; + if (SymbolWriter.bytesRemaining() > 0) + return make_error(raw_error_code::stream_too_long); + } + return Error::success(); +} Index: llvm/lib/DebugInfo/PDB/Native/RawError.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/RawError.cpp +++ llvm/lib/DebugInfo/PDB/Native/RawError.cpp @@ -38,6 +38,8 @@ return "The entry does not exist."; case raw_error_code::not_writable: return "The PDB does not support writing."; + case raw_error_code::stream_too_long: + return "The stream was longer than expected."; case raw_error_code::invalid_tpi_hash: return "The Type record has an invalid hash value."; } Index: llvm/lib/Support/BinaryStreamWriter.cpp =================================================================== --- llvm/lib/Support/BinaryStreamWriter.cpp +++ llvm/lib/Support/BinaryStreamWriter.cpp @@ -9,6 +9,7 @@ #include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/BinaryStreamError.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/BinaryStreamRef.h" @@ -57,3 +58,11 @@ } return Error::success(); } + +Error BinaryStreamWriter::padToAlignment(uint32_t Align) { + uint32_t NewOffset = alignTo(Offset, Align); + if (NewOffset > getLength()) + return make_error(stream_error_code::stream_too_short); + Offset = NewOffset; + return Error::success(); +} Index: llvm/test/DebugInfo/PDB/Inputs/one-symbol.yaml =================================================================== --- /dev/null +++ llvm/test/DebugInfo/PDB/Inputs/one-symbol.yaml @@ -0,0 +1,11 @@ +--- +DbiStream: + Modules: + - Module: one-symbol.yaml + Modi: + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'c:\foo\one-symbol.yaml' +... Index: llvm/test/DebugInfo/PDB/pdb-minimal-construct.test =================================================================== --- /dev/null +++ llvm/test/DebugInfo/PDB/pdb-minimal-construct.test @@ -0,0 +1,11 @@ +; This testcase verifies that we can produce a minimal PDB, while +; serving as an example for how to construct a minimal PDB for other +; testcases. It takes as input a small fragment of hand-written yaml +; that specifies nothing about the PDB other than a definition of one +; symbol that it contains. Then it produces a PDB, and uses the +; resulting PDB to go back to yaml, and verify that the resulting yaml +; is identical. + +; RUN: llvm-pdbdump yaml2pdb -pdb=%t.pdb %p/Inputs/one-symbol.yaml +; RUN: llvm-pdbdump pdb2yaml -minimal -dbi-module-syms -no-file-headers %t.pdb > %t.pdb.yaml +; RUN: diff -b %p/Inputs/one-symbol.yaml %t.pdb.yaml Index: llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test +++ llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test @@ -4,18 +4,14 @@ YAML: --- YAML: MSF: YAML: SuperBlock: -YAML: BlockSize: 4096 -YAML: FreeBlockMap: 2 YAML: NumBlocks: 25 YAML: NumDirectoryBytes: 136 -YAML: Unknown1: 0 YAML: BlockMapAddr: 24 YAML: NumDirectoryBlocks: 1 YAML: DirectoryBlocks: [ 23 ] YAML: NumStreams: 0 YAML: FileSize: 102400 YAML: TpiStream: -YAML: Version: VC80 YAML: Records: YAML: - Kind: LF_ARGLIST YAML: ArgList: Index: llvm/tools/llvm-pdbdump/PdbYaml.h =================================================================== --- llvm/tools/llvm-pdbdump/PdbYaml.h +++ llvm/tools/llvm-pdbdump/PdbYaml.h @@ -32,10 +32,10 @@ struct MSFHeaders { msf::SuperBlock SuperBlock; - uint32_t NumDirectoryBlocks; + uint32_t NumDirectoryBlocks = 0; std::vector DirectoryBlocks; - uint32_t NumStreams; - uint32_t FileSize; + uint32_t NumStreams = 0; + uint32_t FileSize = 0; }; struct StreamBlockList { @@ -48,9 +48,9 @@ }; struct PdbInfoStream { - PdbRaw_ImplVer Version; - uint32_t Signature; - uint32_t Age; + PdbRaw_ImplVer Version = PdbImplVC70; + uint32_t Signature = 0; + uint32_t Age = 1; PDB_UniqueId Guid; std::vector NamedStreams; }; @@ -72,13 +72,13 @@ }; struct PdbDbiStream { - PdbRaw_DbiVer VerHeader; - uint32_t Age; - uint16_t BuildNumber; - uint32_t PdbDllVersion; - uint16_t PdbDllRbld; - uint16_t Flags; - PDB_Machine MachineType; + PdbRaw_DbiVer VerHeader = PdbDbiV70; + uint32_t Age = 1; + uint16_t BuildNumber = 0; + uint32_t PdbDllVersion = 0; + uint16_t PdbDllRbld = 0; + uint16_t Flags = 1; + PDB_Machine MachineType = PDB_Machine::x86; std::vector ModInfos; }; @@ -92,7 +92,7 @@ }; struct PdbTpiStream { - PdbRaw_TpiVer Version; + PdbRaw_TpiVer Version = PdbTpiV80; std::vector Records; }; Index: llvm/tools/llvm-pdbdump/PdbYaml.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PdbYaml.cpp +++ llvm/tools/llvm-pdbdump/PdbYaml.cpp @@ -158,11 +158,11 @@ } void MappingTraits::mapping(IO &IO, MSFHeaders &Obj) { - IO.mapRequired("SuperBlock", Obj.SuperBlock); - IO.mapRequired("NumDirectoryBlocks", Obj.NumDirectoryBlocks); - IO.mapRequired("DirectoryBlocks", Obj.DirectoryBlocks); - IO.mapRequired("NumStreams", Obj.NumStreams); - IO.mapRequired("FileSize", Obj.FileSize); + IO.mapOptional("SuperBlock", Obj.SuperBlock); + IO.mapOptional("NumDirectoryBlocks", Obj.NumDirectoryBlocks); + IO.mapOptional("DirectoryBlocks", Obj.DirectoryBlocks); + IO.mapOptional("NumStreams", Obj.NumStreams); + IO.mapOptional("FileSize", Obj.FileSize); } void MappingTraits::mapping(IO &IO, msf::SuperBlock &SB) { @@ -170,12 +170,13 @@ ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic)); } - IO.mapRequired("BlockSize", SB.BlockSize); - IO.mapRequired("FreeBlockMap", SB.FreeBlockMapBlock); - IO.mapRequired("NumBlocks", SB.NumBlocks); - IO.mapRequired("NumDirectoryBytes", SB.NumDirectoryBytes); - IO.mapRequired("Unknown1", SB.Unknown1); - IO.mapRequired("BlockMapAddr", SB.BlockMapAddr); + using u32 = support::ulittle32_t; + IO.mapOptional("BlockSize", SB.BlockSize, u32(4096U)); + IO.mapOptional("FreeBlockMap", SB.FreeBlockMapBlock, u32(0U)); + IO.mapOptional("NumBlocks", SB.NumBlocks, u32(0U)); + IO.mapOptional("NumDirectoryBytes", SB.NumDirectoryBytes, u32(0U)); + IO.mapOptional("Unknown1", SB.Unknown1, u32(0U)); + IO.mapOptional("BlockMapAddr", SB.BlockMapAddr, u32(0U)); } void MappingTraits::mapping(IO &IO, StreamBlockList &SB) { @@ -183,26 +184,26 @@ } void MappingTraits::mapping(IO &IO, PdbInfoStream &Obj) { - IO.mapRequired("Age", Obj.Age); - IO.mapRequired("Guid", Obj.Guid); - IO.mapRequired("Signature", Obj.Signature); - IO.mapRequired("Version", Obj.Version); + IO.mapOptional("Age", Obj.Age, 1U); + IO.mapOptional("Guid", Obj.Guid); + IO.mapOptional("Signature", Obj.Signature, 0U); + IO.mapOptional("Version", Obj.Version, PdbImplVC70); } void MappingContextTraits::mapping(IO &IO, PdbDbiStream &Obj, pdb::yaml::SerializationContext &Context) { - IO.mapRequired("VerHeader", Obj.VerHeader); - IO.mapRequired("Age", Obj.Age); - IO.mapRequired("BuildNumber", Obj.BuildNumber); - IO.mapRequired("PdbDllVersion", Obj.PdbDllVersion); - IO.mapRequired("PdbDllRbld", Obj.PdbDllRbld); - IO.mapRequired("Flags", Obj.Flags); - IO.mapRequired("MachineType", Obj.MachineType); + IO.mapOptional("VerHeader", Obj.VerHeader, PdbDbiV70); + IO.mapOptional("Age", Obj.Age, 1U); + IO.mapOptional("BuildNumber", Obj.BuildNumber, uint16_t(0U)); + IO.mapOptional("PdbDllVersion", Obj.PdbDllVersion, 0U); + IO.mapOptional("PdbDllRbld", Obj.PdbDllRbld, uint16_t(0U)); + IO.mapOptional("Flags", Obj.Flags, uint16_t(1U)); + IO.mapOptional("MachineType", Obj.MachineType, PDB_Machine::x86); IO.mapOptionalWithContext("Modules", Obj.ModInfos, Context); } void MappingContextTraits::mapping( IO &IO, pdb::yaml::PdbTpiStream &Obj, pdb::yaml::SerializationContext &Context) { - IO.mapRequired("Version", Obj.Version); + IO.mapOptional("Version", Obj.Version, PdbTpiV80); IO.mapRequired("Records", Obj.Records, Context); } @@ -234,13 +235,13 @@ } void MappingContextTraits::mapping(IO &IO, PdbModiStream &Obj, pdb::yaml::SerializationContext &Context) { - IO.mapRequired("Signature", Obj.Signature); + IO.mapOptional("Signature", Obj.Signature, 4U); IO.mapRequired("Records", Obj.Symbols, Context); } void MappingContextTraits::mapping(IO &IO, PdbDbiModuleInfo &Obj, pdb::yaml::SerializationContext &Context) { IO.mapRequired("Module", Obj.Mod); - IO.mapRequired("ObjFile", Obj.Obj); + IO.mapOptional("ObjFile", Obj.Obj, Obj.Mod); IO.mapOptional("SourceFiles", Obj.SourceFiles); IO.mapOptionalWithContext("Modi", Obj.Modi, Context); } Index: llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -24,7 +24,9 @@ using namespace llvm::pdb; YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) - : File(File), Out(outs()), Obj(File.getAllocator()) {} + : File(File), Out(outs()), Obj(File.getAllocator()) { + Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal); +} Error YAMLOutputStyle::dump() { if (opts::pdb2yaml::StreamDirectory) Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.h =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ llvm/tools/llvm-pdbdump/llvm-pdbdump.h @@ -73,6 +73,7 @@ namespace pdb2yaml { extern llvm::cl::opt NoFileHeaders; +extern llvm::cl::opt Minimal; extern llvm::cl::opt StreamMetadata; extern llvm::cl::opt StreamDirectory; extern llvm::cl::opt StringTable; Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -39,6 +39,7 @@ #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/ModInfoBuilder.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" @@ -290,6 +291,9 @@ cl::desc("Do not dump MSF file headers (you will not be able " "to generate a fresh PDB from the resulting YAML)"), cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt Minimal("minimal", + cl::desc("Don't write fields with default values"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); cl::opt StreamMetadata( "stream-metadata", @@ -364,13 +368,13 @@ llvm::yaml::Input In(Buffer->getBuffer()); pdb::yaml::PdbObject YamlObj(Allocator); In >> YamlObj; - if (!YamlObj.Headers.hasValue()) - ExitOnErr(make_error(generic_error_code::unspecified, - "Yaml does not contain MSF headers")); PDBFileBuilder Builder(Allocator); - ExitOnErr(Builder.initialize(YamlObj.Headers->SuperBlock.BlockSize)); + uint32_t BlockSize = 4096; + if (YamlObj.Headers.hasValue()) + BlockSize = YamlObj.Headers->SuperBlock.BlockSize; + ExitOnErr(Builder.initialize(BlockSize)); // Add each of the reserved streams. We ignore stream metadata in the // yaml, because we will reconstruct our own view of the streams. For // example, the YAML may say that there were 20 streams in the original @@ -386,43 +390,51 @@ Strings.insert(S); } - if (YamlObj.PdbStream.hasValue()) { - auto &InfoBuilder = Builder.getInfoBuilder(); - InfoBuilder.setAge(YamlObj.PdbStream->Age); - InfoBuilder.setGuid(YamlObj.PdbStream->Guid); - InfoBuilder.setSignature(YamlObj.PdbStream->Signature); - InfoBuilder.setVersion(YamlObj.PdbStream->Version); - } - - if (YamlObj.DbiStream.hasValue()) { - auto &DbiBuilder = Builder.getDbiBuilder(); - DbiBuilder.setAge(YamlObj.DbiStream->Age); - DbiBuilder.setBuildNumber(YamlObj.DbiStream->BuildNumber); - DbiBuilder.setFlags(YamlObj.DbiStream->Flags); - DbiBuilder.setMachineType(YamlObj.DbiStream->MachineType); - DbiBuilder.setPdbDllRbld(YamlObj.DbiStream->PdbDllRbld); - DbiBuilder.setPdbDllVersion(YamlObj.DbiStream->PdbDllVersion); - DbiBuilder.setVersionHeader(YamlObj.DbiStream->VerHeader); - for (const auto &MI : YamlObj.DbiStream->ModInfos) { - ExitOnErr(DbiBuilder.addModuleInfo(MI.Obj, MI.Mod)); - for (auto S : MI.SourceFiles) - ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S)); + pdb::yaml::PdbInfoStream DefaultInfoStream; + pdb::yaml::PdbDbiStream DefaultDbiStream; + pdb::yaml::PdbTpiStream DefaultTpiStream; + + const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream); + + auto &InfoBuilder = Builder.getInfoBuilder(); + InfoBuilder.setAge(Info.Age); + InfoBuilder.setGuid(Info.Guid); + InfoBuilder.setSignature(Info.Signature); + InfoBuilder.setVersion(Info.Version); + + const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream); + auto &DbiBuilder = Builder.getDbiBuilder(); + DbiBuilder.setAge(Dbi.Age); + DbiBuilder.setBuildNumber(Dbi.BuildNumber); + DbiBuilder.setFlags(Dbi.Flags); + DbiBuilder.setMachineType(Dbi.MachineType); + DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld); + DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion); + DbiBuilder.setVersionHeader(Dbi.VerHeader); + for (const auto &MI : Dbi.ModInfos) { + auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Obj)); + + for (auto S : MI.SourceFiles) + ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S)); + if (MI.Modi.hasValue()) { + const auto &ModiStream = *MI.Modi; + ModiBuilder.setObjFileName(MI.Obj); + for (auto Symbol : ModiStream.Symbols) + ModiBuilder.addSymbol(Symbol.Record); } } - if (YamlObj.TpiStream.hasValue()) { - auto &TpiBuilder = Builder.getTpiBuilder(); - TpiBuilder.setVersionHeader(YamlObj.TpiStream->Version); - for (const auto &R : YamlObj.TpiStream->Records) - TpiBuilder.addTypeRecord(R.Record); - } - - if (YamlObj.IpiStream.hasValue()) { - auto &IpiBuilder = Builder.getIpiBuilder(); - IpiBuilder.setVersionHeader(YamlObj.IpiStream->Version); - for (const auto &R : YamlObj.IpiStream->Records) - IpiBuilder.addTypeRecord(R.Record); - } + auto &TpiBuilder = Builder.getTpiBuilder(); + const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream); + TpiBuilder.setVersionHeader(Tpi.Version); + for (const auto &R : Tpi.Records) + TpiBuilder.addTypeRecord(R.Record); + + const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultTpiStream); + auto &IpiBuilder = Builder.getIpiBuilder(); + IpiBuilder.setVersionHeader(Ipi.Version); + for (const auto &R : Ipi.Records) + IpiBuilder.addTypeRecord(R.Record); ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile)); }