[llvm] r281063 - [pdb] Write PDB TPI Stream from Yaml.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 9 10:46:18 PDT 2016


Author: zturner
Date: Fri Sep  9 12:46:17 2016
New Revision: 281063

URL: http://llvm.org/viewvc/llvm-project?rev=281063&view=rev
Log:
[pdb] Write PDB TPI Stream from Yaml.

This writes the full sequence of type records described in
Yaml to the TPI stream of the PDB file.

Reviewed By: rnk
Differential Revision: https://reviews.llvm.org/D24316

Added:
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h
    llvm/trunk/include/llvm/DebugInfo/MSF/SequencedItemStream.h
    llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h
    llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp
    llvm/trunk/tools/llvm-pdbdump/YamlSerializationContext.h
Modified:
    llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h
    llvm/trunk/include/llvm/DebugInfo/MSF/StreamArray.h
    llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h
    llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h
    llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawTypes.h
    llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h
    llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h
    llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
    llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
    llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
    llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt
    llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp
    llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp
    llvm/trunk/test/DebugInfo/PDB/pdbdump-readwrite.test
    llvm/trunk/test/DebugInfo/PDB/pdbdump-write.test
    llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.cpp
    llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.h
    llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp
    llvm/trunk/tools/llvm-pdbdump/PdbYaml.h
    llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp
    llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp
    llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h Fri Sep  9 12:46:17 2016
@@ -20,7 +20,8 @@ namespace codeview {
 
 class MemoryTypeTableBuilder : public TypeTableBuilder {
 public:
-  MemoryTypeTableBuilder() {}
+  explicit MemoryTypeTableBuilder(BumpPtrAllocator &Allocator)
+      : RecordStorage(Allocator) {}
 
   bool empty() const { return Records.empty(); }
 
@@ -33,12 +34,13 @@ public:
     }
   }
 
-protected:
   TypeIndex writeRecord(llvm::StringRef Data) override;
 
+  ArrayRef<StringRef> getRecords() const { return Records; }
+
 private:
   std::vector<StringRef> Records;
-  BumpPtrAllocator RecordStorage;
+  BumpPtrAllocator &RecordStorage;
   DenseMap<StringRef, TypeIndex> HashedRecords;
 };
 

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h Fri Sep  9 12:46:17 2016
@@ -47,6 +47,7 @@ public:
   llvm::StringRef str();
 
   uint64_t size() const { return Stream.tell(); }
+  TypeRecordKind kind() const { return Kind; }
 
   void truncate(uint64_t Size) {
     // This works because raw_svector_ostream is not buffered.
@@ -56,10 +57,12 @@ public:
 
   void reset(TypeRecordKind K) {
     Buffer.clear();
+    Kind = K;
     writeTypeRecordKind(K);
   }
 
 private:
+  TypeRecordKind Kind;
   llvm::SmallVector<char, 256> Buffer;
   llvm::raw_svector_ostream Stream;
   llvm::support::endian::Writer<llvm::support::endianness::little> Writer;

Added: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h?rev=281063&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h (added)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h Fri Sep  9 12:46:17 2016
@@ -0,0 +1,74 @@
+//===- TypeSerializationVisitor.h -------------------------------*- 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_CODEVIEW_TYPESERIALIZATIONVISITOR_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZATIONVISITOR_H
+
+#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+namespace codeview {
+
+class TypeSerializationVisitor : public TypeVisitorCallbacks {
+public:
+  TypeSerializationVisitor(FieldListRecordBuilder &FieldListBuilder,
+                           MemoryTypeTableBuilder &TypeTableBuilder)
+      : FieldListBuilder(FieldListBuilder), TypeTableBuilder(TypeTableBuilder) {
+  }
+
+  virtual Expected<TypeLeafKind> visitTypeBegin(const CVType &Record) override {
+    if (Record.Type == TypeLeafKind::LF_FIELDLIST)
+      FieldListBuilder.reset();
+    return Record.Type;
+  }
+
+  virtual Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override {
+    if (Record.Type == TypeLeafKind::LF_FIELDLIST)
+      TypeTableBuilder.writeFieldList(FieldListBuilder);
+    return Error::success();
+  }
+
+#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
+  virtual Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,            \
+                                 Name##Record &Record) override {              \
+    visitKnownRecordImpl(Record);                                              \
+    return Error::success();                                                   \
+  }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
+  virtual Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,            \
+                                 Name##Record &Record) override {              \
+    visitMemberRecordImpl(Record);                                             \
+    return Error::success();                                                   \
+  }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+
+private:
+  template <typename RecordKind> void visitKnownRecordImpl(RecordKind &Record) {
+    TypeTableBuilder.writeKnownType(Record);
+  }
+  template <typename RecordKind>
+  void visitMemberRecordImpl(RecordKind &Record) {
+    FieldListBuilder.writeMemberType(Record);
+  }
+
+  void visitKnownRecordImpl(FieldListRecord &FieldList) {}
+
+  FieldListRecordBuilder &FieldListBuilder;
+  MemoryTypeTableBuilder &TypeTableBuilder;
+};
+}
+}
+
+#endif

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h Fri Sep  9 12:46:17 2016
@@ -63,6 +63,11 @@ public:
   TypeIndex writeRecord(TypeRecordBuilder &builder);
 
   virtual TypeIndex writeRecord(llvm::StringRef record) = 0;
+
+  ArrayRef<TypeRecordKind> getRecordKinds() const { return RecordKinds; }
+
+private:
+  std::vector<TypeRecordKind> RecordKinds;
 };
 }
 }

