From 91d41f9825b3130bebcd60ce161dc8dc0fe96d26 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Thu, 30 Jun 2016 17:43:00 +0000 Subject: [PATCH] [pdb] Re-add code to write PDB files. Somehow all the functionality to write PDB files got removed, probably accidentally when uploading the patch perhaps the wrong one got uploaded. This re-adds all the code, as well as the corresponding test. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@274248 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/DebugInfo/CodeView/ByteStream.h | 2 + .../llvm/DebugInfo/CodeView/StreamInterface.h | 2 + include/llvm/DebugInfo/CodeView/StreamRef.h | 2 + .../DebugInfo/PDB/Raw/MappedBlockStream.h | 1 + include/llvm/DebugInfo/PDB/Raw/PDBFile.h | 8 +- lib/DebugInfo/CodeView/ByteStream.cpp | 4 + lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp | 2 + lib/DebugInfo/PDB/Raw/PDBFile.cpp | 133 +++++++++++------- test/DebugInfo/PDB/pdbdump-write.test | 13 ++ tools/llvm-pdbdump/YAMLOutputStyle.cpp | 5 +- tools/llvm-pdbdump/YAMLOutputStyle.h | 1 - tools/llvm-pdbdump/llvm-pdbdump.cpp | 56 +++++--- 12 files changed, 153 insertions(+), 76 deletions(-) create mode 100644 test/DebugInfo/PDB/pdbdump-write.test diff --git a/include/llvm/DebugInfo/CodeView/ByteStream.h b/include/llvm/DebugInfo/CodeView/ByteStream.h index ec841d9f45e..f398c93723e 100644 --- a/include/llvm/DebugInfo/CodeView/ByteStream.h +++ b/include/llvm/DebugInfo/CodeView/ByteStream.h @@ -40,6 +40,8 @@ public: uint32_t getLength() const override; + Error commit() const override; + ArrayRef data() const { return Data; } StringRef str() const; diff --git a/include/llvm/DebugInfo/CodeView/StreamInterface.h b/include/llvm/DebugInfo/CodeView/StreamInterface.h index a8b9dbfc2b6..241aec45787 100644 --- a/include/llvm/DebugInfo/CodeView/StreamInterface.h +++ b/include/llvm/DebugInfo/CodeView/StreamInterface.h @@ -45,6 +45,8 @@ public: virtual Error writeBytes(uint32_t Offset, ArrayRef Data) const = 0; virtual uint32_t getLength() const = 0; + + virtual Error commit() const = 0; }; } // end namespace codeview diff --git a/include/llvm/DebugInfo/CodeView/StreamRef.h b/include/llvm/DebugInfo/CodeView/StreamRef.h index f6e3da59c28..b581c120cca 100644 --- a/include/llvm/DebugInfo/CodeView/StreamRef.h +++ b/include/llvm/DebugInfo/CodeView/StreamRef.h @@ -60,6 +60,8 @@ public: uint32_t getLength() const override { return Length; } + Error commit() const override { return Stream->commit(); } + StreamRef drop_front(uint32_t N) const { if (!Stream) return StreamRef(); diff --git a/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h b/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h index 8ee0ab66446..ccb6478e280 100644 --- a/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h +++ b/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h @@ -36,6 +36,7 @@ public: Error writeBytes(uint32_t Offset, ArrayRef Buffer) const override; uint32_t getLength() const override; + Error commit() const override; uint32_t getNumBytesCopied() const; diff --git a/include/llvm/DebugInfo/PDB/Raw/PDBFile.h b/include/llvm/DebugInfo/PDB/Raw/PDBFile.h index 966716fbc56..69a457429da 100644 --- a/include/llvm/DebugInfo/PDB/Raw/PDBFile.h +++ b/include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -115,15 +115,17 @@ public: Expected getPDBSymbolStream(); Expected getStringTable(); - void setSuperBlock(const SuperBlock *Block); + Error setSuperBlock(const SuperBlock *Block); void setStreamSizes(ArrayRef Sizes); - void setStreamMap(ArrayRef> Blocks); - void commit(); + void setStreamMap(ArrayRef Directory, + std::vector> &Streams); + Error commit(); private: std::unique_ptr Buffer; const PDBFile::SuperBlock *SB; ArrayRef StreamSizes; + ArrayRef DirectoryBlocks; std::vector> StreamMap; std::unique_ptr Info; diff --git a/lib/DebugInfo/CodeView/ByteStream.cpp b/lib/DebugInfo/CodeView/ByteStream.cpp index 83b2f8ec307..2c43bc6958d 100644 --- a/lib/DebugInfo/CodeView/ByteStream.cpp +++ b/lib/DebugInfo/CodeView/ByteStream.cpp @@ -62,6 +62,10 @@ template uint32_t ByteStream::getLength() const { return Data.size(); } +template Error ByteStream::commit() const { + return Error::success(); +} + template StringRef ByteStream::str() const { const char *CharData = reinterpret_cast(Data.data()); return StringRef(CharData, Data.size()); diff --git a/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp b/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp index 36f8ead090a..3463871227b 100644 --- a/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp +++ b/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp @@ -147,6 +147,8 @@ Error MappedBlockStream::readLongestContiguousChunk( uint32_t MappedBlockStream::getLength() const { return Data->getLength(); } +Error MappedBlockStream::commit() const { return Error::success(); } + bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, ArrayRef &Buffer) const { // Attempt to fulfill the request with a reference directly into the stream. diff --git a/lib/DebugInfo/PDB/Raw/PDBFile.cpp b/lib/DebugInfo/PDB/Raw/PDBFile.cpp index 1385e91f7ac..cf0ef688b66 100644 --- a/lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ b/lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/StreamInterface.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h" #include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" @@ -107,44 +108,12 @@ Error PDBFile::parseFileHeaders() { "Does not contain superblock"); } - // Check the magic bytes. - if (memcmp(SB->MagicBytes, MsfMagic, sizeof(MsfMagic)) != 0) - return make_error(raw_error_code::corrupt_file, - "MSF magic header doesn't match"); - - // We don't support blocksizes which aren't a multiple of four bytes. - if (SB->BlockSize % sizeof(support::ulittle32_t) != 0) - return make_error(raw_error_code::corrupt_file, - "Block size is not multiple of 4."); - - switch (SB->BlockSize) { - case 512: case 1024: case 2048: case 4096: - break; - default: - // An invalid block size suggests a corrupt PDB file. - return make_error(raw_error_code::corrupt_file, - "Unsupported block size."); - } - - if (Buffer->getLength() % SB->BlockSize != 0) - return make_error(raw_error_code::corrupt_file, - "File size is not a multiple of block size"); - - // We don't support directories whose sizes aren't a multiple of four bytes. - if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) - return make_error(raw_error_code::corrupt_file, - "Directory size is not multiple of 4."); - - // The number of blocks which comprise the directory is a simple function of - // the number of bytes it contains. - uint64_t NumDirectoryBlocks = getNumDirectoryBlocks(); + if (auto EC = setSuperBlock(SB)) + return EC; - // The directory, as we understand it, is a block which consists of a list of - // block numbers. It is unclear what would happen if the number of blocks - // couldn't fit on a single block. - if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t)) - return make_error(raw_error_code::corrupt_file, - "Too many directory blocks."); + Reader.setOffset(getBlockMapOffset()); + if (auto EC = Reader.readArray(DirectoryBlocks, getNumDirectoryBlocks())) + return EC; return Error::success(); } @@ -195,12 +164,7 @@ Error PDBFile::parseStreamData() { } llvm::ArrayRef PDBFile::getDirectoryBlockArray() const { - StreamReader Reader(*Buffer); - Reader.setOffset(getBlockMapOffset()); - llvm::ArrayRef Result; - if (auto EC = Reader.readArray(Result, getNumDirectoryBlocks())) - consumeError(std::move(EC)); - return Result; + return DirectoryBlocks; } Expected PDBFile::getPDBInfoStream() { @@ -323,14 +287,89 @@ Expected PDBFile::getStringTable() { return *StringTable; } -void PDBFile::setSuperBlock(const SuperBlock *Block) { SB = Block; } +Error PDBFile::setSuperBlock(const SuperBlock *Block) { + SB = Block; + + // Check the magic bytes. + if (memcmp(SB->MagicBytes, MsfMagic, sizeof(MsfMagic)) != 0) + return make_error(raw_error_code::corrupt_file, + "MSF magic header doesn't match"); + + // We don't support blocksizes which aren't a multiple of four bytes. + if (SB->BlockSize % sizeof(support::ulittle32_t) != 0) + return make_error(raw_error_code::corrupt_file, + "Block size is not multiple of 4."); + + switch (SB->BlockSize) { + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + // An invalid block size suggests a corrupt PDB file. + return make_error(raw_error_code::corrupt_file, + "Unsupported block size."); + } + + if (Buffer->getLength() % SB->BlockSize != 0) + return make_error(raw_error_code::corrupt_file, + "File size is not a multiple of block size"); + + // We don't support directories whose sizes aren't a multiple of four bytes. + if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) + return make_error(raw_error_code::corrupt_file, + "Directory size is not multiple of 4."); + + // The number of blocks which comprise the directory is a simple function of + // the number of bytes it contains. + uint64_t NumDirectoryBlocks = getNumDirectoryBlocks(); + + // The directory, as we understand it, is a block which consists of a list of + // block numbers. It is unclear what would happen if the number of blocks + // couldn't fit on a single block. + if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t)) + return make_error(raw_error_code::corrupt_file, + "Too many directory blocks."); + + return Error::success(); +} void PDBFile::setStreamSizes(ArrayRef Sizes) { StreamSizes = Sizes; } -void PDBFile::setStreamMap(ArrayRef> Blocks) { - StreamMap = Blocks; +void PDBFile::setStreamMap( + ArrayRef Directory, + std::vector> &Streams) { + DirectoryBlocks = Directory; + StreamMap = Streams; } -void PDBFile::commit() {} +Error PDBFile::commit() { + StreamWriter Writer(*Buffer); + + if (auto EC = Writer.writeObject(*SB)) + return EC; + Writer.setOffset(getBlockMapOffset()); + if (auto EC = Writer.writeArray(DirectoryBlocks)) + return EC; + + auto DS = MappedBlockStream::createDirectoryStream(*this); + if (!DS) + return DS.takeError(); + auto DirStream = std::move(*DS); + StreamWriter DW(*DirStream); + if (auto EC = DW.writeInteger(this->getNumStreams())) + return EC; + + if (auto EC = DW.writeArray(StreamSizes)) + return EC; + + for (const auto &Blocks : StreamMap) { + if (auto EC = DW.writeArray(Blocks)) + return EC; + } + + return Buffer->commit(); +} \ No newline at end of file diff --git a/test/DebugInfo/PDB/pdbdump-write.test b/test/DebugInfo/PDB/pdbdump-write.test new file mode 100644 index 00000000000..46ee0ba10b6 --- /dev/null +++ b/test/DebugInfo/PDB/pdbdump-write.test @@ -0,0 +1,13 @@ +; This testcase checks to make sure that we can write PDB files. It +; works by first reading a known good PDB file and dumping the contents +; to YAML. Then it tries to reconstruct as much of the original PDB as +; possible, although depending on what flags are specified when generating +; the YAML, the PDB might be missing data required for any standard tool +; to recognize it. Finally, it dumps the same set of fields from the newly +; constructed PDB to YAML, and verifies that the YAML is the same as the +; original YAML generated from the good PDB. +; +; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory %p/Inputs/empty.pdb > %t.1 +; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1 +; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory %t.2 > %t.3 +; RUN: diff %t.1 %t.3 diff --git a/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/tools/llvm-pdbdump/YAMLOutputStyle.cpp index cf386bf5486..d4a3582f261 100644 --- a/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ b/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -12,8 +12,8 @@ #include "PdbYaml.h" #include "llvm-pdbdump.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" using namespace llvm; using namespace llvm::pdb; @@ -44,7 +44,8 @@ Error YAMLOutputStyle::dumpFileHeaders() { Obj.Headers.DirectoryBlocks.assign(Blocks.begin(), Blocks.end()); Obj.Headers.NumDirectoryBlocks = File.getNumDirectoryBlocks(); Obj.Headers.SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes(); - Obj.Headers.NumStreams = opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0; + Obj.Headers.NumStreams = + opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0; Obj.Headers.SuperBlock.Unknown0 = File.getUnknown0(); Obj.Headers.SuperBlock.Unknown1 = File.getUnknown1(); Obj.Headers.FileSize = File.getFileSize(); diff --git a/tools/llvm-pdbdump/YAMLOutputStyle.h b/tools/llvm-pdbdump/YAMLOutputStyle.h index a2c208d03f1..e2d39411fe6 100644 --- a/tools/llvm-pdbdump/YAMLOutputStyle.h +++ b/tools/llvm-pdbdump/YAMLOutputStyle.h @@ -26,7 +26,6 @@ public: Error dump() override; private: - Error dumpFileHeaders(); Error dumpStreamMetadata(); Error dumpStreamDirectory(); diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp index a92e59bc811..94e25004fce 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -72,6 +72,12 @@ public: Buffer->getBufferEnd())), FileBuffer(std::move(Buffer)) {} + Error commit() const override { + if (FileBuffer->commit()) + return llvm::make_error(raw_error_code::not_writable); + return Error::success(); + } + private: std::unique_ptr FileBuffer; }; @@ -83,7 +89,9 @@ cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file"); cl::SubCommand PrettySubcommand("pretty", "Dump semantic information about types and symbols"); -cl::SubCommand YamlToPdbSubcommand("yaml2pdb", "Generate a PDB file from a YAML description"); +cl::SubCommand + YamlToPdbSubcommand("yaml2pdb", + "Generate a PDB file from a YAML description"); cl::SubCommand PdbToYamlSubcommand("pdb2yaml", "Generate a detailed YAML description of a PDB File"); @@ -200,8 +208,8 @@ cl::opt DumpModules("modules", cl::desc("dump compiland information"), cl::opt DumpModuleFiles("module-files", cl::desc("dump file information"), cl::cat(FileOptions), cl::sub(RawSubcommand)); cl::opt DumpLineInfo("line-info", - cl::desc("dump file and line information"), - cl::cat(FileOptions), cl::sub(RawSubcommand)); + cl::desc("dump file and line information"), + cl::cat(FileOptions), cl::sub(RawSubcommand)); // SYMBOL OPTIONS cl::opt DumpModuleSyms("module-syms", cl::desc("dump module symbols"), @@ -216,29 +224,25 @@ cl::opt // MISCELLANEOUS OPTIONS cl::opt DumpSectionContribs("section-contribs", cl::desc("dump section contributions"), - cl::cat(MiscOptions), - cl::sub(RawSubcommand)); + cl::cat(MiscOptions), cl::sub(RawSubcommand)); cl::opt DumpSectionMap("section-map", cl::desc("dump section map"), cl::cat(MiscOptions), cl::sub(RawSubcommand)); cl::opt DumpSectionHeaders("section-headers", cl::desc("dump section headers"), - cl::cat(MiscOptions), - cl::sub(RawSubcommand)); -cl::opt DumpFpo("fpo", cl::desc("dump FPO records"), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); + cl::cat(MiscOptions), cl::sub(RawSubcommand)); +cl::opt DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions), + cl::sub(RawSubcommand)); cl::opt DumpStreamDataIdx("stream", cl::desc("dump stream data"), - cl::cat(MiscOptions), - cl::sub(RawSubcommand)); + cl::cat(MiscOptions), + cl::sub(RawSubcommand)); cl::opt DumpStreamDataName("stream-name", - cl::desc("dump stream data"), - cl::cat(MiscOptions), - cl::sub(RawSubcommand)); + cl::desc("dump stream data"), + cl::cat(MiscOptions), + cl::sub(RawSubcommand)); -cl::opt - RawAll("all", - cl::desc("Implies most other options."), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); +cl::opt RawAll("all", cl::desc("Implies most other options."), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); cl::list InputFilenames(cl::Positional, cl::desc(""), @@ -256,8 +260,14 @@ cl::list InputFilename(cl::Positional, } namespace pdb2yaml { - cl::opt StreamMetadata("stream-metadata", cl::desc("Dump the number of streams and each stream's size"), cl::sub(PdbToYamlSubcommand)); - cl::opt StreamDirectory("stream-directory", cl::desc("Dump each stream's block map (implies -stream-metadata)"), cl::sub(PdbToYamlSubcommand)); +cl::opt StreamMetadata( + "stream-metadata", + cl::desc("Dump the number of streams and each stream's size"), + cl::sub(PdbToYamlSubcommand)); +cl::opt StreamDirectory( + "stream-directory", + cl::desc("Dump each stream's block map (implies -stream-metadata)"), + cl::sub(PdbToYamlSubcommand)); cl::list InputFilename(cl::Positional, cl::desc(""), cl::Required, @@ -291,19 +301,19 @@ static void yamlToPdb(StringRef Path) { auto FileByteStream = llvm::make_unique(std::move(*OutFileOrError)); PDBFile Pdb(std::move(FileByteStream)); - Pdb.setSuperBlock(&YamlObj.Headers.SuperBlock); + ExitOnErr(Pdb.setSuperBlock(&YamlObj.Headers.SuperBlock)); if (YamlObj.StreamMap.hasValue()) { std::vector> StreamMap; for (auto &E : YamlObj.StreamMap.getValue()) { StreamMap.push_back(E.Blocks); } - Pdb.setStreamMap(StreamMap); + Pdb.setStreamMap(YamlObj.Headers.DirectoryBlocks, StreamMap); } if (YamlObj.StreamSizes.hasValue()) { Pdb.setStreamSizes(YamlObj.StreamSizes.getValue()); } - Pdb.commit(); + ExitOnErr(Pdb.commit()); } static void dumpRaw(StringRef Path) { -- 2.50.0