]> granicus.if.org Git - llvm/commitdiff
[pdb] Write the module info and symbol record streams.
authorZachary Turner <zturner@google.com>
Wed, 15 Mar 2017 22:18:53 +0000 (22:18 +0000)
committerZachary Turner <zturner@google.com>
Wed, 15 Mar 2017 22:18:53 +0000 (22:18 +0000)
Previously we did not have support for writing detailed
module information for each module, as well as the symbol
records.  This patch adds support for this, and in doing
so enables the ability to construct minimal PDBs from
just a few lines of YAML.  A test is added to illustrate
this functionality.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297900 91177308-0d34-0410-b5e6-96231b3b80d8

17 files changed:
include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h
include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h [new file with mode: 0644]
include/llvm/DebugInfo/PDB/Native/RawError.h
include/llvm/Support/BinaryStreamWriter.h
lib/DebugInfo/PDB/CMakeLists.txt
lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp [new file with mode: 0644]
lib/DebugInfo/PDB/Native/RawError.cpp
lib/Support/BinaryStreamWriter.cpp
test/DebugInfo/PDB/Inputs/one-symbol.yaml [new file with mode: 0644]
test/DebugInfo/PDB/pdb-minimal-construct.test [new file with mode: 0644]
test/DebugInfo/PDB/pdbdump-yaml-types.test
tools/llvm-pdbdump/PdbYaml.cpp
tools/llvm-pdbdump/PdbYaml.h
tools/llvm-pdbdump/YAMLOutputStyle.cpp
tools/llvm-pdbdump/llvm-pdbdump.cpp
tools/llvm-pdbdump/llvm-pdbdump.h

index 23c74ae8de1629484f197b965de6a7e0dd45f576..16426bd93847a685e5eb34b0ba32433377919028 100644 (file)
@@ -31,11 +31,13 @@ struct coff_section;
 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 @@ public:
 
   uint32_t calculateSerializedLength() const;
 
-  Error addModuleInfo(StringRef ObjFile, StringRef Module);
+  Expected<ModInfoBuilder &> 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 @@ private:
   Error generateModiSubstream();
   Error generateFileInfoSubstream();
 
-  struct ModuleInfo {
-    std::vector<StringRef> SourceFiles;
-    StringRef Obj;
-    StringRef Mod;
-  };
-
   msf::MSFBuilder &Msf;
   BumpPtrAllocator &Allocator;
 
@@ -107,13 +103,12 @@ private:
 
   const DbiStreamHeader *Header;
 
-  StringMap<std::unique_ptr<ModuleInfo>> ModuleInfos;
-  std::vector<ModuleInfo *> ModuleInfoList;
+  StringMap<std::unique_ptr<ModInfoBuilder>> ModiMap;
+  std::vector<ModInfoBuilder *> ModiList;
 
   StringMap<uint32_t> SourceFileNames;
 
   WritableBinaryStreamRef NamesBuffer;
-  MutableBinaryByteStream ModInfoBuffer;
   MutableBinaryByteStream FileInfoBuffer;
   ArrayRef<SectionContrib> SectionContribs;
   ArrayRef<SecMapEntry> SectionMap;
diff --git a/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h b/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h
new file mode 100644 (file)
index 0000000..605fd24
--- /dev/null
@@ -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 <cstdint>
+#include <string>
+#include <vector>
+
+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<std::string> 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<std::string> SourceFiles;
+  std::vector<codeview::CVSymbol> Symbols;
+  ModuleInfoHeader Layout;
+};
+
+} // end namespace pdb
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_PDB_RAW_MODINFOBUILDER_H
index f96b8066bbe56dce7c1a4bf3a8592aaa1a66a895..3624a7682e3876dcd269550e7939bee0d15f238a 100644 (file)
@@ -28,6 +28,7 @@ enum class raw_error_code {
   duplicate_entry,
   no_entry,
   not_writable,
+  stream_too_long,
   invalid_tpi_hash,
 };
 
index acc979c66d5442afe355d3d7b08d543143a1b14e..64f26b24543df3a545991993e1b8a9b8af54e176 100644 (file)
@@ -154,6 +154,7 @@ public:
   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 1b9dd2b651dc20a84480ad5d42d2ac9023f982d8..448b6a369b079cc677263ed25d4e053b0d97b089 100644 (file)