Added: llvm/trunk/include/llvm/DebugInfo/MSF/SequencedItemStream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/MSF/SequencedItemStream.h?rev=281063&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/MSF/SequencedItemStream.h (added)
+++ llvm/trunk/include/llvm/DebugInfo/MSF/SequencedItemStream.h Fri Sep  9 12:46:17 2016
@@ -0,0 +1,91 @@
+//===- SequencedItemStream.h ------------------------------------*- 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_MSF_SEQUENCEDITEMSTREAM_H
+#define LLVM_DEBUGINFO_MSF_SEQUENCEDITEMSTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/MSF/MSFError.h"
+#include "llvm/DebugInfo/MSF/StreamInterface.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <memory>
+#include <type_traits>
+
+namespace llvm {
+namespace msf {
+template <typename T> struct SequencedItemTraits {
+  static size_t length(const T &Item) = delete;
+  static ArrayRef<uint8_t> bytes(const T &Item) = delete;
+};
+
+/// SequencedItemStream represents a sequence of objects stored in a
+/// standard container but for which it is useful to view as a stream of
+/// contiguous bytes.  An example of this might be if you have a std::vector
+/// of TPI records, where each record contains a byte sequence that
+/// represents that one record serialized, but where each consecutive item
+/// might not be allocated immediately after the previous item.  Using a
+/// SequencedItemStream, we can adapt the VarStreamArray class to trivially
+/// extract one item at a time, allowing the data to be used anywhere a
+/// VarStreamArray could be used.
+template <typename T, typename Traits = SequencedItemTraits<T>>
+class SequencedItemStream : public ReadableStream {
+public:
+  SequencedItemStream() {}
+
+  Error readBytes(uint32_t Offset, uint32_t Size,
+                  ArrayRef<uint8_t> &Buffer) const override {
+    auto ExpectedIndex = translateOffsetIndex(Offset);
+    if (!ExpectedIndex)
+      return ExpectedIndex.takeError();
+    const auto &Item = Items[*ExpectedIndex];
+    if (Size > Traits::length(Item))
+      return make_error<MSFError>(msf_error_code::insufficient_buffer);
+    Buffer = Traits::bytes(Item).take_front(Size);
+    return Error::success();
+  }
+
+  Error readLongestContiguousChunk(uint32_t Offset,
+                                   ArrayRef<uint8_t> &Buffer) const override {
+    auto ExpectedIndex = translateOffsetIndex(Offset);
+    if (!ExpectedIndex)
+      return ExpectedIndex.takeError();
+    Buffer = Traits::bytes(Items[*ExpectedIndex]);
+    return Error::success();
+  }
+
+  void setItems(ArrayRef<T> ItemArray) { Items = ItemArray; }
+
+  uint32_t getLength() const override {
+    uint32_t Size = 0;
+    for (const auto &Item : Items)
+      Size += Traits::length(Item);
+    return Size;
+  }
+
+private:
+  Expected<uint32_t> translateOffsetIndex(uint32_t Offset) const {
+    uint32_t CurrentOffset = 0;
+    uint32_t CurrentIndex = 0;
+    for (const auto &Item : Items) {
+      if (CurrentOffset >= Offset)
+        break;
+      CurrentOffset += Traits::length(Item);
+      ++CurrentIndex;
+    }
+    if (CurrentOffset != Offset)
+      return make_error<MSFError>(msf_error_code::insufficient_buffer);
+    return CurrentIndex;
+  }
+  ArrayRef<T> Items;
+};
+} // end namespace msf
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_SEQUENCEDITEMSTREAM_H

Modified: llvm/trunk/include/llvm/DebugInfo/MSF/StreamArray.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/MSF/StreamArray.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/MSF/StreamArray.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/MSF/StreamArray.h Fri Sep  9 12:46:17 2016
@@ -10,6 +10,7 @@
 #ifndef LLVM_DEBUGINFO_MSF_STREAMARRAY_H
 #define LLVM_DEBUGINFO_MSF_STREAMARRAY_H
 
+#include "llvm/DebugInfo/MSF/SequencedItemStream.h"
 #include "llvm/DebugInfo/MSF/StreamRef.h"
 #include "llvm/Support/Error.h"
 

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h Fri Sep  9 12:46:17 2016
@@ -92,6 +92,8 @@ public:
   Expected<SymbolStream &> getPDBSymbolStream();
   Expected<NameHashTable &> getStringTable();
 
+  BumpPtrAllocator &getAllocator() { return Allocator; }
+
 private:
   BumpPtrAllocator &Allocator;
 

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h Fri Sep  9 12:46:17 2016
@@ -28,6 +28,7 @@ class MSFBuilder;
 namespace pdb {
 class DbiStreamBuilder;
 class InfoStreamBuilder;
+class TpiStreamBuilder;
 
 class PDBFileBuilder {
 public:
@@ -40,6 +41,7 @@ public:
   msf::MSFBuilder &getMsfBuilder();
   InfoStreamBuilder &getInfoBuilder();
   DbiStreamBuilder &getDbiBuilder();
+  TpiStreamBuilder &getTpiBuilder();
 
   Expected<std::unique_ptr<PDBFile>>
   build(std::unique_ptr<msf::WritableStream> PdbFileBuffer);
@@ -54,6 +56,7 @@ private:
   std::unique_ptr<msf::MSFBuilder> Msf;
   std::unique_ptr<InfoStreamBuilder> Info;
   std::unique_ptr<DbiStreamBuilder> Dbi;
+  std::unique_ptr<TpiStreamBuilder> Tpi;
 };
 }
 }

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawTypes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawTypes.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawTypes.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawTypes.h Fri Sep  9 12:46:17 2016
@@ -266,6 +266,34 @@ struct PDB_UniqueId {
   char Guid[16];
 };
 
