Index: include/llvm/DebugInfo/CodeView/CVRecord.h =================================================================== --- include/llvm/DebugInfo/CodeView/CVRecord.h +++ include/llvm/DebugInfo/CodeView/CVRecord.h @@ -22,14 +22,27 @@ namespace llvm { namespace codeview { -template struct CVRecord { - uint32_t Length; +template class CVRecord { +public: + CVRecord() {} + CVRecord(Kind K, ArrayRef Data) : Type(K), RecordData(Data) {} + + uint32_t length() const { return RecordData.size(); } + Kind kind() const { return Type; } + ArrayRef data() const { return RecordData; } + ArrayRef content() const { + return RecordData.drop_front(sizeof(RecordPrefix)); + } + Optional hash() const { return Hash; } + + void setHash(uint32_t Value) { Hash = Value; } + Kind Type; - ArrayRef Data; - ArrayRef RawData; + ArrayRef RecordData; Optional Hash; }; } + namespace msf { template @@ -43,17 +56,17 @@ if (auto EC = Reader.readObject(Prefix)) return EC; - Item.Length = Prefix->RecordLen; - if (Item.Length < 2) + if (Prefix->RecordLen < 2) return make_error(cv_error_code::corrupt_record); - Item.Type = static_cast(uint16_t(Prefix->RecordKind)); + Kind K = static_cast(uint16_t(Prefix->RecordKind)); Reader.setOffset(Offset); + ArrayRef RawData; if (auto EC = - Reader.readBytes(Item.RawData, Item.Length + sizeof(uint16_t))) + Reader.readBytes(RawData, Prefix->RecordLen + sizeof(uint16_t))) return EC; - Item.Data = Item.RawData.slice(sizeof(RecordPrefix)); - Len = Prefix->RecordLen + 2; + Item = codeview::CVRecord(K, RawData); + Len = Item.length(); return Error::success(); } }; Index: include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h =================================================================== --- include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h +++ include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h @@ -47,7 +47,7 @@ #include "CVSymbolTypes.def" void visitSymbolRecord(const CVRecord &Record) { - ArrayRef Data = Record.Data; + ArrayRef Data = Record.content(); auto *DerivedThis = static_cast(this); DerivedThis->visitSymbolBegin(Record.Type, Data); uint32_t RecordOffset = Delegate ? Delegate->getRecordOffset(Data) : 0; @@ -70,7 +70,7 @@ SYMBOL_RECORD(EnumVal, EnumVal, AliasName) #include "CVSymbolTypes.def" } - DerivedThis->visitSymbolEnd(Record.Type, Record.Data); + DerivedThis->visitSymbolEnd(Record.Type, Record.content()); } /// Visits the symbol records in Data. Sets the error flag on parse failures. Index: include/llvm/DebugInfo/CodeView/CVTypeVisitor.h =================================================================== --- include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -23,7 +23,8 @@ public: explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks); - Error visitTypeRecord(CVRecord &Record); + Error visitTypeRecord(CVType &Record); + Error visitMemberRecord(CVMemberTypeRecord &Record); /// Visits the type records in Data. Sets the error flag on parse failures. Error visitTypeStream(const CVTypeArray &Types); Index: include/llvm/DebugInfo/CodeView/TypeDeserializer.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeDeserializer.h +++ include/llvm/DebugInfo/CodeView/TypeDeserializer.h @@ -20,12 +20,14 @@ TypeDeserializer() {} #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVRecord &CVR, Name##Record &Record) \ - override { \ + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \ return defaultVisitKnownRecord(CVR, Record); \ } #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - TYPE_RECORD(EnumName, EnumVal, Name) + Error visitKnownMember(CVMemberTypeRecord &CVR, Name##Record &Record) \ + override { \ + return defaultVisitKnownMember(CVR, Record); \ + } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "TypeRecords.def" @@ -44,13 +46,19 @@ } private: - template - Error defaultVisitKnownRecord(CVRecord &CVR, T &Record) { - ArrayRef RD = CVR.Data; + template Error defaultVisitKnownRecord(CVType &CVR, T &Record) { + ArrayRef RD = CVR.content(); if (auto EC = deserializeRecord(RD, CVR.Type, Record)) return EC; return Error::success(); } + template + Error defaultVisitKnownMember(CVMemberTypeRecord &CVMR, T &Record) { + ArrayRef RD = CVMR.Data; + if (auto EC = deserializeRecord(RD, CVMR.Kind, Record)) + return EC; + return Error::success(); + } }; } } Index: include/llvm/DebugInfo/CodeView/TypeDumper.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeDumper.h +++ include/llvm/DebugInfo/CodeView/TypeDumper.h @@ -63,19 +63,21 @@ ScopedPrinter *getPrinter() { return W; } /// Action to take on unknown types. By default, they are ignored. - Error visitUnknownType(CVRecord &Record) override; - Error visitUnknownMember(CVRecord &Record) override; + Error visitUnknownType(CVType &Record) override; + Error visitUnknownMember(CVMemberTypeRecord &Record) override; /// Paired begin/end actions for all types. Receives all record data, /// including the fixed-length record prefix. - Error visitTypeBegin(CVRecord &Record) override; - Error visitTypeEnd(CVRecord &Record) override; + Error visitTypeBegin(CVType &Record) override; + Error visitTypeEnd(CVType &Record) override; + Error visitMemberBegin(CVMemberTypeRecord &Record) override; + Error visitMemberEnd(CVMemberTypeRecord &Record) override; #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVRecord &CVR, Name##Record &Record) \ - override; + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - TYPE_RECORD(EnumName, EnumVal, Name) + Error visitKnownMember(CVMemberTypeRecord &CVR, Name##Record &Record) \ + override; #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "TypeRecords.def" Index: include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeRecord.h +++ include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -29,6 +29,11 @@ using llvm::support::ulittle32_t; typedef CVRecord CVType; + +struct CVMemberTypeRecord { + TypeLeafKind Kind; + ArrayRef Data; +}; typedef msf::VarStreamArray CVTypeArray; /// Equvalent to CV_fldattr_t in cvinfo.h. Index: include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h +++ include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h @@ -51,7 +51,8 @@ } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \ + virtual Error visitKnownMember(CVMemberTypeRecord &CVR, \ + Name##Record &Record) override { \ visitMemberRecordImpl(Record); \ return Error::success(); \ } @@ -61,10 +62,7 @@ private: void updateCVRecord(CVType &Record) { StringRef S = TypeTableBuilder.getRecords().back(); - ArrayRef Data(S.bytes_begin(), S.bytes_end()); - Record.RawData = Data; - Record.Data = Record.RawData.drop_front(sizeof(RecordPrefix)); - Record.Length = Data.size() - sizeof(ulittle16_t); + Record.RecordData = ArrayRef(S.bytes_begin(), S.bytes_end()); } template void visitKnownRecordImpl(CVType &CVR, RecordKind &Record) { Index: include/llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h +++ include/llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h @@ -30,7 +30,7 @@ return Error::success(); } - virtual Error visitUnknownMember(CVRecord &Record) override { + virtual Error visitUnknownMember(CVMemberTypeRecord &Record) override { for (auto Visitor : Pipeline) { if (auto EC = Visitor->visitUnknownMember(Record)) return EC; @@ -38,14 +38,14 @@ return Error::success(); } - virtual Error visitTypeBegin(CVRecord &Record) override { + virtual Error visitTypeBegin(CVType &Record) override { for (auto Visitor : Pipeline) { if (auto EC = Visitor->visitTypeBegin(Record)) return EC; } return Error::success(); } - virtual Error visitTypeEnd(CVRecord &Record) override { + virtual Error visitTypeEnd(CVType &Record) override { for (auto Visitor : Pipeline) { if (auto EC = Visitor->visitTypeEnd(Record)) return EC; @@ -53,13 +53,27 @@ return Error::success(); } + virtual Error visitMemberBegin(CVMemberTypeRecord &Record) override { + for (auto Visitor : Pipeline) { + if (auto EC = Visitor->visitMemberBegin(Record)) + return EC; + } + return Error::success(); + } + virtual Error visitMemberEnd(CVMemberTypeRecord &Record) override { + for (auto Visitor : Pipeline) { + if (auto EC = Visitor->visitMemberEnd(Record)) + return EC; + } + return Error::success(); + } + void addCallbackToPipeline(TypeVisitorCallbacks &Callbacks) { Pipeline.push_back(&Callbacks); } #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVRecord &CVR, Name##Record &Record) \ - override { \ + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \ for (auto Visitor : Pipeline) { \ if (auto EC = Visitor->visitKnownRecord(CVR, Record)) \ return EC; \ @@ -67,7 +81,14 @@ return Error::success(); \ } #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - TYPE_RECORD(EnumName, EnumVal, Name) + Error visitKnownMember(CVMemberTypeRecord &CVMR, Name##Record &Record) \ + override { \ + for (auto Visitor : Pipeline) { \ + if (auto EC = Visitor->visitKnownMember(CVMR, Record)) \ + return EC; \ + } \ + return Error::success(); \ + } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" Index: include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h +++ include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h @@ -25,30 +25,33 @@ virtual ~TypeVisitorCallbacks() {} /// Action to take on unknown types. By default, they are ignored. - virtual Error visitUnknownType(CVRecord &Record) { - return Error::success(); - } - virtual Error visitUnknownMember(CVRecord &Record) { - return Error::success(); - } - + virtual Error visitUnknownType(CVType &Record) { return Error::success(); } /// Paired begin/end actions for all types. Receives all record data, /// including the fixed-length record prefix. visitTypeBegin() should return /// the type of the Record, or an error if it cannot be determined. - virtual Error visitTypeBegin(CVRecord &Record) { + virtual Error visitTypeBegin(CVType &Record) { return Error::success(); } + virtual Error visitTypeEnd(CVType &Record) { return Error::success(); } + + virtual Error visitUnknownMember(CVMemberTypeRecord &Record) { return Error::success(); } - virtual Error visitTypeEnd(CVRecord &Record) { + virtual Error visitMemberBegin(CVMemberTypeRecord &Record) { + return Error::success(); + } + virtual Error visitMemberEnd(CVMemberTypeRecord &Record) { return Error::success(); } #define TYPE_RECORD(EnumName, EnumVal, Name) \ - virtual Error visitKnownRecord(CVRecord &CVR, \ - Name##Record &Record) { \ + virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) { \ return Error::success(); \ } #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - TYPE_RECORD(EnumName, EnumVal, Name) + virtual Error visitKnownMember(CVMemberTypeRecord &CVM, \ + Name##Record &Record) { \ + return Error::success(); \ + } + #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "TypeRecords.def" Index: include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h +++ include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h @@ -32,11 +32,9 @@ class WritableStream; template <> struct SequencedItemTraits { - static size_t length(const codeview::CVType &Item) { - return Item.RawData.size(); - } + static size_t length(const codeview::CVType &Item) { return Item.length(); } static ArrayRef bytes(const codeview::CVType &Item) { - return Item.RawData; + return Item.data(); } }; } Index: lib/DebugInfo/CodeView/CVTypeVisitor.cpp =================================================================== --- lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -42,8 +42,8 @@ } template -static Expected deserializeMemberRecord(ArrayRef &Data, - TypeLeafKind Kind) { +static Expected +deserializeMemberRecord(ArrayRef &Data, TypeLeafKind Kind) { ArrayRef OldData = Data; TypeRecordKind RK = static_cast(Kind); auto ExpectedRecord = T::deserialize(RK, Data); @@ -53,20 +53,17 @@ if (auto EC = skipPadding(Data)) return std::move(EC); - CVType CVR; - CVR.Type = Kind; - CVR.Length = OldData.size() - Data.size(); - CVR.Data = OldData.slice(0, CVR.Length); - CVR.RawData = CVR.Data; - return CVR; + CVMemberTypeRecord CVMR; + CVMR.Kind = Kind; + CVMR.Data = OldData.drop_back(Data.size()); + return CVMR; } CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) : Callbacks(Callbacks) {} template -static Error visitKnownRecord(CVRecord &Record, - TypeVisitorCallbacks &Callbacks) { +static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) { TypeRecordKind RK = static_cast(Record.Type); T KnownRecord(RK); if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) @@ -74,7 +71,17 @@ return Error::success(); } -Error CVTypeVisitor::visitTypeRecord(CVRecord &Record) { +template +static Error visitKnownMember(CVMemberTypeRecord &Record, + TypeVisitorCallbacks &Callbacks) { + TypeRecordKind RK = static_cast(Record.Kind); + T KnownRecord(RK); + if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord)) + return EC; + return Error::success(); +} + +Error CVTypeVisitor::visitTypeRecord(CVType &Record) { if (auto EC = Callbacks.visitTypeBegin(Record)) return EC; @@ -91,14 +98,40 @@ } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ TYPE_RECORD(EnumVal, EnumVal, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + } + + if (auto EC = Callbacks.visitTypeEnd(Record)) + return EC; + + return Error::success(); +} + +Error CVTypeVisitor::visitMemberRecord(CVMemberTypeRecord &Record) { + if (auto EC = Callbacks.visitMemberBegin(Record)) + return EC; + + switch (Record.Kind) { + default: + if (auto EC = Callbacks.visitUnknownMember(Record)) + return EC; + break; #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - TYPE_RECORD(EnumName, EnumVal, Name) + case EnumName: { \ + if (auto EC = visitKnownMember(Record, Callbacks)) \ + return EC; \ + break; \ + } #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ - MEMBER_RECORD(EnumName, EnumVal, AliasName) + MEMBER_RECORD(EnumVal, EnumVal, AliasName) +#define TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" } - if (auto EC = Callbacks.visitTypeEnd(Record)) + if (auto EC = Callbacks.visitMemberEnd(Record)) return EC; return Error::success(); @@ -119,12 +152,12 @@ auto ExpectedRecord = deserializeMemberRecord(Data, Leaf); if (!ExpectedRecord) return ExpectedRecord.takeError(); - CVType &Record = *ExpectedRecord; - if (auto EC = Callbacks.visitTypeBegin(Record)) + CVMemberTypeRecord &Record = *ExpectedRecord; + if (auto EC = Callbacks.visitMemberBegin(Record)) return EC; - if (auto EC = visitKnownRecord(Record, Callbacks)) + if (auto EC = visitKnownMember(Record, Callbacks)) return EC; - if (auto EC = Callbacks.visitTypeEnd(Record)) + if (auto EC = Callbacks.visitMemberEnd(Record)) return EC; return Error::success(); } Index: lib/DebugInfo/CodeView/TypeDumper.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeDumper.cpp +++ lib/DebugInfo/CodeView/TypeDumper.cpp @@ -204,15 +204,12 @@ } Error CVTypeDumper::visitTypeBegin(CVRecord &Record) { + assert(!IsInFieldList); // Reset Name to the empty string. If the visitor sets it, we know it. Name = ""; W->startLine() << getLeafTypeName(Record.Type); - if (!IsInFieldList) { - // If this is a field list member, don't record its type index because it - // doesn't have one. Only the outer field list has a type index. - W->getOStream() << " (" << HexNumber(getNextTypeIndex()) << ")"; - } + W->getOStream() << " (" << HexNumber(getNextTypeIndex()) << ")"; W->getOStream() << " {\n"; W->indent(); W->printEnum("TypeLeafKind", unsigned(Record.Type), @@ -220,7 +217,6 @@ if (Record.Type == LF_FIELDLIST) { // Record that we're in a field list so that members do not get assigned // type indices. - assert(!IsInFieldList); IsInFieldList = true; } return Error::success(); @@ -231,15 +227,37 @@ assert(IsInFieldList); IsInFieldList = false; } + assert(!IsInFieldList); - if (!IsInFieldList) { - // Record every type that is not a field list member, even if Name is empty. - // CVUDTNames is indexed by type index, and must have one entry for every - // type. Field list members are not recorded, and are only referenced by - // their containing field list record. - recordType(Name); - } + // Record every type that is not a field list member, even if Name is empty. + // CVUDTNames is indexed by type index, and must have one entry for every + // type. Field list members are not recorded, and are only referenced by + // their containing field list record. + recordType(Name); + + if (PrintRecordBytes) + W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content())); + + W->unindent(); + W->startLine() << "}\n"; + return Error::success(); +} + +Error CVTypeDumper::visitMemberBegin(CVMemberTypeRecord &Record) { + assert(IsInFieldList); + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + + W->startLine() << getLeafTypeName(Record.Kind); + W->getOStream() << " {\n"; + W->indent(); + W->printEnum("TypeLeafKind", unsigned(Record.Kind), + makeArrayRef(LeafTypeNames)); + return Error::success(); +} +Error CVTypeDumper::visitMemberEnd(CVMemberTypeRecord &Record) { + assert(IsInFieldList); if (PrintRecordBytes) W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data)); @@ -573,18 +591,18 @@ } } -Error CVTypeDumper::visitUnknownMember(CVRecord &Record) { - W->printHex("UnknownMember", unsigned(Record.Type)); +Error CVTypeDumper::visitUnknownMember(CVMemberTypeRecord &Record) { + W->printHex("UnknownMember", unsigned(Record.Kind)); return Error::success(); } Error CVTypeDumper::visitUnknownType(CVRecord &Record) { - W->printEnum("Kind", uint16_t(Record.Type), makeArrayRef(LeafTypeNames)); - W->printNumber("Length", uint32_t(Record.Data.size())); + W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames)); + W->printNumber("Length", uint32_t(Record.content().size())); return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, NestedTypeRecord &Nested) { printTypeIndex("Type", Nested.getNestedType()); W->printString("Name", Nested.getName()); @@ -592,7 +610,7 @@ return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, OneMethodRecord &Method) { MethodKind K = Method.getKind(); printMemberAttributes(Method.getAccess(), K, Method.getOptions()); @@ -605,7 +623,7 @@ return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, OverloadedMethodRecord &Method) { W->printHex("MethodCount", Method.getNumOverloads()); printTypeIndex("MethodListIndex", Method.getMethodList()); @@ -614,7 +632,7 @@ return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, DataMemberRecord &Field) { printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -625,7 +643,7 @@ return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, StaticDataMemberRecord &Field) { printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -635,13 +653,13 @@ return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, VFPtrRecord &VFTable) { printTypeIndex("Type", VFTable.getType()); return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, EnumeratorRecord &Enum) { printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -651,7 +669,7 @@ return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, BaseClassRecord &Base) { printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -660,7 +678,7 @@ return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, VirtualBaseClassRecord &Base) { printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -671,7 +689,7 @@ return Error::success(); } -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, +Error CVTypeDumper::visitKnownMember(CVMemberTypeRecord &CVR, ListContinuationRecord &Cont) { printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); return Error::success(); Index: lib/DebugInfo/CodeView/TypeStreamMerger.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -60,18 +60,19 @@ /// TypeVisitorCallbacks overrides. #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVRecord &CVR, Name##Record &Record) \ - override; + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - TYPE_RECORD(EnumName, EnumVal, Name) + Error visitKnownMember(CVMemberTypeRecord &CVR, Name##Record &Record) \ + override; #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" - Error visitUnknownType(CVRecord &Record) override; + Error visitUnknownType(CVType &Record) override; - Error visitTypeBegin(CVRecord &Record) override; - Error visitTypeEnd(CVRecord &Record) override; + Error visitTypeBegin(CVType &Record) override; + Error visitTypeEnd(CVType &Record) override; + Error visitMemberEnd(CVMemberTypeRecord &Record) override; bool mergeStream(const CVTypeArray &Types); @@ -137,27 +138,30 @@ IndexMap.push_back(DestStream.writeFieldList(FieldBuilder)); FieldBuilder.reset(); IsInFieldList = false; - } else if (!IsInFieldList) { - assert(IndexMap.size() == BeginIndexMapSize + 1); } return Error::success(); } +Error TypeStreamMerger::visitMemberEnd(CVMemberTypeRecord &Rec) { + assert(IndexMap.size() == BeginIndexMapSize + 1); + return Error::success(); +} + #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error TypeStreamMerger::visitKnownRecord(CVRecord &CVR, \ + Error TypeStreamMerger::visitKnownRecord(CVType &CVR, \ Name##Record &Record) { \ return visitKnownRecordImpl(Record); \ } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - Error TypeStreamMerger::visitKnownRecord(CVRecord &CVR, \ + Error TypeStreamMerger::visitKnownMember(CVMemberTypeRecord &CVR, \ Name##Record &Record) { \ return visitKnownMemberRecordImpl(Record); \ } #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" -Error TypeStreamMerger::visitUnknownType(CVRecord &Rec) { +Error TypeStreamMerger::visitUnknownType(CVType &Rec) { // We failed to translate a type. Translate this index as "not translated". IndexMap.push_back( TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct)); Index: lib/DebugInfo/PDB/Raw/TpiRecordHashVisitor.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/TpiRecordHashVisitor.cpp +++ lib/DebugInfo/PDB/Raw/TpiRecordHashVisitor.cpp @@ -59,17 +59,17 @@ void TpiRecordHashUpdateVisitor::visitKnownRecordImpl(CVType &CVR, ClassRecord &Rec) { - CVR.Hash = getTpiHash(Rec, CVR.RawData); + CVR.Hash = getTpiHash(Rec, CVR.data()); } void TpiRecordHashUpdateVisitor::visitKnownRecordImpl(CVType &CVR, EnumRecord &Rec) { - CVR.Hash = getTpiHash(Rec, CVR.RawData); + CVR.Hash = getTpiHash(Rec, CVR.data()); } void TpiRecordHashUpdateVisitor::visitKnownRecordImpl(CVType &CVR, UnionRecord &Rec) { - CVR.Hash = getTpiHash(Rec, CVR.RawData); + CVR.Hash = getTpiHash(Rec, CVR.data()); } Error TpiRecordHashVerificationVisitor::visitKnownRecord( @@ -84,19 +84,19 @@ Error TpiRecordHashVerificationVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Rec) { - if (getTpiHash(Rec, CVR.RawData) % NumHashBuckets != HashValues[Index]) + if (getTpiHash(Rec, CVR.data()) % NumHashBuckets != HashValues[Index]) return errorInvalidHash(); return Error::success(); } Error TpiRecordHashVerificationVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Rec) { - if (getTpiHash(Rec, CVR.RawData) % NumHashBuckets != HashValues[Index]) + if (getTpiHash(Rec, CVR.data()) % NumHashBuckets != HashValues[Index]) return errorInvalidHash(); return Error::success(); } Error TpiRecordHashVerificationVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Rec) { - if (getTpiHash(Rec, CVR.RawData) % NumHashBuckets != HashValues[Index]) + if (getTpiHash(Rec, CVR.data()) % NumHashBuckets != HashValues[Index]) return errorInvalidHash(); return Error::success(); } Index: tools/llvm-pdbdump/CodeViewYaml.h =================================================================== --- tools/llvm-pdbdump/CodeViewYaml.h +++ tools/llvm-pdbdump/CodeViewYaml.h @@ -29,7 +29,8 @@ llvm::pdb::yaml::SerializationContext &Context) : YamlIO(IO), Context(Context) {} - virtual Error visitTypeBegin(CVRecord &Record) override; + virtual Error visitTypeBegin(CVType &Record) override; + virtual Error visitMemberBegin(CVMemberTypeRecord &Record) override; #define TYPE_RECORD(EnumName, EnumVal, Name) \ Error visitKnownRecord(CVRecord &CVR, Name##Record &Record) \ @@ -38,12 +39,20 @@ return Error::success(); \ } #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - TYPE_RECORD(EnumName, EnumVal, Name) + Error visitKnownMember(CVMemberTypeRecord &CVR, Name##Record &Record) \ + override { \ + visitKnownMemberImpl(#Name, Record); \ + return Error::success(); \ + } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" private: + template void visitKnownMemberImpl(const char *Name, T &Record) { + YamlIO.mapRequired(Name, Record); + } + template void visitKnownRecordImpl(const char *Name, CVType &Type, T &Record) { YamlIO.mapRequired(Name, Record); Index: tools/llvm-pdbdump/CodeViewYaml.cpp =================================================================== --- tools/llvm-pdbdump/CodeViewYaml.cpp +++ tools/llvm-pdbdump/CodeViewYaml.cpp @@ -15,7 +15,9 @@ #include "llvm/DebugInfo/CodeView/EnumTables.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeSerializationVisitor.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/PDB/Raw/TpiRecordHashVisitor.h" using namespace llvm; using namespace llvm::codeview; @@ -27,33 +29,34 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(VFTableSlotKind) LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef) LLVM_YAML_IS_SEQUENCE_VECTOR(CVType) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiRecord) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiFieldListRecord) namespace { struct FieldListRecordSplitter : public TypeVisitorCallbacks { public: explicit FieldListRecordSplitter( - std::vector &Records) + std::vector &Records) : Records(Records) {} #define TYPE_RECORD(EnumName, EnumVal, Name) #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVType &CVT, Name##Record &Record) override { \ - visitKnownRecordImpl(CVT); \ + Error visitKnownMember(CVMemberTypeRecord &CVT, Name##Record &Record) \ + override { \ + visitKnownMemberImpl(CVT); \ return Error::success(); \ } #include "llvm/DebugInfo/CodeView/TypeRecords.def" private: - void visitKnownRecordImpl(CVType &CVT) { - llvm::pdb::yaml::PdbTpiRecord R; + void visitKnownMemberImpl(CVMemberTypeRecord &CVT) { + llvm::pdb::yaml::PdbTpiFieldListRecord R; R.Record = CVT; Records.push_back(std::move(R)); } - std::vector &Records; + std::vector &Records; }; } @@ -525,14 +528,20 @@ } Error llvm::codeview::yaml::YamlTypeDumperCallbacks::visitTypeBegin( - CVRecord &CVR) { + CVType &CVR) { YamlIO.mapRequired("Kind", CVR.Type); return Error::success(); } +Error llvm::codeview::yaml::YamlTypeDumperCallbacks::visitMemberBegin( + CVMemberTypeRecord &Record) { + YamlIO.mapRequired("Kind", Record.Kind); + return Error::success(); +} + void llvm::codeview::yaml::YamlTypeDumperCallbacks::visitKnownRecordImpl( const char *Name, CVType &CVR, FieldListRecord &FieldList) { - std::vector FieldListRecords; + std::vector FieldListRecords; if (YamlIO.outputting()) { // 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 @@ -551,3 +560,36 @@ } YamlIO.mapRequired("FieldList", FieldListRecords, Context); } + +namespace llvm { +namespace yaml { +template <> +struct MappingContextTraits { + static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj, + pdb::yaml::SerializationContext &Context) { + codeview::TypeVisitorCallbackPipeline Pipeline; + codeview::TypeDeserializer Deserializer; + codeview::TypeSerializationVisitor Serializer(Context.FieldListBuilder, + Context.TypeTableBuilder); + pdb::TpiRecordHashUpdateVisitor Hasher; + + if (IO.outputting()) { + // For PDB to Yaml, deserialize into a high level record type, then dump + // it. + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Context.Dumper); + } else { + // For Yaml to PDB, extract from the high level record type, then write it + // to bytes. + Pipeline.addCallbackToPipeline(Context.Dumper); + Pipeline.addCallbackToPipeline(Serializer); + Pipeline.addCallbackToPipeline(Hasher); + } + + codeview::CVTypeVisitor Visitor(Pipeline); + consumeError(Visitor.visitMemberRecord(Obj.Record)); + } +}; +} +} Index: tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -497,7 +497,7 @@ } if (DumpRecordBytes) - P.printBinaryBlock("Bytes", Type.Data); + P.printBinaryBlock("Bytes", Type.content()); } dumpTpiHash(P, *Tpi); if (HadError) @@ -604,7 +604,7 @@ if (opts::raw::DumpModuleSyms) SD.dump(S); if (opts::raw::DumpSymRecordBytes) - P.printBinaryBlock("Bytes", S.Data); + P.printBinaryBlock("Bytes", S.content()); } if (HadError) return make_error( @@ -813,7 +813,7 @@ SD.dump(S); if (opts::raw::DumpSymRecordBytes) - P.printBinaryBlock("Bytes", S.Data); + P.printBinaryBlock("Bytes", S.content()); } if (HadError) return make_error( Index: tools/llvm-pdbdump/PdbYaml.h =================================================================== --- tools/llvm-pdbdump/PdbYaml.h +++ tools/llvm-pdbdump/PdbYaml.h @@ -75,6 +75,10 @@ codeview::CVType Record; }; +struct PdbTpiFieldListRecord { + codeview::CVMemberTypeRecord Record; +}; + struct PdbTpiStream { PdbRaw_TpiVer Version; std::vector Records;