Index: llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h @@ -20,7 +20,8 @@ class MemoryTypeTableBuilder : public TypeTableBuilder { public: - MemoryTypeTableBuilder() {} + explicit MemoryTypeTableBuilder(BumpPtrAllocator &Allocator) + : RecordStorage(Allocator) {} bool empty() const { return Records.empty(); } @@ -33,12 +34,13 @@ } } -protected: TypeIndex writeRecord(llvm::StringRef Data) override; + ArrayRef getRecords() const { return Records; } + private: std::vector Records; - BumpPtrAllocator RecordStorage; + BumpPtrAllocator &RecordStorage; DenseMap HashedRecords; }; Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h @@ -47,6 +47,7 @@ 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 @@ void reset(TypeRecordKind K) { Buffer.clear(); + Kind = K; writeTypeRecordKind(K); } private: + TypeRecordKind Kind; llvm::SmallVector Buffer; llvm::raw_svector_ostream Stream; llvm::support::endian::Writer Writer; Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h @@ -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 visitTypeBegin(const CVType &Record) override { + if (Record.Type == TypeLeafKind::LF_FIELDLIST) + FieldListBuilder.reset(); + return Record.Type; + } + + virtual Error visitTypeEnd(const CVRecord &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 &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 &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 void visitKnownRecordImpl(RecordKind &Record) { + TypeTableBuilder.writeKnownType(Record); + } + template + void visitMemberRecordImpl(RecordKind &Record) { + FieldListBuilder.writeMemberType(Record); + } + + void visitKnownRecordImpl(FieldListRecord &FieldList) {} + + FieldListRecordBuilder &FieldListBuilder; + MemoryTypeTableBuilder &TypeTableBuilder; +}; +} +} + +#endif Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -63,6 +63,11 @@ TypeIndex writeRecord(TypeRecordBuilder &builder); virtual TypeIndex writeRecord(llvm::StringRef record) = 0; + + ArrayRef getRecordKinds() const { return RecordKinds; } + +private: + std::vector RecordKinds; }; } } Index: llvm/trunk/include/llvm/DebugInfo/MSF/SequencedItemStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/SequencedItemStream.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/SequencedItemStream.h @@ -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 +#include +#include + +namespace llvm { +namespace msf { +template struct SequencedItemTraits { + static size_t length(const T &Item) = delete; + static ArrayRef 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 > +class SequencedItemStream : public ReadableStream { +public: + SequencedItemStream() {} + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &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(msf_error_code::insufficient_buffer); + Buffer = Traits::bytes(Item).take_front(Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) const override { + auto ExpectedIndex = translateOffsetIndex(Offset); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + Buffer = Traits::bytes(Items[*ExpectedIndex]); + return Error::success(); + } + + void setItems(ArrayRef 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 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(msf_error_code::insufficient_buffer); + return CurrentIndex; + } + ArrayRef Items; +}; +} // end namespace msf +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_MSF_SEQUENCEDITEMSTREAM_H Index: llvm/trunk/include/llvm/DebugInfo/MSF/StreamArray.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/StreamArray.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/StreamArray.h @@ -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" Index: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -92,6 +92,8 @@ Expected getPDBSymbolStream(); Expected getStringTable(); + BumpPtrAllocator &getAllocator() { return Allocator; } + private: BumpPtrAllocator &Allocator; Index: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h @@ -28,6 +28,7 @@ namespace pdb { class DbiStreamBuilder; class InfoStreamBuilder; +class TpiStreamBuilder; class PDBFileBuilder { public: @@ -40,6 +41,7 @@ msf::MSFBuilder &getMsfBuilder(); InfoStreamBuilder &getInfoBuilder(); DbiStreamBuilder &getDbiBuilder(); + TpiStreamBuilder &getTpiBuilder(); Expected> build(std::unique_ptr PdbFileBuffer); @@ -54,6 +56,7 @@ std::unique_ptr Msf; std::unique_ptr Info; std::unique_ptr Dbi; + std::unique_ptr Tpi; }; } } Index: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawTypes.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawTypes.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawTypes.h @@ -266,6 +266,34 @@ 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; Index: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h @@ -27,7 +27,7 @@ class PDBFile; class TpiStream { - struct HeaderInfo; + friend class TpiStreamBuilder; public: TpiStream(const PDBFile &File, @@ -66,7 +66,7 @@ msf::FixedStreamArray TypeIndexOffsets; msf::FixedStreamArray HashAdjustments; - const HeaderInfo *Header; + const TpiStreamHeader *Header; }; } } Index: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h @@ -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 + +namespace llvm { +namespace codeview { +class TypeRecord; +} +namespace msf { +struct MSFLayout; +class ReadableStreamRef; +class WritableStream; + +template <> struct SequencedItemTraits { + static size_t length(const codeview::CVType &Item) { return Item.Length; } + static ArrayRef 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> 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 VerHeader; + std::vector TypeRecords; + msf::SequencedItemStream TypeRecordStream; + + const TpiStreamHeader *Header; +}; +} +} + +#endif Index: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -36,6 +36,7 @@ /// \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. Index: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -40,7 +40,8 @@ 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") || Index: llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -81,14 +81,17 @@ 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(Record, Callbacks)) \ + if (auto EC = visitKnownRecord(RecordCopy, Callbacks)) \ return EC; \ break; \ } @@ -101,7 +104,7 @@ #include "llvm/DebugInfo/CodeView/TypeRecords.def" } - if (auto EC = Callbacks.visitTypeEnd(Record)) + if (auto EC = Callbacks.visitTypeEnd(RecordCopy)) return EC; return Error::success(); Index: llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp @@ -13,7 +13,7 @@ using namespace codeview; TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind) - : Stream(Buffer), Writer(Stream) { + : Kind(Kind), Stream(Buffer), Writer(Stream) { writeTypeRecordKind(Kind); } Index: llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp @@ -257,7 +257,9 @@ } 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) { Index: llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt +++ llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt @@ -45,7 +45,8 @@ 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") Index: llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp @@ -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 @@ return *Dbi; } +TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { + if (!Tpi) + Tpi = llvm::make_unique(Allocator); + return *Tpi; +} + Expected PDBFileBuilder::finalizeMsfLayout() const { if (Info) { uint32_t Length = Info->calculateSerializedLength(); @@ -69,6 +77,11 @@ 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 @@ 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( raw_error_code::corrupt_file, @@ -144,5 +164,10 @@ return EC; } + if (Tpi) { + if (auto EC = Tpi->commit(Layout, Buffer)) + return EC; + } + return Buffer.commit(); } \ No newline at end of file Index: llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -31,35 +31,6 @@ 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 Stream) : Pdb(File), Stream(std::move(Stream)) {} @@ -175,7 +146,7 @@ Error TpiStream::reload() { StreamReader Reader(*Stream); - if (Reader.bytesRemaining() < sizeof(HeaderInfo)) + if (Reader.bytesRemaining() < sizeof(TpiStreamHeader)) return make_error(raw_error_code::corrupt_file, "TPI Stream does not contain a header."); @@ -187,7 +158,7 @@ return make_error(raw_error_code::corrupt_file, "Unsupported TPI Version."); - if (Header->HeaderSize != sizeof(HeaderInfo)) + if (Header->HeaderSize != sizeof(TpiStreamHeader)) return make_error(raw_error_code::corrupt_file, "Corrupt TPI Header size."); @@ -195,8 +166,8 @@ return make_error(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(raw_error_code::corrupt_file, "TPI Stream Invalid number of hash buckets."); @@ -205,40 +176,44 @@ return EC; // Hash indices, hash values, etc come from the hash stream. - if (Header->HashStreamIndex >= Pdb.getNumStreams()) - return make_error(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( - 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(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( + 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(); } Index: llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp @@ -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(); + + 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> +TpiStreamBuilder::build(PDBFile &File, const msf::WritableStream &Buffer) { + if (!VerHeader.hasValue()) + return make_error(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(File, std::move(StreamData)); + Tpi->Header = Header; + Tpi->TypeRecords = VarStreamArray(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(TypeRecordStream); + if (auto EC = Writer.writeArray(RecordArray)) + return EC; + + return Error::success(); +} Index: llvm/trunk/test/DebugInfo/PDB/pdbdump-readwrite.test =================================================================== --- llvm/trunk/test/DebugInfo/PDB/pdbdump-readwrite.test +++ llvm/trunk/test/DebugInfo/PDB/pdbdump-readwrite.test @@ -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: 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 Index: llvm/trunk/test/DebugInfo/PDB/pdbdump-write.test =================================================================== --- llvm/trunk/test/DebugInfo/PDB/pdbdump-write.test +++ llvm/trunk/test/DebugInfo/PDB/pdbdump-write.test @@ -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 Index: llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.h =================================================================== --- llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.h +++ llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.h @@ -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 visitTypeBegin(const CVRecord &Record) override; @@ -42,13 +50,19 @@ 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 MappingContextTraits { +struct MappingContextTraits { static void mapping(IO &IO, codeview::CVType &Obj, - codeview::yaml::YamlTypeDumperCallbacks &Context); + pdb::yaml::SerializationContext &Context); }; template <> struct ScalarEnumerationTraits { @@ -77,13 +90,6 @@ #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 { - static void mapping(IO &IO, codeview::FieldListRecord &Record, - codeview::yaml::YamlTypeDumperCallbacks &Context); -}; } } Index: llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.cpp +++ llvm/trunk/tools/llvm-pdbdump/CodeViewYaml.cpp @@ -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 @@ static bool mustQuote(StringRef Scalar) { return false; } }; -void MappingContextTraits::mapping( - IO &IO, CVType &Record, YamlTypeDumperCallbacks &Dumper) { +void MappingContextTraits::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::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::mapping(IO &IO, StringIdRecord &String) { IO.mapRequired("Id", String.Id); IO.mapRequired("String", String.String); @@ -549,13 +536,23 @@ } void llvm::codeview::yaml::YamlTypeDumperCallbacks::visitKnownRecordImpl( - const char *Name, const CVType &Type, FieldListRecord &FieldList) { - - std::vector Records; + const char *Name, const CVType &CVR, FieldListRecord &FieldList) { + std::vector 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); } Index: llvm/trunk/tools/llvm-pdbdump/PdbYaml.h =================================================================== --- llvm/trunk/tools/llvm-pdbdump/PdbYaml.h +++ llvm/trunk/tools/llvm-pdbdump/PdbYaml.h @@ -26,6 +26,8 @@ namespace pdb { namespace yaml { +struct SerializationContext; + struct MSFHeaders { msf::SuperBlock SuperBlock; uint32_t NumDirectoryBlocks; @@ -79,12 +81,16 @@ }; struct PdbObject { + explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {} + Optional Headers; Optional> StreamSizes; Optional> StreamMap; Optional PdbStream; Optional DbiStream; Optional TpiStream; + + BumpPtrAllocator &Allocator; }; } } @@ -117,8 +123,10 @@ static void mapping(IO &IO, pdb::yaml::PdbDbiStream &Obj); }; -template <> struct MappingTraits { - static void mapping(IO &IO, pdb::yaml::PdbTpiStream &Obj); +template <> +struct MappingContextTraits { + static void mapping(IO &IO, pdb::yaml::PdbTpiStream &Obj, + llvm::BumpPtrAllocator &Allocator); }; template <> struct MappingTraits { @@ -129,8 +137,11 @@ static void mapping(IO &IO, pdb::yaml::PdbDbiModuleInfo &Obj); }; -template <> struct MappingTraits { - static void mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj); +template <> +struct MappingContextTraits { + static void mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj, + pdb::yaml::SerializationContext &Context); }; } } Index: llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp +++ llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp @@ -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 @@ 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::mapping(IO &IO, MSFHeaders &Obj) { @@ -181,10 +183,18 @@ IO.mapOptional("Modules", Obj.ModInfos); } -void MappingTraits::mapping(IO &IO, - pdb::yaml::PdbTpiStream &Obj) { +void MappingContextTraits::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::mapping(IO &IO, @@ -199,21 +209,40 @@ IO.mapOptional("SourceFiles", Obj.SourceFiles); } -void MappingTraits::mapping(IO &IO, - pdb::yaml::PdbTpiRecord &Obj) { - if (IO.outputting()) { - codeview::TypeDeserializer Deserializer; - codeview::yaml::YamlTypeDumperCallbacks Callbacks(IO); +void MappingContextTraits:: + 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 Records = Context.TypeTableBuilder.getRecords(); + ArrayRef Kinds = + Context.TypeTableBuilder.getRecordKinds(); + + StringRef ThisRecord = Records.back(); + Obj.Record.Type = static_cast(Kinds.back()); + Obj.Record.Data = + ArrayRef(ThisRecord.bytes_begin(), ThisRecord.bytes_end()); + Obj.Record.RawData = Obj.Record.Data; + Obj.Record.Length = ThisRecord.size(); } } Index: llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -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) Index: llvm/trunk/tools/llvm-pdbdump/YamlSerializationContext.h =================================================================== --- llvm/trunk/tools/llvm-pdbdump/YamlSerializationContext.h +++ llvm/trunk/tools/llvm-pdbdump/YamlSerializationContext.h @@ -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 Index: llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -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 @@ std::unique_ptr &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(generic_error_code::unspecified, @@ -382,6 +384,13 @@ } } + 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)); } Index: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp +++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp @@ -331,8 +331,15 @@ 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 @@ 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 @@ if (opts::CodeViewMergedTypes) { ScopedPrinter W(outs()); - dumpCodeViewMergedTypes(W, CVTypes); + dumpCodeViewMergedTypes(W, CVTypes.Builder); } return 0;