+// The header preceeding the global TPI stream.
+// This corresponds to `HDR` in PDB/dbi/tpi.h.
+struct TpiStreamHeader {
+  struct EmbeddedBuf {
+    support::little32_t Off;
+    support::ulittle32_t Length;
+  };
+
+  support::ulittle32_t Version;
+  support::ulittle32_t HeaderSize;
+  support::ulittle32_t TypeIndexBegin;
+  support::ulittle32_t TypeIndexEnd;
+  support::ulittle32_t TypeRecordBytes;
+
+  // The following members correspond to `TpiHash` in PDB/dbi/tpi.h.
+  support::ulittle16_t HashStreamIndex;
+  support::ulittle16_t HashAuxStreamIndex;
+  support::ulittle32_t HashKeySize;
+  support::ulittle32_t NumHashBuckets;
+
+  EmbeddedBuf HashValueBuffer;
+  EmbeddedBuf IndexOffsetBuffer;
+  EmbeddedBuf HashAdjBuffer;
+};
+
+const uint32_t MinTpiHashBuckets = 0x1000;
+const uint32_t MaxTpiHashBuckets = 0x40000;
+
 /// The header preceeding the global PDB Stream (Stream 1)
 struct InfoStreamHeader {
   support::ulittle32_t Version;

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h Fri Sep  9 12:46:17 2016
@@ -27,7 +27,7 @@ namespace pdb {
 class PDBFile;
 
 class TpiStream {
-  struct HeaderInfo;
+  friend class TpiStreamBuilder;
 
 public:
   TpiStream(const PDBFile &File,
@@ -66,7 +66,7 @@ private:
   msf::FixedStreamArray<TypeIndexOffset> TypeIndexOffsets;
   msf::FixedStreamArray<TypeIndexOffset> HashAdjustments;
 
-  const HeaderInfo *Header;
+  const TpiStreamHeader *Header;
 };
 }
 }

Added: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h?rev=281063&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h (added)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h Fri Sep  9 12:46:17 2016
@@ -0,0 +1,76 @@
+//===- TpiStreamBuilder.h - PDB Tpi Stream Creation -------------*- 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_PDBTPISTREAMBUILDER_H
+#define LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAMBUILDER_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/DebugInfo/MSF/SequencedItemStream.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
+
+#include <vector>
+
+namespace llvm {
+namespace codeview {
+class TypeRecord;
+}
+namespace msf {
+struct MSFLayout;
+class ReadableStreamRef;
+class WritableStream;
+
+template <> struct SequencedItemTraits<llvm::codeview::CVType> {
+  static size_t length(const codeview::CVType &Item) { return Item.Length; }
+  static ArrayRef<uint8_t> bytes(const codeview::CVType &Item) {
+    return Item.RawData;
+  }
+};
+}
+namespace pdb {
+class PDBFile;
+class TpiStream;
+struct TpiStreamHeader;
+
+class TpiStreamBuilder {
+public:
+  explicit TpiStreamBuilder(BumpPtrAllocator &Allocator);
+  ~TpiStreamBuilder();
+
+  TpiStreamBuilder(const TpiStreamBuilder &) = delete;
+  TpiStreamBuilder &operator=(const TpiStreamBuilder &) = delete;
+
+  void setVersionHeader(PdbRaw_TpiVer Version);
+  void addTypeRecord(const codeview::CVType &Record);
+
+  Expected<std::unique_ptr<TpiStream>> build(PDBFile &File,
+                                             const msf::WritableStream &Buffer);
+
+  Error commit(const msf::MSFLayout &Layout, const msf::WritableStream &Buffer);
+
+  uint32_t calculateSerializedLength() const;
+
+private:
+  Error finalize();
+
+  BumpPtrAllocator &Allocator;
+
+  Optional<PdbRaw_TpiVer> VerHeader;
+  std::vector<codeview::CVType> TypeRecords;
+  msf::SequencedItemStream<codeview::CVType> TypeRecordStream;
+
+  const TpiStreamHeader *Header;
+};
+}
+}
+
+#endif

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp Fri Sep  9 12:46:17 2016
@@ -40,7 +40,8 @@ using namespace llvm::codeview;
 using namespace llvm::msf;
 
 CodeViewDebug::CodeViewDebug(AsmPrinter *AP)
-    : DebugHandlerBase(AP), OS(*Asm->OutStreamer), CurFn(nullptr) {
+    : DebugHandlerBase(AP), OS(*Asm->OutStreamer), Allocator(),
+      TypeTable(Allocator), CurFn(nullptr) {
   // If module doesn't have named metadata anchors or COFF debug section
   // is not available, skip any debug info related stuff.
   if (!MMI->getModule()->getNamedMetadata("llvm.dbg.cu") ||

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h Fri Sep  9 12:46:17 2016
@@ -36,6 +36,7 @@ struct ClassInfo;
 /// \brief Collects and handles line tables information in a CodeView format.
 class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
   MCStreamer &OS;
+  llvm::BumpPtrAllocator Allocator;
   codeview::MemoryTypeTableBuilder TypeTable;
 
   /// Represents the most general definition range.

Modified: llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp Fri Sep  9 12:46:17 2016
@@ -81,14 +81,17 @@ Error CVTypeVisitor::visitTypeRecord(con
   else
     return ExpectedKind.takeError();
 
+  CVType RecordCopy = Record;
+  RecordCopy.Type = Kind;
+
   switch (Kind) {
   default:
-    if (auto EC = Callbacks.visitUnknownType(Record))
+    if (auto EC = Callbacks.visitUnknownType(RecordCopy))
       return EC;
     break;
 #define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
   case EnumName: {                                                             \
-    if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks))           \
+    if (auto EC = visitKnownRecord<Name##Record>(RecordCopy, Callbacks))       \
       return EC;                                                               \
     break;                                                                     \
   }
@@ -101,7 +104,7 @@ Error CVTypeVisitor::visitTypeRecord(con
 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
   }
 
-  if (auto EC = Callbacks.visitTypeEnd(Record))
+  if (auto EC = Callbacks.visitTypeEnd(RecordCopy))
     return EC;
 
   return Error::success();

Modified: llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp Fri Sep  9 12:46:17 2016
@@ -13,7 +13,7 @@ using namespace llvm;
 using namespace codeview;
 
 TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind)
-    : Stream(Buffer), Writer(Stream) {
+    : Kind(Kind), Stream(Buffer), Writer(Stream) {
   writeTypeRecordKind(Kind);
 }
 

Modified: llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp Fri Sep  9 12:46:17 2016
@@ -257,7 +257,9 @@ TypeIndex TypeTableBuilder::writeKnownTy
 }
 
 TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
-  return writeRecord(Builder.str());
+  TypeIndex I = writeRecord(Builder.str());
+  RecordKinds.push_back(Builder.kind());
+  return I;
 }
 
 TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {

Modified: llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt (original)
+++ llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt Fri Sep  9 12:46:17 2016
@@ -45,7 +45,8 @@ add_pdb_impl_folder(Raw
   Raw/RawError.cpp
   Raw/RawSession.cpp
   Raw/SymbolStream.cpp
-  Raw/TpiStream.cpp)
+  Raw/TpiStream.cpp
+  Raw/TpiStreamBuilder.cpp)
 
 list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB/Raw")
 list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB")

Modified: llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp Fri Sep  9 12:46:17 2016
@@ -19,6 +19,8 @@
 #include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
 #include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
 
 using namespace llvm;
 using namespace llvm::codeview;
@@ -58,6 +60,12 @@ DbiStreamBuilder &PDBFileBuilder::getDbi
   return *Dbi;
 }
 
+TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
+  if (!Tpi)
+    Tpi = llvm::make_unique<TpiStreamBuilder>(Allocator);
+  return *Tpi;
+}
+
 Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() const {
   if (Info) {
     uint32_t Length = Info->calculateSerializedLength();
@@ -69,6 +77,11 @@ Expected<msf::MSFLayout> PDBFileBuilder:
     if (auto EC = Msf->setStreamSize(StreamDBI, Length))
       return std::move(EC);
   }
+  if (Tpi) {
+    uint32_t Length = Tpi->calculateSerializedLength();
+    if (auto EC = Msf->setStreamSize(StreamTPI, Length))
+      return std::move(EC);
+  }
 
   return Msf->build();
 }
@@ -96,6 +109,13 @@ PDBFileBuilder::build(std::unique_ptr<ms
     File->Dbi = std::move(*ExpectedDbi);
   }
 
+  if (Tpi) {
+    auto ExpectedTpi = Tpi->build(*File, *PdbFileBuffer);
+    if (!ExpectedTpi)
+      return ExpectedTpi.takeError();
+    File->Tpi = std::move(*ExpectedTpi);
+  }
+
   if (File->Info && File->Dbi && File->Info->getAge() != File->Dbi->getAge())
     return llvm::make_error<RawError>(
         raw_error_code::corrupt_file,
@@ -144,5 +164,10 @@ Error PDBFileBuilder::commit(const msf::
       return EC;
   }
 
+  if (Tpi) {
+    if (auto EC = Tpi->commit(Layout, Buffer))
+      return EC;
+  }
+
   return Buffer.commit();
 }
\ No newline at end of file

Modified: llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp Fri Sep  9 12:46:17 2016
@@ -31,35 +31,6 @@ using namespace llvm::support;
 using namespace llvm::msf;
 using namespace llvm::pdb;
 
-namespace {
-const uint32_t MinHashBuckets = 0x1000;
-const uint32_t MaxHashBuckets = 0x40000;
-}
-
-// This corresponds to `HDR` in PDB/dbi/tpi.h.
-struct TpiStream::HeaderInfo {
-  struct EmbeddedBuf {
-    little32_t Off;
-    ulittle32_t Length;
-  };
-
-  ulittle32_t Version;
-  ulittle32_t HeaderSize;
-  ulittle32_t TypeIndexBegin;
-  ulittle32_t TypeIndexEnd;
-  ulittle32_t TypeRecordBytes;
-
-  // The following members correspond to `TpiHash` in PDB/dbi/tpi.h.
-  ulittle16_t HashStreamIndex;
-  ulittle16_t HashAuxStreamIndex;
-  ulittle32_t HashKeySize;
-  ulittle32_t NumHashBuckets;
-
-  EmbeddedBuf HashValueBuffer;
-  EmbeddedBuf IndexOffsetBuffer;
-  EmbeddedBuf HashAdjBuffer;
-};
-
 TpiStream::TpiStream(const PDBFile &File,
                      std::unique_ptr<MappedBlockStream> Stream)
     : Pdb(File), Stream(std::move(Stream)) {}
@@ -175,7 +146,7 @@ Error TpiStream::verifyHashValues() {
 Error TpiStream::reload() {
   StreamReader Reader(*Stream);
 
-  if (Reader.bytesRemaining() < sizeof(HeaderInfo))
+  if (Reader.bytesRemaining() < sizeof(TpiStreamHeader))
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "TPI Stream does not contain a header.");
 
@@ -187,7 +158,7 @@ Error TpiStream::reload() {
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "Unsupported TPI Version.");
 
-  if (Header->HeaderSize != sizeof(HeaderInfo))
+  if (Header->HeaderSize != sizeof(TpiStreamHeader))
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "Corrupt TPI Header size.");
 
@@ -195,8 +166,8 @@ Error TpiStream::reload() {
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "TPI Stream expected 4 byte hash key size.");
 
-  if (Header->NumHashBuckets < MinHashBuckets ||
-      Header->NumHashBuckets > MaxHashBuckets)
+  if (Header->NumHashBuckets < MinTpiHashBuckets ||
+      Header->NumHashBuckets > MaxTpiHashBuckets)
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "TPI Stream Invalid number of hash buckets.");
 
