]> granicus.if.org Git - llvm/commitdiff
[pdb] Re-add code to write PDB files.
authorZachary Turner <zturner@google.com>
Thu, 30 Jun 2016 17:43:00 +0000 (17:43 +0000)
committerZachary Turner <zturner@google.com>
Thu, 30 Jun 2016 17:43:00 +0000 (17:43 +0000)
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

12 files changed:
include/llvm/DebugInfo/CodeView/ByteStream.h
include/llvm/DebugInfo/CodeView/StreamInterface.h
include/llvm/DebugInfo/CodeView/StreamRef.h
include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h
include/llvm/DebugInfo/PDB/Raw/PDBFile.h
lib/DebugInfo/CodeView/ByteStream.cpp
lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp
lib/DebugInfo/PDB/Raw/PDBFile.cpp
test/DebugInfo/PDB/pdbdump-write.test [new file with mode: 0644]
tools/llvm-pdbdump/YAMLOutputStyle.cpp
tools/llvm-pdbdump/YAMLOutputStyle.h
tools/llvm-pdbdump/llvm-pdbdump.cpp

index ec841d9f45e5f9c7fbea1c4d04742d0892f02d85..f398c93723e7a7585a2f04f0a93fc8e95c54b3f0 100644 (file)
@@ -40,6 +40,8 @@ public:
 
   uint32_t getLength() const override;
 
+  Error commit() const override;
+
   ArrayRef<uint8_t> data() const { return Data; }
   StringRef str() const;
 
index a8b9dbfc2b6f8a890991c7bca5b04471527ee948..241aec4578700459e9c3897e752c0a107570722d 100644 (file)
@@ -45,6 +45,8 @@ public:
   virtual Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const = 0;
 
   virtual uint32_t getLength() const = 0;
+
+  virtual Error commit() const = 0;
 };
 
 } // end namespace codeview
index f6e3da59c28c2d3657689841837e87683023a3c4..b581c120cca64dfeab98004f18eda33c52963ae6 100644 (file)
@@ -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();
index 8ee0ab66446a938e23a8aae3d554a1fa14fa3db5..ccb6478e280f0751bd80dc76e0813ebeb2fca6c7 100644 (file)
@@ -36,6 +36,7 @@ public:
   Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) const override;
 
   uint32_t getLength() const override;
+  Error commit() const override;
 
   uint32_t getNumBytesCopied() const;
 
index 966716fbc56c474f561530f90dec4f7cb9bf56b1..69a457429da63dc9f723422a979cf4e11e4ac4d6 100644 (file)
@@ -115,15 +115,17 @@ public:
   Expected<SymbolStream &> getPDBSymbolStream();
   Expected<NameHashTable &> getStringTable();
 
-  void setSuperBlock(const SuperBlock *Block);
+  Error setSuperBlock(const SuperBlock *Block);
   void setStreamSizes(ArrayRef<support::ulittle32_t> Sizes);
-  void setStreamMap(ArrayRef<ArrayRef<support::ulittle32_t>> Blocks);
-  void commit();
+  void setStreamMap(ArrayRef<support::ulittle32_t> Directory,
+                    std::vector<ArrayRef<support::ulittle32_t>> &Streams);
+  Error commit();
 
 private:
   std::unique_ptr<codeview::StreamInterface> Buffer;
   const PDBFile::SuperBlock *SB;
   ArrayRef<support::ulittle32_t> StreamSizes;
+  ArrayRef<support::ulittle32_t> DirectoryBlocks;
   std::vector<ArrayRef<support::ulittle32_t>> StreamMap;
 
   std::unique_ptr<InfoStream> Info;
index 83b2f8ec30754a90616bd0b8cec40d8ca2eaacb6..2c43bc6958d26aaa969e5ba43d36725b87e7fc3b 100644 (file)
@@ -62,6 +62,10 @@ template <bool Writable> uint32_t ByteStream<Writable>::getLength() const {
   return Data.size();
 }
 