@@ -38,6 +38,7 @@ add_pdb_impl_folder(Native
   Native/InfoStream.cpp
   Native/InfoStreamBuilder.cpp
   Native/ModInfo.cpp
+  Native/ModInfoBuilder.cpp
   Native/ModStream.cpp
   Native/NativeCompilandSymbol.cpp
   Native/NativeEnumModules.cpp
index efd7f127a191dd2858fac971125a5357bb24311f..a203aea60fe7ae0f18d23aca7d721452f01ed423 100644 (file)
@@ -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::codeview;
 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 @@ uint32_t DbiStreamBuilder::calculateSerializedLength() const {
          calculateSectionMapStreamSize() + calculateDbgStreamsSize();
 }
 
-Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) {
-  auto Entry = llvm::make_unique<ModuleInfo>();
-  ModuleInfo *M = Entry.get();
-  Entry->Mod = Module;
-  Entry->Obj = ObjFile;
-  auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry)));
+Expected<ModInfoBuilder &>
+DbiStreamBuilder::addModuleInfo(StringRef ModuleName) {
+  uint32_t Index = ModiList.size();
+  auto MIB = llvm::make_unique<ModInfoBuilder>(ModuleName, Index, Msf);
+  auto M = MIB.get();
+  auto Result = ModiMap.insert(std::make_pair(ModuleName, std::move(MIB)));
+
   if (!Result.second)
     return make_error<RawError>(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<RawError>(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 DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
   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 @@ uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const {
   return DbgStreams.size() * sizeof(uint16_t);
 }
 
-Error DbiStreamBuilder::generateModiSubstream() {
-  uint32_t Size = calculateModiSubstreamSize();
-  auto Data = Allocator.Allocate<uint8_t>(Size);
-
-  ModInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(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<RawError>(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 @@ Error DbiStreamBuilder::generateFileInfoSubstream() {
       WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset);
   BinaryStreamWriter MetadataWriter(MetadataBuffer);
 
-  uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModuleInfos.size());
+  uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size());
   uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size());
   if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
     return EC;
@@ -197,8 +169,8 @@ Error DbiStreamBuilder::generateFileInfoSubstream() {
     if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
       return EC;
   }
-  for (const auto MI : ModuleInfoList) {
-    FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
+  for (const auto &MI : ModiList) {
+    FileCount = static_cast<uint16_t>(MI->source_files().size());
     if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
       return EC;
   }
@@ -215,8 +187,8 @@ Error DbiStreamBuilder::generateFileInfoSubstream() {
       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<RawError>(raw_error_code::no_entry,
@@ -242,13 +214,13 @@ Error DbiStreamBuilder::finalize() {
   if (Header)
     return Error::success();
 
-  DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
+  for (auto &MI : ModiList)
+    MI->finalize();
 
-  if (auto EC = generateModiSubstream())
-    return EC;
   if (auto EC = generateFileInfoSubstream())
     return EC;
 
+  DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
   H->VersionHeader = *VerHeader;
   H->VersionSignature = -1;
   H->Age = Age;
@@ -260,7 +232,7 @@ Error DbiStreamBuilder::finalize() {
 
   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::finalize() {
 }
 
 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 @@ std::vector<SecMapEntry> DbiStreamBuilder::createSectionMap(
 }
 
 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 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
     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;
diff --git a/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp b/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp
new file mode 100644 (file)
index 0000000..73c45a9
--- /dev/null
@@ -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<CVSymbol> {
+  static size_t length(const CVSymbol &Item) { return Item.RecordData.size(); }
+
+  static ArrayRef<uint8_t> 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<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
+      return EC;
+    BinaryItemStream<CVSymbol> 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<uint32_t>(0))
+      return EC;
+    if (SymbolWriter.bytesRemaining() > 0)
+      return make_error<RawError>(raw_error_code::stream_too_long);
+  }
+  return Error::success();
+}
index aa126bb8f1ad864bde12665256ae041646c1b497..548289fff3dfeee12c4192e025dce10245ece939 100644 (file)
@@ -38,6 +38,8 @@ public:
       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 487bcdc5a4daffb20f3fa0140e9068a8ae7f70b3..d60b75642d0f148cd59a21f09333beb2da087943 100644 (file)
@@ -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 @@ Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
   }
   return Error::success();
 }
+
+Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
+  uint32_t NewOffset = alignTo(Offset, Align);
+  if (NewOffset > getLength())
+    return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+  Offset = NewOffset;
+  return Error::success();
+}
diff --git a/test/DebugInfo/PDB/Inputs/one-symbol.yaml b/test/DebugInfo/PDB/Inputs/one-symbol.yaml
new file mode 100644 (file)
index 0000000..5728f05
--- /dev/null
@@ -0,0 +1,11 @@
+---\r
+DbiStream:\r
+  Modules:\r
+    - Module:          one-symbol.yaml\r
+      Modi:\r
+        Records:\r
+          - Kind:            S_OBJNAME\r
+            ObjNameSym:\r
+              Signature:       0\r
+              ObjectName:      'c:\foo\one-symbol.yaml'\r
+...\r
diff --git a/test/DebugInfo/PDB/pdb-minimal-construct.test b/test/DebugInfo/PDB/pdb-minimal-construct.test
new file mode 100644 (file)
index 0000000..d75c510
--- /dev/null
@@ -0,0 +1,11 @@
+; This testcase verifies that we can produce a minimal PDB, while\r
+; serving as an example for how to construct a minimal PDB for other\r
+; testcases.  It takes as input a small fragment of hand-written yaml\r
+; that specifies nothing about the PDB other than a definition of one\r
+; symbol that it contains.  Then it produces a PDB, and uses the\r
+; resulting PDB to go back to yaml, and verify that the resulting yaml\r
+; is identical.\r
+\r
+; RUN: llvm-pdbdump yaml2pdb -pdb=%t.pdb %p/Inputs/one-symbol.yaml\r
+; RUN: llvm-pdbdump pdb2yaml -minimal -dbi-module-syms -no-file-headers %t.pdb > %t.pdb.yaml\r
+; RUN: diff -b %p/Inputs/one-symbol.yaml %t.pdb.yaml\r
index 25895f3de2f3fc6307f666d4613d928d7ee7c03c..7e6fcc1ca42010b5792a507b4d745fd15dd7d431 100644 (file)
@@ -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 9877af0a07c406f3cc8dfbe6a5ccec820bd32fb4..21f5a775c55a30d4118f461bba7f50a98c60c304 100644 (file)
@@ -158,11 +158,11 @@ void MappingTraits<PdbObject>::mapping(IO &IO, PdbObject &Obj) {
 }
 
 void MappingTraits<MSFHeaders>::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<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) {
@@ -170,12 +170,13 @@ void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) {
     ::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<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) {
@@ -183,26 +184,26 @@ void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) {
 }
 
 void MappingTraits<PdbInfoStream>::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<PdbDbiStream, pdb::yaml::SerializationContext>::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<PdbTpiStream, pdb::yaml::SerializationContext>::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<PdbSymbolRecord, pdb::yaml::SerializationContext>::map
 }
 
 void MappingContextTraits<PdbModiStream, pdb::yaml::SerializationContext>::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<PdbDbiModuleInfo, pdb::yaml::SerializationContext>::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 3b9b8e5c8134976c17f9f0ed4362580c68348622..7632d7e0b605a6a8a789b7a7d0670b436d7164d7 100644 (file)
@@ -32,10 +32,10 @@ struct SerializationContext;
 
 struct MSFHeaders {
   msf::SuperBlock SuperBlock;
-  uint32_t NumDirectoryBlocks;
+  uint32_t NumDirectoryBlocks = 0;
   std::vector<uint32_t> DirectoryBlocks;
-  uint32_t NumStreams;
-  uint32_t FileSize;
+  uint32_t NumStreams = 0;
+  uint32_t FileSize = 0;
 };
 
 struct StreamBlockList {
@@ -48,9 +48,9 @@ struct NamedStreamMapping {
 };
 
 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<NamedStreamMapping> NamedStreams;
 };
@@ -72,13 +72,13 @@ struct PdbDbiModuleInfo {
 };
 
 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<PdbDbiModuleInfo> ModInfos;
 };