@@ -205,40 +176,44 @@ Error TpiStream::reload() {
     return EC;
 
   // Hash indices, hash values, etc come from the hash stream.
-  if (Header->HashStreamIndex >= Pdb.getNumStreams())
-    return make_error<RawError>(raw_error_code::corrupt_file,
-                                "Invalid TPI hash stream index.");
-  auto HS = MappedBlockStream::createIndexedStream(
-      Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex);
-  StreamReader HSR(*HS);
-
-  uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t);
-  if (NumHashValues != NumTypeRecords())
-    return make_error<RawError>(
-        raw_error_code::corrupt_file,
-        "TPI hash count does not match with the number of type records.");
-  HSR.setOffset(Header->HashValueBuffer.Off);
-  if (auto EC = HSR.readArray(HashValues, NumHashValues))
-    return EC;
-
-  HSR.setOffset(Header->IndexOffsetBuffer.Off);
-  uint32_t NumTypeIndexOffsets =
-      Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
-  if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
-    return EC;
-
-  HSR.setOffset(Header->HashAdjBuffer.Off);
-  uint32_t NumHashAdjustments =
-      Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset);
-  if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments))
-    return EC;
-
-  HashStream = std::move(HS);
-
-  // TPI hash table is a parallel array for the type records.
-  // Verify that the hash values match with type records.
-  if (auto EC = verifyHashValues())
-    return EC;
+  if (Header->HashStreamIndex != kInvalidStreamIndex) {
+    if (Header->HashStreamIndex >= Pdb.getNumStreams())
+      return make_error<RawError>(raw_error_code::corrupt_file,
+                                  "Invalid TPI hash stream index.");
+
+    auto HS = MappedBlockStream::createIndexedStream(
+        Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex);
+    StreamReader HSR(*HS);
+
+    uint32_t NumHashValues =
+        Header->HashValueBuffer.Length / sizeof(ulittle32_t);
+    if (NumHashValues != NumTypeRecords())
+      return make_error<RawError>(
+          raw_error_code::corrupt_file,
+          "TPI hash count does not match with the number of type records.");
+    HSR.setOffset(Header->HashValueBuffer.Off);
+    if (auto EC = HSR.readArray(HashValues, NumHashValues))
+      return EC;
+
+    HSR.setOffset(Header->IndexOffsetBuffer.Off);
+    uint32_t NumTypeIndexOffsets =
+        Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
+    if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
+      return EC;
+
+    HSR.setOffset(Header->HashAdjBuffer.Off);
+    uint32_t NumHashAdjustments =
+        Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset);
+    if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments))
+      return EC;
+
+    HashStream = std::move(HS);
+
+    // TPI hash table is a parallel array for the type records.
+    // Verify that the hash values match with type records.
+    if (auto EC = verifyHashValues())
+      return EC;
+  }
 
   return Error::success();
 }