+template <bool Writable> Error ByteStream<Writable>::commit() const {
+  return Error::success();
+}
+
 template <bool Writable> StringRef ByteStream<Writable>::str() const {
   const char *CharData = reinterpret_cast<const char *>(Data.data());
   return StringRef(CharData, Data.size());
index 36f8ead090ae9e866573b6f2b4118aa3513b5420..3463871227bb0a30cd440454adefd38e625a414b 100644 (file)
@@ -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<uint8_t> &Buffer) const {
   // Attempt to fulfill the request with a reference directly into the stream.
index 1385e91f7ac66b79ac538567331ecef03c8b81ac..cf0ef688b66507db93f65c174a092278adf2695c 100644 (file)
@@ -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<RawError>(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<RawError>(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<RawError>(raw_error_code::corrupt_file,
-                                "Unsupported block size.");
-  }
-
-  if (Buffer->getLength() % SB->BlockSize != 0)
-    return make_error<RawError>(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<RawError>(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<RawError>(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<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
-  StreamReader Reader(*Buffer);
-  Reader.setOffset(getBlockMapOffset());
-  llvm::ArrayRef<support::ulittle32_t> Result;
-  if (auto EC = Reader.readArray(Result, getNumDirectoryBlocks()))
-    consumeError(std::move(EC));
-  return Result;
+  return DirectoryBlocks;
 }
 
 Expected<InfoStream &> PDBFile::getPDBInfoStream() {
@@ -323,14 +287,89 @@ Expected<NameHashTable &> 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<RawError>(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<RawError>(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<RawError>(raw_error_code::corrupt_file,
+                                "Unsupported block size.");
+  }
+
+  if (Buffer->getLength() % SB->BlockSize != 0)
+    return make_error<RawError>(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<RawError>(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<RawError>(raw_error_code::corrupt_file,
+                                "Too many directory blocks.");
+
+  return Error::success();
+}
 
 void PDBFile::setStreamSizes(ArrayRef<support::ulittle32_t> Sizes) {
   StreamSizes = Sizes;
 }
 
-void PDBFile::setStreamMap(ArrayRef<ArrayRef<support::ulittle32_t>> Blocks) {
-  StreamMap = Blocks;
+void PDBFile::setStreamMap(
+    ArrayRef<support::ulittle32_t> Directory,
+    std::vector<ArrayRef<support::ulittle32_t>> &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 (file)
index 0000000..46ee0ba
--- /dev/null
@@ -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
index cf386bf5486993db0859bcea6f234f6d32e7920a..d4a3582f26191976b1dcd1cb1bb52b2d19339fbc 100644 (file)
@@ -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();
index a2c208d03f14a3b321cbf0fb92a4e3af6364e23a..e2d39411fe638f596b7defa0c483b81a594ce8e7 100644 (file)
@@ -26,7 +26,6 @@ public:
   Error dump() override;
 
 private:
-
   Error dumpFileHeaders();
   Error dumpStreamMetadata();
   Error dumpStreamDirectory();
index a92e59bc81115a0f0b5e3962e06ac1a49f9fd11c..94e25004fce21752fe938563243170118ef841d7 100644 (file)
@@ -72,6 +72,12 @@ public:
                                             Buffer->getBufferEnd())),
         FileBuffer(std::move(Buffer)) {}
 
+  Error commit() const override {
+    if (FileBuffer->commit())
+      return llvm::make_error<RawError>(raw_error_code::not_writable);
+    return Error::success();
+  }
+
 private:
   std::unique_ptr<FileOutputBuffer> 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<bool> DumpModules("modules", cl::desc("dump compiland information"),
 cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
                               cl::cat(FileOptions), cl::sub(RawSubcommand));
 cl::opt<bool> 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<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
@@ -216,29 +224,25 @@ cl::opt<bool>
 // MISCELLANEOUS OPTIONS
 cl::opt<bool> DumpSectionContribs("section-contribs",
                                   cl::desc("dump section contributions"),
-                                  cl::cat(MiscOptions),
-                                  cl::sub(RawSubcommand));
+                                  cl::cat(MiscOptions), cl::sub(RawSubcommand));
 cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
                              cl::cat(MiscOptions), cl::sub(RawSubcommand));
 cl::opt<bool> DumpSectionHeaders("section-headers",
                                  cl::desc("dump section headers"),
-                                 cl::cat(MiscOptions),
-                                 cl::sub(RawSubcommand));
-cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"),
-                      cl::cat(MiscOptions), cl::sub(RawSubcommand));
+                                 cl::cat(MiscOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions),
+                      cl::sub(RawSubcommand));
 
 cl::opt<std::string> DumpStreamDataIdx("stream", cl::desc("dump stream data"),
-  cl::cat(MiscOptions),
-  cl::sub(RawSubcommand));
+                                       cl::cat(MiscOptions),
+                                       cl::sub(RawSubcommand));
 cl::opt<std::string> 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<bool>
-    RawAll("all",
-           cl::desc("Implies most other options."),
-           cl::cat(MiscOptions), cl::sub(RawSubcommand));
+cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
+                     cl::cat(MiscOptions), cl::sub(RawSubcommand));
 
 cl::list<std::string> InputFilenames(cl::Positional,
                                      cl::desc("<input PDB files>"),
@@ -256,8 +260,14 @@ cl::list<std::string> InputFilename(cl::Positional,
 }
 
 namespace pdb2yaml {
-  cl::opt<bool> StreamMetadata("stream-metadata", cl::desc("Dump the number of streams and each stream's size"), cl::sub(PdbToYamlSubcommand));
-  cl::opt<bool> StreamDirectory("stream-directory", cl::desc("Dump each stream's block map (implies -stream-metadata)"), cl::sub(PdbToYamlSubcommand));
+cl::opt<bool> StreamMetadata(
+    "stream-metadata",
+    cl::desc("Dump the number of streams and each stream's size"),
+    cl::sub(PdbToYamlSubcommand));
+cl::opt<bool> StreamDirectory(
+    "stream-directory",
+    cl::desc("Dump each stream's block map (implies -stream-metadata)"),
+    cl::sub(PdbToYamlSubcommand));
 
 cl::list<std::string> InputFilename(cl::Positional,
                                     cl::desc("<input PDB file>"), cl::Required,
@@ -291,19 +301,19 @@ static void yamlToPdb(StringRef Path) {
   auto FileByteStream =
       llvm::make_unique<FileBufferByteStream>(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<ArrayRef<support::ulittle32_t>> 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) {