@@ -92,7 +92,7 @@ struct PdbTpiFieldListRecord {
 };
 
 struct PdbTpiStream {
-  PdbRaw_TpiVer Version;
+  PdbRaw_TpiVer Version = PdbTpiV80;
   std::vector<PdbTpiRecord> Records;
 };
 
index 065a60d32a8cc23d6c3be1b52444661580f29ab6..fab3760fabb23d1a4c5bd8a8ab34fe0d5416eb31 100644 (file)
@@ -24,7 +24,9 @@ using namespace llvm;
 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 c4bdab2606791ac8897190f9c40f2b7f4df6496d..7dd4eec1fe5b2dfd50b8b208a8be235cf14bd087 100644 (file)
@@ -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"
@@ -293,6 +294,9 @@ cl::opt<bool>
                   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<bool> Minimal("minimal",
+                      cl::desc("Don't write fields with default values"),
+                      cl::sub(PdbToYamlSubcommand), cl::init(false));
 
 cl::opt<bool> StreamMetadata(
     "stream-metadata",
@@ -367,13 +371,13 @@ static void yamlToPdb(StringRef Path) {
   llvm::yaml::Input In(Buffer->getBuffer());
   pdb::yaml::PdbObject YamlObj(Allocator);
   In >> YamlObj;
-  if (!YamlObj.Headers.hasValue())
-    ExitOnErr(make_error<GenericError>(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
@@ -389,43 +393,51 @@ static void yamlToPdb(StringRef Path) {
       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));
 }
index cdebc20fb5f1bf026c3adb1eb505cddd8380ffc3..0cf31c8163b8816baaa15d0ac88e10c93131b66d 100644 (file)
@@ -73,6 +73,7 @@ extern llvm::cl::opt<bool> Pedantic;
 
 namespace pdb2yaml {
 extern llvm::cl::opt<bool> NoFileHeaders;
+extern llvm::cl::opt<bool> Minimal;
 extern llvm::cl::opt<bool> StreamMetadata;
 extern llvm::cl::opt<bool> StreamDirectory;
 extern llvm::cl::opt<bool> StringTable;