Added: llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp?rev=281063&view=auto
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp (added)
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp Fri Sep  9 12:46:17 2016
@@ -0,0 +1,95 @@
+#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
+
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/MSF/StreamWriter.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
+#include "llvm/Support/Allocator.h"
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+TpiStreamBuilder::TpiStreamBuilder(BumpPtrAllocator &Allocator)
+    : Allocator(Allocator), Header(nullptr) {}
+
+TpiStreamBuilder::~TpiStreamBuilder() {}
+
+void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) {
+  VerHeader = Version;
+}
+
+void TpiStreamBuilder::addTypeRecord(const codeview::CVType &Record) {
+  TypeRecords.push_back(Record);
+  TypeRecordStream.setItems(TypeRecords);
+}
+
+Error TpiStreamBuilder::finalize() {
+  if (Header)
+    return Error::success();
+
+  TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>();
+
+  uint32_t Count = TypeRecords.size();
+
+  H->Version = *VerHeader;
+  H->HeaderSize = sizeof(TpiStreamHeader);
+  H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex;
+  H->TypeIndexEnd = H->TypeIndexBegin + Count;
+  H->TypeRecordBytes = TypeRecordStream.getLength();
+
+  H->HashStreamIndex = kInvalidStreamIndex;
+  H->HashAuxStreamIndex = kInvalidStreamIndex;
+  H->HashKeySize = sizeof(ulittle32_t);
+  H->NumHashBuckets = MinTpiHashBuckets;
+
+  H->HashValueBuffer.Length = 0;
+  H->HashAdjBuffer.Length = 0;
+  H->IndexOffsetBuffer.Length = 0;
+
+  Header = H;
+  return Error::success();
+}
+
+uint32_t TpiStreamBuilder::calculateSerializedLength() const {
+  return sizeof(TpiStreamHeader) + TypeRecordStream.getLength();
+}
+
+Expected<std::unique_ptr<TpiStream>>
+TpiStreamBuilder::build(PDBFile &File, const msf::WritableStream &Buffer) {
+  if (!VerHeader.hasValue())
+    return make_error<RawError>(raw_error_code::unspecified,
+                                "Missing TPI Stream Version");
+  if (auto EC = finalize())
+    return std::move(EC);
+
+  auto StreamData = MappedBlockStream::createIndexedStream(File.getMsfLayout(),
+                                                           Buffer, StreamTPI);
+  auto Tpi = llvm::make_unique<TpiStream>(File, std::move(StreamData));
+  Tpi->Header = Header;
+  Tpi->TypeRecords = VarStreamArray<codeview::CVType>(TypeRecordStream);
+  return std::move(Tpi);
+}
+
+Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
+                               const msf::WritableStream &Buffer) {
+  if (auto EC = finalize())
+    return EC;
+
+  auto InfoS =
+      WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamTPI);
+
+  StreamWriter Writer(*InfoS);
+  if (auto EC = Writer.writeObject(*Header))
+    return EC;
+
+  auto RecordArray = VarStreamArray<codeview::CVType>(TypeRecordStream);
+  if (auto EC = Writer.writeArray(RecordArray))
+    return EC;
+
+  return Error::success();
+}

Modified: llvm/trunk/test/DebugInfo/PDB/pdbdump-readwrite.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdbdump-readwrite.test?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-readwrite.test (original)
+++ llvm/trunk/test/DebugInfo/PDB/pdbdump-readwrite.test Fri Sep  9 12:46:17 2016
@@ -1,10 +1,10 @@
 RUN: llvm-pdbdump pdb2yaml -dbi-module-info -dbi-module-source-info \
-RUN:   -dbi-stream -pdb-stream -stream-directory -stream-metadata \
-RUN:   %p/Inputs/empty.pdb > %t.1
+RUN:   -dbi-stream -pdb-stream -tpi-stream -stream-directory \
+RUN:   -stream-metadata %p/Inputs/empty.pdb > %t.1
 RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1
 
-RUN: llvm-pdbdump raw -headers %p/Inputs/empty.pdb | FileCheck %s
-RUN: llvm-pdbdump raw -headers %t.2 | FileCheck %s
+RUN: llvm-pdbdump raw -headers -tpi-records %p/Inputs/empty.pdb | FileCheck %s
+RUN: llvm-pdbdump raw -headers -tpi-records %t.2 | FileCheck %s
 
 CHECK:      FileHeaders {
 CHECK-NEXT:   BlockSize: 4096
@@ -17,13 +17,16 @@ CHECK-NEXT:   NumDirectoryBlocks: 1
 CHECK-NEXT:   DirectoryBlocks: [23]
 CHECK-NEXT:   NumStreams: 17
 CHECK-NEXT: }
-CHECK-NEXT: PDB Stream {
+CHECK:      PDB Stream {
 CHECK-NEXT:   Version: 20000404
 CHECK-NEXT:   Signature: 0x54E507E2
 CHECK-NEXT:   Age: 1
 CHECK-NEXT:   Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
 CHECK-NEXT: }
-CHECK-NEXT: DBI Stream {
+CHECK:      Type Info Stream (TPI) {
+CHECK-NEXT:   TPI Version: 20040203
+CHECK-NEXT:   Record count: 75
+CHECK:      DBI Stream {
 CHECK-NEXT:   Dbi Version: 19990903
 CHECK-NEXT:   Age: 1
 CHECK-NEXT:   Incremental Linking: Yes

Modified: llvm/trunk/test/DebugInfo/PDB/pdbdump-write.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdbdump-write.test?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-write.test (original)
+++ llvm/trunk/test/DebugInfo/PDB/pdbdump-write.test Fri Sep  9 12:46:17 2016
@@ -10,8 +10,8 @@
 ; stream metadata, since the layout of the MSF file might be different
 ; (for example if we don't write the entire stream)
 ;
-; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream %p/Inputs/empty.pdb > %t.1
+; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream -tpi-stream %p/Inputs/empty.pdb > %t.1
 ; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1
-; RUN: llvm-pdbdump pdb2yaml -pdb-stream %p/Inputs/empty.pdb > %t.3
-; RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.2 > %t.4
+; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream %p/Inputs/empty.pdb > %t.3
+; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream %t.2 > %t.4
 ; RUN: diff %t.3 %t.4

Modified: llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.cpp (original)
+++ llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.cpp Fri Sep  9 12:46:17 2016
@@ -9,6 +9,7 @@
 
 #include "CodeViewYaml.h"
 #include "PdbYaml.h"
+#include "YamlSerializationContext.h"
 
 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/EnumTables.h"
@@ -269,34 +270,20 @@ template <> struct ScalarTraits<APSInt>
   static bool mustQuote(StringRef Scalar) { return false; }
 };
 
-void MappingContextTraits<CVType, YamlTypeDumperCallbacks>::mapping(
-    IO &IO, CVType &Record, YamlTypeDumperCallbacks &Dumper) {
+void MappingContextTraits<CVType, pdb::yaml::SerializationContext>::mapping(
+    IO &IO, CVType &Record, pdb::yaml::SerializationContext &Context) {
   if (IO.outputting()) {
     codeview::TypeDeserializer Deserializer;
 
     codeview::TypeVisitorCallbackPipeline Pipeline;
     Pipeline.addCallbackToPipeline(Deserializer);
-    Pipeline.addCallbackToPipeline(Dumper);
+    Pipeline.addCallbackToPipeline(Context.Dumper);
 
     codeview::CVTypeVisitor Visitor(Pipeline);
     consumeError(Visitor.visitTypeRecord(Record));
   }
 }
 
-void MappingContextTraits<FieldListRecord, YamlTypeDumperCallbacks>::mapping(
-    IO &IO, FieldListRecord &FieldList, YamlTypeDumperCallbacks &Dumper) {
-  if (IO.outputting()) {
-    codeview::TypeDeserializer Deserializer;
-
-    codeview::TypeVisitorCallbackPipeline Pipeline;
-    Pipeline.addCallbackToPipeline(Deserializer);
-    Pipeline.addCallbackToPipeline(Dumper);
-
-    codeview::CVTypeVisitor Visitor(Pipeline);
-    consumeError(Visitor.visitFieldListMemberStream(FieldList.Data));
-  }
-}
-
 void MappingTraits<StringIdRecord>::mapping(IO &IO, StringIdRecord &String) {
   IO.mapRequired("Id", String.Id);
   IO.mapRequired("String", String.String);
@@ -549,13 +536,23 @@ llvm::codeview::yaml::YamlTypeDumperCall
 }
 
 void llvm::codeview::yaml::YamlTypeDumperCallbacks::visitKnownRecordImpl(
-    const char *Name, const CVType &Type, FieldListRecord &FieldList) {
-
-  std::vector<llvm::pdb::yaml::PdbTpiRecord> Records;
+    const char *Name, const CVType &CVR, FieldListRecord &FieldList) {
+  std::vector<llvm::pdb::yaml::PdbTpiRecord> FieldListRecords;
   if (YamlIO.outputting()) {
-    FieldListRecordSplitter Splitter(Records);
+    // If we are outputting, then `FieldList.Data` contains a huge chunk of data
+    // representing the serialized list of members.  We need to split it up into
+    // individual CVType records where each record represents an individual
+    // member.  This way, we can simply map the entire thing as a Yaml sequence,
+    // which will recurse back to the standard handler for top-level fields
+    // (top-level and member fields all have the exact same Yaml syntax so use
+    // the same parser).
+    //
+    // If we are not outputting, then the array contains no data starting out,
+    // and is instead populated from the sequence represented by the yaml --
+    // again, using the same logic that we use for top-level records.
+    FieldListRecordSplitter Splitter(FieldListRecords);
     CVTypeVisitor V(Splitter);
     consumeError(V.visitFieldListMemberStream(FieldList.Data));
   }
-  YamlIO.mapRequired(Name, Records);
+  YamlIO.mapRequired("FieldList", FieldListRecords, Context);
 }

Modified: llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.h (original)
+++ llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.h Fri Sep  9 12:46:17 2016
@@ -11,15 +11,23 @@
 #define LLVM_TOOLS_LLVMPDBDUMP_CODEVIEWYAML_H
 
 #include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
 #include "llvm/Support/YAMLTraits.h"
 
 namespace llvm {
+namespace pdb {
+namespace yaml {
+struct SerializationContext;
+}
+}
 namespace codeview {
 namespace yaml {
 class YamlTypeDumperCallbacks : public TypeVisitorCallbacks {
 public:
-  YamlTypeDumperCallbacks(llvm::yaml::IO &IO) : YamlIO(IO) {}
+  YamlTypeDumperCallbacks(llvm::yaml::IO &IO,
+                          llvm::pdb::yaml::SerializationContext &Context)
+      : YamlIO(IO), Context(Context) {}
 
   virtual Expected<TypeLeafKind>
   visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override;
@@ -42,13 +50,19 @@ private:
     YamlIO.mapRequired(Name, Record);
   }
 
-  void visitKnownRecordImpl(const char *Name, const CVType &Type,
+  void visitKnownRecordImpl(const char *Name, const CVType &CVR,
                             FieldListRecord &FieldList);
 
   llvm::yaml::IO &YamlIO;
+  llvm::pdb::yaml::SerializationContext &Context;
 };
 }
 }
+namespace pdb {
+namespace yaml {
+struct SerializationContext;
+}
+}
 }
 
 namespace llvm {
@@ -58,10 +72,9 @@ template <> struct MappingTraits<codevie
 };
 
 template <>
-struct MappingContextTraits<codeview::CVType,
-                            codeview::yaml::YamlTypeDumperCallbacks> {
+struct MappingContextTraits<codeview::CVType, pdb::yaml::SerializationContext> {
   static void mapping(IO &IO, codeview::CVType &Obj,
-                      codeview::yaml::YamlTypeDumperCallbacks &Context);
+                      pdb::yaml::SerializationContext &Context);
 };
 
 template <> struct ScalarEnumerationTraits<codeview::TypeLeafKind> {
@@ -77,13 +90,6 @@ template <> struct ScalarEnumerationTrai
 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
-
-template <>
-struct MappingContextTraits<codeview::FieldListRecord,
-                            codeview::yaml::YamlTypeDumperCallbacks> {
-  static void mapping(IO &IO, codeview::FieldListRecord &Record,
-                      codeview::yaml::YamlTypeDumperCallbacks &Context);
-};
 }
 }
 

Modified: llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp (original)
+++ llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp Fri Sep  9 12:46:17 2016
@@ -10,9 +10,11 @@
 #include "PdbYaml.h"
 
 #include "CodeViewYaml.h"
+#include "YamlSerializationContext.h"
 
 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializationVisitor.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/PDB/PDBExtras.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
@@ -134,7 +136,7 @@ void MappingTraits<PdbObject>::mapping(I
   IO.mapOptional("StreamMap", Obj.StreamMap);
   IO.mapOptional("PdbStream", Obj.PdbStream);
   IO.mapOptional("DbiStream", Obj.DbiStream);
-  IO.mapOptional("TpiStream", Obj.TpiStream);
+  IO.mapOptionalWithContext("TpiStream", Obj.TpiStream, Obj.Allocator);
 }
 
 void MappingTraits<MSFHeaders>::mapping(IO &IO, MSFHeaders &Obj) {
@@ -181,10 +183,18 @@ void MappingTraits<PdbDbiStream>::mappin
   IO.mapOptional("Modules", Obj.ModInfos);
 }
 
-void MappingTraits<PdbTpiStream>::mapping(IO &IO,
-                                          pdb::yaml::PdbTpiStream &Obj) {
+void MappingContextTraits<PdbTpiStream, BumpPtrAllocator>::mapping(
+    IO &IO, pdb::yaml::PdbTpiStream &Obj, BumpPtrAllocator &Allocator) {
+  // Create a single serialization context that will be passed through the
+  // entire process of serializing / deserializing a Tpi Stream.  This is
+  // especially important when we are going from Pdb -> Yaml because we need
+  // to maintain state in a TypeTableBuilder across mappings, and at the end of
+  // the entire process, we need to have one TypeTableBuilder that has every
+  // record.
+  pdb::yaml::SerializationContext Context(IO, Allocator);
+
   IO.mapRequired("Version", Obj.Version);
-  IO.mapRequired("Records", Obj.Records);
+  IO.mapRequired("Records", Obj.Records, Context);
 }
 
 void MappingTraits<NamedStreamMapping>::mapping(IO &IO,
@@ -199,21 +209,40 @@ void MappingTraits<PdbDbiModuleInfo>::ma
   IO.mapOptional("SourceFiles", Obj.SourceFiles);
 }
 
-void MappingTraits<PdbTpiRecord>::mapping(IO &IO,
-                                          pdb::yaml::PdbTpiRecord &Obj) {
-  if (IO.outputting()) {
-    codeview::TypeDeserializer Deserializer;
-    codeview::yaml::YamlTypeDumperCallbacks Callbacks(IO);
+void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>::
+    mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj,
+            pdb::yaml::SerializationContext &Context) {
+  codeview::TypeVisitorCallbackPipeline Pipeline;
+  codeview::TypeDeserializer Deserializer;
+  codeview::TypeSerializationVisitor Serializer(Context.FieldListBuilder,
+                                                Context.TypeTableBuilder);
 
-    codeview::TypeVisitorCallbackPipeline Pipeline;
+  if (IO.outputting()) {
+    // For PDB to Yaml, deserialize into a high level record type, then dump it.
     Pipeline.addCallbackToPipeline(Deserializer);
-    Pipeline.addCallbackToPipeline(Callbacks);
-
-    codeview::CVTypeVisitor Visitor(Pipeline);
-    consumeError(Visitor.visitTypeRecord(Obj.Record));
+    Pipeline.addCallbackToPipeline(Context.Dumper);
   } else {
-    codeview::yaml::YamlTypeDumperCallbacks Callbacks(IO);
-    codeview::CVTypeVisitor Visitor(Callbacks);
-    consumeError(Visitor.visitTypeRecord(Obj.Record));
+    // For Yaml to PDB, extract from the high level record type, then write it
+    // to bytes.
+    Pipeline.addCallbackToPipeline(Context.Dumper);
+    Pipeline.addCallbackToPipeline(Serializer);
+  }
+
+  codeview::CVTypeVisitor Visitor(Pipeline);
+  consumeError(Visitor.visitTypeRecord(Obj.Record));
+
+  if (!IO.outputting()) {
+    // For Yaml to PDB, we need to update the input Object with the bytes for
+    // this record.
+    ArrayRef<StringRef> Records = Context.TypeTableBuilder.getRecords();
+    ArrayRef<codeview::TypeRecordKind> Kinds =
+        Context.TypeTableBuilder.getRecordKinds();
+
+    StringRef ThisRecord = Records.back();
+    Obj.Record.Type = static_cast<codeview::TypeLeafKind>(Kinds.back());
+    Obj.Record.Data =
+        ArrayRef<uint8_t>(ThisRecord.bytes_begin(), ThisRecord.bytes_end());
+    Obj.Record.RawData = Obj.Record.Data;
+    Obj.Record.Length = ThisRecord.size();
   }
 }

Modified: llvm/trunk/tools/llvm-pdbdump/PdbYaml.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbdump/PdbYaml.h?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/PdbYaml.h (original)
+++ llvm/trunk/tools/llvm-pdbdump/PdbYaml.h Fri Sep  9 12:46:17 2016
@@ -26,6 +26,8 @@ namespace llvm {
 namespace pdb {
 
 namespace yaml {
+struct SerializationContext;
+
 struct MSFHeaders {
   msf::SuperBlock SuperBlock;
   uint32_t NumDirectoryBlocks;
@@ -79,12 +81,16 @@ struct PdbTpiStream {
 };
 
 struct PdbObject {
+  explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {}
+
   Optional<MSFHeaders> Headers;
   Optional<std::vector<uint32_t>> StreamSizes;
   Optional<std::vector<StreamBlockList>> StreamMap;
   Optional<PdbInfoStream> PdbStream;
   Optional<PdbDbiStream> DbiStream;
   Optional<PdbTpiStream> TpiStream;
+
+  BumpPtrAllocator &Allocator;
 };
 }
 }
@@ -117,8 +123,10 @@ template <> struct MappingTraits<pdb::ya
   static void mapping(IO &IO, pdb::yaml::PdbDbiStream &Obj);
 };
 
-template <> struct MappingTraits<pdb::yaml::PdbTpiStream> {
-  static void mapping(IO &IO, pdb::yaml::PdbTpiStream &Obj);
+template <>
+struct MappingContextTraits<pdb::yaml::PdbTpiStream, llvm::BumpPtrAllocator> {
+  static void mapping(IO &IO, pdb::yaml::PdbTpiStream &Obj,
+                      llvm::BumpPtrAllocator &Allocator);
 };
 
 template <> struct MappingTraits<pdb::yaml::NamedStreamMapping> {
@@ -129,8 +137,11 @@ template <> struct MappingTraits<pdb::ya
   static void mapping(IO &IO, pdb::yaml::PdbDbiModuleInfo &Obj);
 };
 
-template <> struct MappingTraits<pdb::yaml::PdbTpiRecord> {
-  static void mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj);
+template <>
+struct MappingContextTraits<pdb::yaml::PdbTpiRecord,
+                            pdb::yaml::SerializationContext> {
+  static void mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj,
+                      pdb::yaml::SerializationContext &Context);
 };
 }
 }

Modified: llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp (original)
+++ llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp Fri Sep  9 12:46:17 2016
@@ -21,7 +21,8 @@
 using namespace llvm;
 using namespace llvm::pdb;
 
-YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) : File(File), Out(outs()) {}
+YAMLOutputStyle::YAMLOutputStyle(PDBFile &File)
+    : File(File), Out(outs()), Obj(File.getAllocator()) {}
 
 Error YAMLOutputStyle::dump() {
   if (opts::pdb2yaml::StreamDirectory)

Added: llvm/trunk/tools/llvm-pdbdump/YamlSerializationContext.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbdump/YamlSerializationContext.h?rev=281063&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/YamlSerializationContext.h (added)
+++ llvm/trunk/tools/llvm-pdbdump/YamlSerializationContext.h Fri Sep  9 12:46:17 2016
@@ -0,0 +1,36 @@
+//===- YamlSerializationContext.h ----------------------------- *- C++ --*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_YAMLSERIALIZATIONCONTEXT_H
+#define LLVM_TOOLS_LLVMPDBDUMP_YAMLSERIALIZATIONCONTEXT_H
+
+#include "CodeViewYaml.h"
+#include "PdbYaml.h"
+#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
+
+namespace llvm {
+namespace yaml {
+class IO;
+}
+
+namespace pdb {
+namespace yaml {
+struct SerializationContext {
+  explicit SerializationContext(llvm::yaml::IO &IO, BumpPtrAllocator &Allocator)
+      : Dumper(IO, *this), TypeTableBuilder(Allocator) {}
+  codeview::yaml::YamlTypeDumperCallbacks Dumper;
+  codeview::MemoryTypeTableBuilder TypeTableBuilder;
+  codeview::FieldListRecordBuilder FieldListBuilder;
+};
+}
+}
+}
+
+#endif
\ No newline at end of file

Modified: llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp (original)
+++ llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp Fri Sep  9 12:46:17 2016
@@ -50,6 +50,8 @@
 #include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
 #include "llvm/DebugInfo/PDB/Raw/RawSession.h"
+#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
 #include "llvm/Support/COM.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ConvertUTF.h"
@@ -306,7 +308,7 @@ static void yamlToPdb(StringRef Path) {
   std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get();
 
   llvm::yaml::Input In(Buffer->getBuffer());
-  pdb::yaml::PdbObject YamlObj;
+  pdb::yaml::PdbObject YamlObj(Allocator);
   In >> YamlObj;
   if (!YamlObj.Headers.hasValue())
     ExitOnErr(make_error<GenericError>(generic_error_code::unspecified,
@@ -382,6 +384,13 @@ static void yamlToPdb(StringRef Path) {
     }
   }
 
+  if (YamlObj.TpiStream.hasValue()) {
+    auto &TpiBuilder = Builder.getTpiBuilder();
+    TpiBuilder.setVersionHeader(YamlObj.TpiStream->Version);
+    for (const auto &R : YamlObj.TpiStream->Records)
+      TpiBuilder.addTypeRecord(R.Record);
+  }
+
   ExitOnErr(Builder.commit(*FileByteStream));
 }
 

Modified: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp?rev=281063&r1=281062&r2=281063&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp Fri Sep  9 12:46:17 2016
@@ -331,8 +331,15 @@ static bool isMipsArch(unsigned Arch) {
     return false;
   }
 }
-
-static llvm::codeview::MemoryTypeTableBuilder CVTypes;
+namespace {
+struct TypeTableBuilder {
+  TypeTableBuilder() : Allocator(), Builder(Allocator) {}
+
+  llvm::BumpPtrAllocator Allocator;
+  llvm::codeview::MemoryTypeTableBuilder Builder;
+};
+}
+static TypeTableBuilder CVTypes;
 
 /// @brief Creates an format-specific object file dumper.
 static std::error_code createDumper(const ObjectFile *Obj,
@@ -429,7 +436,7 @@ static void dumpObject(const ObjectFile
     if (opts::CodeView)
       Dumper->printCodeViewDebugInfo();
     if (opts::CodeViewMergedTypes)
-      Dumper->mergeCodeViewTypes(CVTypes);
+      Dumper->mergeCodeViewTypes(CVTypes.Builder);
   }
   if (Obj->isMachO()) {
     if (opts::MachODataInCode)
@@ -534,7 +541,7 @@ int main(int argc, const char *argv[]) {
 
   if (opts::CodeViewMergedTypes) {
     ScopedPrinter W(outs());
-    dumpCodeViewMergedTypes(W, CVTypes);
+    dumpCodeViewMergedTypes(W, CVTypes.Builder);
   }
 
   return 0;




More information about the llvm-commits mailing list