Index: include/llvm/DebugInfo/CodeView/CVTypeVisitor.h =================================================================== --- include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H #define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H +#include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -27,12 +28,6 @@ /// Visits the type records in Data. Sets the error flag on parse failures. Error visitTypeStream(const CVTypeArray &Types); - Error skipPadding(ArrayRef &Data); - - /// Visits individual member records of a field list record. Member records do - /// not describe their own length, and need special handling. - Error visitFieldList(const CVRecord &Record); - private: /// The interface to the class that gets notified of each visitation. TypeVisitorCallbacks &Callbacks; Index: include/llvm/DebugInfo/CodeView/CodeView.h =================================================================== --- include/llvm/DebugInfo/CodeView/CodeView.h +++ include/llvm/DebugInfo/CodeView/CodeView.h @@ -21,8 +21,6 @@ enum class TypeRecordKind : uint16_t { #define TYPE_RECORD(lf_ename, value, name) name = value, #include "TypeRecords.def" - // FIXME: Add serialization support - FieldList = 0x1203, }; /// Duplicate copy of the above enum, but using the official CV names. Useful Index: include/llvm/DebugInfo/CodeView/CodeViewError.h =================================================================== --- include/llvm/DebugInfo/CodeView/CodeViewError.h +++ include/llvm/DebugInfo/CodeView/CodeViewError.h @@ -21,6 +21,7 @@ insufficient_buffer, operation_unsupported, corrupt_record, + unknown_member_record, }; /// Base class for errors originating when parsing raw PDB files Index: include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h =================================================================== --- include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h +++ include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h @@ -49,15 +49,17 @@ void reset() { ListRecordBuilder::reset(); } - void writeBaseClass(const BaseClassRecord &Record); - void writeEnumerator(const EnumeratorRecord &Record); - void writeDataMember(const DataMemberRecord &Record); - void writeOneMethod(const OneMethodRecord &Record); - void writeOverloadedMethod(const OverloadedMethodRecord &Record); - void writeNestedType(const NestedTypeRecord &Record); - void writeStaticDataMember(const StaticDataMemberRecord &Record); - void writeVirtualBaseClass(const VirtualBaseClassRecord &Record); - void writeVFPtr(const VFPtrRecord &Type); + void writeMemberType(const BaseClassRecord &Record); + void writeMemberType(const EnumeratorRecord &Record); + void writeMemberType(const DataMemberRecord &Record); + void writeMemberType(const OneMethodRecord &Record); + void writeMemberType(const OverloadedMethodRecord &Record); + void writeMemberType(const NestedTypeRecord &Record); + void writeMemberType(const StaticDataMemberRecord &Record); + void writeMemberType(const VirtualBaseClassRecord &Record); + void writeMemberType(const VFPtrRecord &Type); + + using ListRecordBuilder::writeMemberType; }; } } Index: include/llvm/DebugInfo/CodeView/ListRecordBuilder.h =================================================================== --- include/llvm/DebugInfo/CodeView/ListRecordBuilder.h +++ include/llvm/DebugInfo/CodeView/ListRecordBuilder.h @@ -35,7 +35,7 @@ SubrecordStart = 0; } - void writeListContinuation(const ListContinuationRecord &R); + void writeMemberType(const ListContinuationRecord &R); /// Writes this list record as a possible sequence of records. TypeIndex writeListRecord(TypeTableBuilder &Table); Index: include/llvm/DebugInfo/CodeView/RecordSerialization.h =================================================================== --- include/llvm/DebugInfo/CodeView/RecordSerialization.h +++ include/llvm/DebugInfo/CodeView/RecordSerialization.h @@ -44,7 +44,7 @@ if (Data.size() < sizeof(*Res)) return make_error( cv_error_code::insufficient_buffer, - "Error consuming object. Not enough data for requested object size."); + "Insufficient bytes for expected object type"); Res = reinterpret_cast(Data.data()); Data = Data.drop_front(sizeof(*Res)); return Error::success(); @@ -146,9 +146,8 @@ Error deserialize(ArrayRef &Data) const { if (Data.empty()) - return make_error( - cv_error_code::insufficient_buffer, - "Null terminated string buffer is empty!"); + return make_error(cv_error_code::insufficient_buffer, + "Null terminated string is empty!"); StringRef Field; // Stop when we run out of bytes or we hit record padding bytes. @@ -159,7 +158,7 @@ if (Data.empty()) return make_error( cv_error_code::insufficient_buffer, - "Null terminated string buffer is empty!"); + "Null terminated string has no null terminator!"); } Data = Data.drop_front(1); return Error::success(); Index: include/llvm/DebugInfo/CodeView/TypeDeserializer.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/CodeView/TypeDeserializer.h @@ -0,0 +1,100 @@ +//===- TypeDeserializer.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_TYPEDESERIALIZER_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H + +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { +class TypeDeserializerBase : public TypeVisitorCallbacks { +public: + explicit TypeDeserializerBase(TypeVisitorCallbacks &Recipient) + : Recipient(Recipient) {} + + Error visitTypeBegin(const CVRecord &Record) override { + return Recipient.visitTypeBegin(Record); + } + + Error visitTypeEnd(const CVRecord &Record) override { + return Recipient.visitTypeEnd(Record); + } + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownRecord(const CVRecord &CVR, \ + Name##Record &Record) override { \ + return defaultVisitKnownRecord(CVR, Record); \ + } +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "TypeRecords.def" + +protected: + TypeVisitorCallbacks &Recipient; + + template + Error deserializeRecord(ArrayRef &Data, TypeLeafKind Kind, + T &Record) const { + TypeRecordKind RK = static_cast(Kind); + auto ExpectedRecord = T::deserialize(RK, Data); + if (!ExpectedRecord) + return ExpectedRecord.takeError(); + Record = std::move(*ExpectedRecord); + return Error::success(); + } + +private: + template + Error defaultVisitKnownRecord(const CVRecord &CVR, T &Record) { + ArrayRef RD = CVR.Data; + if (auto EC = deserializeRecord(RD, CVR.Type, Record)) + return EC; + return Recipient.visitKnownRecord(CVR, Record); + } +}; + +class TypeDeserializer : public TypeDeserializerBase { +public: + explicit TypeDeserializer(TypeVisitorCallbacks &Recipient) + : TypeDeserializerBase(Recipient) {} + + /// FieldList records need special handling. For starters, they do not + /// describe their own length, so a different extraction algorithm is + /// necessary. Secondly, a single FieldList record will result in the + /// deserialization of many records. So even though the top level visitor + /// calls visitFieldBegin() on a single record, multiple records get visited + /// through the callback interface. + Error visitKnownRecord(const CVRecord &CVR, + FieldListRecord &Record) override; + +private: + template + Error visitKnownMember(ArrayRef &Data, TypeLeafKind Kind, + T &Record) { + ArrayRef OldData = Data; + if (auto EC = deserializeRecord(Data, Kind, Record)) + return EC; + + CVRecord CVR; + CVR.Length = OldData.size() - Data.size(); + CVR.Data = OldData.slice(0, CVR.Length); + CVR.RawData = CVR.Data; + return Recipient.visitKnownRecord(CVR, Record); + } + + Error skipPadding(ArrayRef &Data); +}; +} +} + +#endif Index: include/llvm/DebugInfo/CodeView/TypeDumper.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeDumper.h +++ include/llvm/DebugInfo/CodeView/TypeDumper.h @@ -72,7 +72,8 @@ Error visitTypeEnd(const CVRecord &Record) override; #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visit##Name(Name##Record &Record) override; + Error visitKnownRecord(const CVRecord &CVR, \ + Name##Record &Record) override; #define MEMBER_RECORD(EnumName, EnumVal, Name) \ TYPE_RECORD(EnumName, EnumVal, Name) #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) Index: include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeRecord.h +++ include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -114,6 +114,7 @@ // LF_MODIFIER class ModifierRecord : public TypeRecord { public: + explicit ModifierRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} ModifierRecord(TypeIndex ModifiedType, ModifierOptions Modifiers) : TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType), Modifiers(Modifiers) {} @@ -141,6 +142,7 @@ // LF_PROCEDURE class ProcedureRecord : public TypeRecord { public: + explicit ProcedureRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} ProcedureRecord(TypeIndex ReturnType, CallingConvention CallConv, FunctionOptions Options, uint16_t ParameterCount, TypeIndex ArgumentList) @@ -182,6 +184,8 @@ // LF_MFUNCTION class MemberFunctionRecord : public TypeRecord { public: + explicit MemberFunctionRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} + MemberFunctionRecord(TypeIndex ReturnType, TypeIndex ClassType, TypeIndex ThisType, CallingConvention CallConv, FunctionOptions Options, uint16_t ParameterCount, @@ -233,6 +237,7 @@ // LF_MFUNC_ID class MemberFuncIdRecord : public TypeRecord { public: + explicit MemberFuncIdRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} MemberFuncIdRecord(TypeIndex ClassType, TypeIndex FunctionType, StringRef Name) : TypeRecord(TypeRecordKind::MemberFuncId), ClassType(ClassType), @@ -262,6 +267,8 @@ // LF_ARGLIST, LF_SUBSTR_LIST class ArgListRecord : public TypeRecord { public: + explicit ArgListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} + ArgListRecord(TypeRecordKind Kind, ArrayRef Indices) : TypeRecord(Kind), StringIndices(Indices) {} @@ -297,6 +304,8 @@ static const uint32_t PointerSizeShift = 13; static const uint32_t PointerSizeMask = 0xFF; + explicit PointerRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} + PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, PointerOptions Options, uint8_t Size) : PointerRecord(ReferentType, Kind, Mode, Options, Size, @@ -382,6 +391,7 @@ // LF_NESTTYPE class NestedTypeRecord : public TypeRecord { public: + explicit NestedTypeRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} NestedTypeRecord(TypeIndex Type, StringRef Name) : TypeRecord(TypeRecordKind::NestedType), Type(Type), Name(Name) {} @@ -406,9 +416,30 @@ StringRef Name; }; +// LF_FIELDLIST +class FieldListRecord : public TypeRecord { +public: + explicit FieldListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} + FieldListRecord(ArrayRef ListData) + : TypeRecord(TypeRecordKind::FieldList), ListData(ListData) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap) { return false; } + + static Expected deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + ArrayRef getFieldListData() const { return ListData; } + +private: + ArrayRef ListData; +}; + // LF_ARRAY class ArrayRecord : public TypeRecord { public: + explicit ArrayRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} ArrayRecord(TypeIndex ElementType, TypeIndex IndexType, uint64_t Size, StringRef Name) : TypeRecord(TypeRecordKind::Array), ElementType(ElementType), @@ -442,6 +473,7 @@ class TagRecord : public TypeRecord { protected: + explicit TagRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} TagRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList, StringRef Name, StringRef UniqueName) : TypeRecord(Kind), MemberCount(MemberCount), Options(Options), @@ -474,6 +506,7 @@ // LF_CLASS, LF_STRUCTURE, LF_INTERFACE class ClassRecord : public TagRecord { public: + explicit ClassRecord(TypeRecordKind Kind) : TagRecord(Kind) {} ClassRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options, HfaKind Hfa, WindowsRTClassKind WinRTKind, TypeIndex FieldList, TypeIndex DerivationList, TypeIndex VTableShape, uint64_t Size, @@ -520,6 +553,7 @@ // LF_UNION struct UnionRecord : public TagRecord { + explicit UnionRecord(TypeRecordKind Kind) : TagRecord(Kind) {} UnionRecord(uint16_t MemberCount, ClassOptions Options, HfaKind Hfa, TypeIndex FieldList, uint64_t Size, StringRef Name, StringRef UniqueName) @@ -554,6 +588,7 @@ // LF_ENUM class EnumRecord : public TagRecord { public: + explicit EnumRecord(TypeRecordKind Kind) : TagRecord(Kind) {} EnumRecord(uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList, StringRef Name, StringRef UniqueName, TypeIndex UnderlyingType) : TagRecord(TypeRecordKind::Enum, MemberCount, Options, FieldList, Name, @@ -587,6 +622,7 @@ // LF_BITFIELD class BitFieldRecord : public TypeRecord { public: + explicit BitFieldRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} BitFieldRecord(TypeIndex Type, uint8_t BitSize, uint8_t BitOffset) : TypeRecord(TypeRecordKind::BitField), Type(Type), BitSize(BitSize), BitOffset(BitOffset) {} @@ -617,6 +653,7 @@ // LF_VTSHAPE class VFTableShapeRecord : public TypeRecord { public: + explicit VFTableShapeRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} explicit VFTableShapeRecord(ArrayRef Slots) : TypeRecord(TypeRecordKind::VFTableShape), SlotsRef(Slots) {} explicit VFTableShapeRecord(std::vector Slots) @@ -653,6 +690,7 @@ // LF_TYPESERVER2 class TypeServer2Record : public TypeRecord { public: + explicit TypeServer2Record(TypeRecordKind Kind) : TypeRecord(Kind) {} TypeServer2Record(StringRef Guid, uint32_t Age, StringRef Name) : TypeRecord(TypeRecordKind::TypeServer2), Guid(Guid), Age(Age), Name(Name) {} @@ -685,6 +723,7 @@ // LF_STRING_ID class StringIdRecord : public TypeRecord { public: + explicit StringIdRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} StringIdRecord(TypeIndex Id, StringRef String) : TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {} @@ -712,6 +751,7 @@ // LF_FUNC_ID class FuncIdRecord : public TypeRecord { public: + explicit FuncIdRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} FuncIdRecord(TypeIndex ParentScope, TypeIndex FunctionType, StringRef Name) : TypeRecord(TypeRecordKind::FuncId), ParentScope(ParentScope), FunctionType(FunctionType), Name(Name) {} @@ -744,6 +784,7 @@ // LF_UDT_SRC_LINE class UdtSourceLineRecord : public TypeRecord { public: + explicit UdtSourceLineRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} UdtSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, uint32_t LineNumber) : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), SourceFile(SourceFile), LineNumber(LineNumber) {} @@ -774,6 +815,7 @@ // LF_UDT_MOD_SRC_LINE class UdtModSourceLineRecord : public TypeRecord { public: + explicit UdtModSourceLineRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} UdtModSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, uint32_t LineNumber, uint16_t Module) : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), @@ -812,6 +854,7 @@ // LF_BUILDINFO class BuildInfoRecord : public TypeRecord { public: + explicit BuildInfoRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} BuildInfoRecord(ArrayRef ArgIndices) : TypeRecord(TypeRecordKind::BuildInfo), ArgIndices(ArgIndices.begin(), ArgIndices.end()) {} @@ -836,6 +879,7 @@ // LF_VFTABLE class VFTableRecord : public TypeRecord { public: + explicit VFTableRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} VFTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable, uint32_t VFPtrOffset, StringRef Name, ArrayRef Methods) @@ -887,6 +931,7 @@ // LF_ONEMETHOD class OneMethodRecord : public TypeRecord { public: + explicit OneMethodRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} OneMethodRecord(TypeIndex Type, MethodKind Kind, MethodOptions Options, MemberAccess Access, int32_t VFTableOffset, StringRef Name) : TypeRecord(TypeRecordKind::OneMethod), Type(Type), Kind(Kind), @@ -932,6 +977,7 @@ // LF_METHODLIST class MethodOverloadListRecord : public TypeRecord { public: + explicit MethodOverloadListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} MethodOverloadListRecord(ArrayRef Methods) : TypeRecord(TypeRecordKind::MethodOverloadList), Methods(Methods) {} @@ -960,6 +1006,7 @@ /// For method overload sets. LF_METHOD class OverloadedMethodRecord : public TypeRecord { public: + explicit OverloadedMethodRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} OverloadedMethodRecord(uint16_t NumOverloads, TypeIndex MethodList, StringRef Name) : TypeRecord(TypeRecordKind::OverloadedMethod), @@ -991,6 +1038,7 @@ // LF_MEMBER class DataMemberRecord : public TypeRecord { public: + explicit DataMemberRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} DataMemberRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset, StringRef Name) : TypeRecord(TypeRecordKind::DataMember), Access(Access), Type(Type), @@ -1025,6 +1073,7 @@ // LF_STMEMBER class StaticDataMemberRecord : public TypeRecord { public: + explicit StaticDataMemberRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} StaticDataMemberRecord(MemberAccess Access, TypeIndex Type, StringRef Name) : TypeRecord(TypeRecordKind::StaticDataMember), Access(Access), Type(Type), Name(Name) {} @@ -1055,6 +1104,7 @@ // LF_ENUMERATE class EnumeratorRecord : public TypeRecord { public: + explicit EnumeratorRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} EnumeratorRecord(MemberAccess Access, APSInt Value, StringRef Name) : TypeRecord(TypeRecordKind::Enumerator), Access(Access), Value(std::move(Value)), Name(Name) {} @@ -1085,6 +1135,7 @@ // LF_VFUNCTAB class VFPtrRecord : public TypeRecord { public: + explicit VFPtrRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} VFPtrRecord(TypeIndex Type) : TypeRecord(TypeRecordKind::VFPtr), Type(Type) {} @@ -1108,6 +1159,7 @@ // LF_BCLASS, LF_BINTERFACE class BaseClassRecord : public TypeRecord { public: + explicit BaseClassRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} BaseClassRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset) : TypeRecord(TypeRecordKind::BaseClass), Access(Access), Type(Type), Offset(Offset) {} @@ -1137,6 +1189,7 @@ // LF_VBCLASS, LF_IVBCLASS class VirtualBaseClassRecord : public TypeRecord { public: + explicit VirtualBaseClassRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} VirtualBaseClassRecord(MemberAccess Access, TypeIndex BaseType, TypeIndex VBPtrType, uint64_t Offset, uint64_t Index) : TypeRecord(TypeRecordKind::VirtualBaseClass), Access(Access), @@ -1175,6 +1228,7 @@ /// together. The first will end in an LF_INDEX record that points to the next. class ListContinuationRecord : public TypeRecord { public: + explicit ListContinuationRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} ListContinuationRecord(TypeIndex ContinuationIndex) : TypeRecord(TypeRecordKind::ListContinuation), ContinuationIndex(ContinuationIndex) {} Index: include/llvm/DebugInfo/CodeView/TypeRecords.def =================================================================== --- include/llvm/DebugInfo/CodeView/TypeRecords.def +++ include/llvm/DebugInfo/CodeView/TypeRecords.def @@ -43,6 +43,8 @@ TYPE_RECORD(LF_MFUNCTION, 0x1009, MemberFunction) TYPE_RECORD(LF_ARGLIST, 0x1201, ArgList) +TYPE_RECORD(LF_FIELDLIST, 0x1203, FieldList) + TYPE_RECORD(LF_ARRAY, 0x1503, Array) TYPE_RECORD(LF_CLASS, 0x1504, Class) TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class) @@ -159,7 +161,6 @@ CV_TYPE(LF_SKIP, 0x1200) CV_TYPE(LF_DEFARG_ST, 0x1202) -CV_TYPE(LF_FIELDLIST, 0x1203) CV_TYPE(LF_DERIVED, 0x1204) CV_TYPE(LF_DIMCONU, 0x1207) CV_TYPE(LF_DIMCONLU, 0x1208) Index: include/llvm/DebugInfo/CodeView/TypeTableBuilder.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -37,26 +37,26 @@ virtual ~TypeTableBuilder(); public: - TypeIndex writeModifier(const ModifierRecord &Record); - TypeIndex writeProcedure(const ProcedureRecord &Record); - TypeIndex writeMemberFunction(const MemberFunctionRecord &Record); - TypeIndex writeArgList(const ArgListRecord &Record); - TypeIndex writePointer(const PointerRecord &Record); - TypeIndex writeArray(const ArrayRecord &Record); - TypeIndex writeClass(const ClassRecord &Record); - TypeIndex writeUnion(const UnionRecord &Record); - TypeIndex writeEnum(const EnumRecord &Record); - TypeIndex writeBitField(const BitFieldRecord &Record); - TypeIndex writeVFTableShape(const VFTableShapeRecord &Record); - TypeIndex writeStringId(const StringIdRecord &Record); - TypeIndex writeVFTable(const VFTableRecord &Record); - TypeIndex writeUdtSourceLine(const UdtSourceLineRecord &Record); - TypeIndex writeUdtModSourceLine(const UdtModSourceLineRecord &Record); - TypeIndex writeFuncId(const FuncIdRecord &Record); - TypeIndex writeMemberFuncId(const MemberFuncIdRecord &Record); - TypeIndex writeBuildInfo(const BuildInfoRecord &Record); - TypeIndex writeMethodOverloadList(const MethodOverloadListRecord &Record); - TypeIndex writeTypeServer2(const TypeServer2Record &Record); + TypeIndex writeKnownType(const ModifierRecord &Record); + TypeIndex writeKnownType(const ProcedureRecord &Record); + TypeIndex writeKnownType(const MemberFunctionRecord &Record); + TypeIndex writeKnownType(const ArgListRecord &Record); + TypeIndex writeKnownType(const PointerRecord &Record); + TypeIndex writeKnownType(const ArrayRecord &Record); + TypeIndex writeKnownType(const ClassRecord &Record); + TypeIndex writeKnownType(const UnionRecord &Record); + TypeIndex writeKnownType(const EnumRecord &Record); + TypeIndex writeKnownType(const BitFieldRecord &Record); + TypeIndex writeKnownType(const VFTableShapeRecord &Record); + TypeIndex writeKnownType(const StringIdRecord &Record); + TypeIndex writeKnownType(const VFTableRecord &Record); + TypeIndex writeKnownType(const UdtSourceLineRecord &Record); + TypeIndex writeKnownType(const UdtModSourceLineRecord &Record); + TypeIndex writeKnownType(const FuncIdRecord &Record); + TypeIndex writeKnownType(const MemberFuncIdRecord &Record); + TypeIndex writeKnownType(const BuildInfoRecord &Record); + TypeIndex writeKnownType(const MethodOverloadListRecord &Record); + TypeIndex writeKnownType(const TypeServer2Record &Record); TypeIndex writeFieldList(FieldListRecordBuilder &FieldList); Index: include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h +++ include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h @@ -41,16 +41,11 @@ return Error::success(); } - virtual Error visitFieldListBegin(const CVRecord &Record) { - return Error::success(); - } - - virtual Error visitFieldListEnd(const CVRecord &Record) { - return Error::success(); - } - #define TYPE_RECORD(EnumName, EnumVal, Name) \ - virtual Error visit##Name(Name##Record &Record) { return Error::success(); } + virtual Error visitKnownRecord(const CVRecord &CVR, \ + Name##Record &Record) { \ + return Error::success(); \ + } #define MEMBER_RECORD(EnumName, EnumVal, Name) \ TYPE_RECORD(EnumName, EnumVal, Name) #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -212,7 +212,7 @@ // Build the fully qualified name of the scope. std::string ScopeName = getFullyQualifiedName(Scope); TypeIndex TI = - TypeTable.writeStringId(StringIdRecord(TypeIndex(), ScopeName)); + TypeTable.writeKnownType(StringIdRecord(TypeIndex(), ScopeName)); return recordTypeIndexForDINode(Scope, TI); } @@ -237,12 +237,12 @@ TypeIndex ClassType = getTypeIndex(Class); MemberFuncIdRecord MFuncId(ClassType, getMemberFunctionType(SP, Class), DisplayName); - TI = TypeTable.writeMemberFuncId(MFuncId); + TI = TypeTable.writeKnownType(MFuncId); } else { // Otherwise, this must be a free function. TypeIndex ParentScope = getScopeIndex(Scope); FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName); - TI = TypeTable.writeFuncId(FuncId); + TI = TypeTable.writeKnownType(FuncId); } return recordTypeIndexForDINode(SP, TI); @@ -1030,7 +1030,7 @@ StringRef Name = (i == 0) ? Ty->getName() : ""; // Update the element size and element type index for subsequent subranges. ElementSize *= Count; - ElementTypeIndex = TypeTable.writeArray( + ElementTypeIndex = TypeTable.writeKnownType( ArrayRecord(ElementTypeIndex, IndexType, ElementSize, Name)); } @@ -1174,7 +1174,7 @@ // do. PointerOptions PO = PointerOptions::None; PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8); - return TypeTable.writePointer(PR); + return TypeTable.writeKnownType(PR); } static PointerToMemberRepresentation @@ -1225,7 +1225,7 @@ MemberPointerInfo MPI( ClassTI, translatePtrToMemberRep(SizeInBytes, IsPMF, Ty->getFlags())); PointerRecord PR(PointeeTI, PK, PM, PO, SizeInBytes, MPI); - return TypeTable.writePointer(PR); + return TypeTable.writeKnownType(PR); } /// Given a DWARF calling convention, get the CodeView equivalent. If we don't @@ -1272,7 +1272,7 @@ return I->second; ModifierRecord MR(ModifiedTI, Mods); - return TypeTable.writeModifier(MR); + return TypeTable.writeKnownType(MR); } TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) { @@ -1289,13 +1289,13 @@ } ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices); - TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec); + TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec); CallingConvention CC = dwarfCCToCodeView(Ty->getCC()); ProcedureRecord Procedure(ReturnTypeIndex, CC, FunctionOptions::None, ArgTypeIndices.size(), ArgListIndex); - return TypeTable.writeProcedure(Procedure); + return TypeTable.writeKnownType(Procedure); } TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, @@ -1322,14 +1322,14 @@ } ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices); - TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec); + TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec); CallingConvention CC = dwarfCCToCodeView(Ty->getCC()); // TODO: Need to use the correct values for: // FunctionOptions // ThisPointerAdjustment. - TypeIndex TI = TypeTable.writeMemberFunction(MemberFunctionRecord( + TypeIndex TI = TypeTable.writeKnownType(MemberFunctionRecord( ReturnTypeIndex, ClassType, ThisTypeIndex, CC, FunctionOptions::None, ArgTypeIndices.size(), ArgListIndex, ThisAdjustment)); @@ -1428,7 +1428,7 @@ // We assume that the frontend provides all members in source declaration // order, which is what MSVC does. if (auto *Enumerator = dyn_cast_or_null(Element)) { - Fields.writeEnumerator(EnumeratorRecord( + Fields.writeMemberType(EnumeratorRecord( MemberAccess::Public, APSInt::getUnsigned(Enumerator->getValue()), Enumerator->getName())); EnumeratorCount++; @@ -1439,9 +1439,9 @@ std::string FullName = getFullyQualifiedName(Ty); - return TypeTable.writeEnum(EnumRecord(EnumeratorCount, CO, FTI, FullName, - Ty->getIdentifier(), - getTypeIndex(Ty->getBaseType()))); + return TypeTable.writeKnownType(EnumRecord(EnumeratorCount, CO, FTI, FullName, + Ty->getIdentifier(), + getTypeIndex(Ty->getBaseType()))); } //===----------------------------------------------------------------------===// @@ -1536,7 +1536,7 @@ ClassOptions CO = ClassOptions::ForwardReference | getCommonClassOptions(Ty); std::string FullName = getFullyQualifiedName(Ty); - TypeIndex FwdDeclTI = TypeTable.writeClass(ClassRecord( + TypeIndex FwdDeclTI = TypeTable.writeKnownType(ClassRecord( Kind, 0, CO, HfaKind::None, WindowsRTClassKind::None, TypeIndex(), TypeIndex(), TypeIndex(), 0, FullName, Ty->getIdentifier())); if (!Ty->isForwardDecl()) @@ -1562,12 +1562,12 @@ uint64_t SizeInBytes = Ty->getSizeInBits() / 8; - TypeIndex ClassTI = TypeTable.writeClass(ClassRecord( + TypeIndex ClassTI = TypeTable.writeKnownType(ClassRecord( Kind, FieldCount, CO, HfaKind::None, WindowsRTClassKind::None, FieldTI, TypeIndex(), VShapeTI, SizeInBytes, FullName, Ty->getIdentifier())); - TypeTable.writeUdtSourceLine(UdtSourceLineRecord( - ClassTI, TypeTable.writeStringId(StringIdRecord( + TypeTable.writeKnownType(UdtSourceLineRecord( + ClassTI, TypeTable.writeKnownType(StringIdRecord( TypeIndex(0x0), getFullFilepath(Ty->getFile()))), Ty->getLine())); @@ -1580,9 +1580,8 @@ ClassOptions CO = ClassOptions::ForwardReference | getCommonClassOptions(Ty); std::string FullName = getFullyQualifiedName(Ty); - TypeIndex FwdDeclTI = - TypeTable.writeUnion(UnionRecord(0, CO, HfaKind::None, TypeIndex(), 0, - FullName, Ty->getIdentifier())); + TypeIndex FwdDeclTI = TypeTable.writeKnownType(UnionRecord( + 0, CO, HfaKind::None, TypeIndex(), 0, FullName, Ty->getIdentifier())); if (!Ty->isForwardDecl()) DeferredCompleteTypes.push_back(Ty); return FwdDeclTI; @@ -1602,12 +1601,12 @@ uint64_t SizeInBytes = Ty->getSizeInBits() / 8; std::string FullName = getFullyQualifiedName(Ty); - TypeIndex UnionTI = TypeTable.writeUnion( + TypeIndex UnionTI = TypeTable.writeKnownType( UnionRecord(FieldCount, CO, HfaKind::None, FieldTI, SizeInBytes, FullName, Ty->getIdentifier())); - TypeTable.writeUdtSourceLine(UdtSourceLineRecord( - UnionTI, TypeTable.writeStringId(StringIdRecord( + TypeTable.writeKnownType(UdtSourceLineRecord( + UnionTI, TypeTable.writeKnownType(StringIdRecord( TypeIndex(0x0), getFullFilepath(Ty->getFile()))), Ty->getLine())); @@ -1634,14 +1633,14 @@ unsigned VBPtrOffset = 0; // FIXME: Despite the accessor name, the offset is really in bytes. unsigned VBTableIndex = I->getOffsetInBits() / 4; - Fields.writeVirtualBaseClass(VirtualBaseClassRecord( + Fields.writeMemberType(VirtualBaseClassRecord( translateAccessFlags(Ty->getTag(), I->getFlags()), getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset, VBTableIndex)); } else { assert(I->getOffsetInBits() % 8 == 0 && "bases must be on byte boundaries"); - Fields.writeBaseClass(BaseClassRecord( + Fields.writeMemberType(BaseClassRecord( translateAccessFlags(Ty->getTag(), I->getFlags()), getTypeIndex(I->getBaseType()), I->getOffsetInBits() / 8)); } @@ -1656,7 +1655,7 @@ translateAccessFlags(Ty->getTag(), Member->getFlags()); if (Member->isStaticMember()) { - Fields.writeStaticDataMember( + Fields.writeMemberType( StaticDataMemberRecord(Access, MemberBaseType, MemberName)); MemberCount++; continue; @@ -1672,11 +1671,11 @@ MemberOffsetInBits = CI->getZExtValue() + MemberInfo.BaseOffset; } StartBitOffset -= MemberOffsetInBits; - MemberBaseType = TypeTable.writeBitField(BitFieldRecord( + MemberBaseType = TypeTable.writeKnownType(BitFieldRecord( MemberBaseType, Member->getSizeInBits(), StartBitOffset)); } uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8; - Fields.writeDataMember(DataMemberRecord(Access, MemberBaseType, + Fields.writeMemberType(DataMemberRecord(Access, MemberBaseType, MemberOffsetInBytes, MemberName)); MemberCount++; } @@ -1703,11 +1702,11 @@ } assert(Methods.size() > 0 && "Empty methods map entry"); if (Methods.size() == 1) - Fields.writeOneMethod(Methods[0]); + Fields.writeMemberType(Methods[0]); else { TypeIndex MethodList = - TypeTable.writeMethodOverloadList(MethodOverloadListRecord(Methods)); - Fields.writeOverloadedMethod( + TypeTable.writeKnownType(MethodOverloadListRecord(Methods)); + Fields.writeMemberType( OverloadedMethodRecord(Methods.size(), MethodList, Name)); } } @@ -1715,7 +1714,7 @@ // Create nested classes. for (const DICompositeType *Nested : Info.NestedClasses) { NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName()); - Fields.writeNestedType(R); + Fields.writeMemberType(R); MemberCount++; } @@ -1728,7 +1727,7 @@ if (!VBPType.getIndex()) { // Make a 'const int *' type. ModifierRecord MR(TypeIndex::Int32(), ModifierOptions::Const); - TypeIndex ModifiedTI = TypeTable.writeModifier(MR); + TypeIndex ModifiedTI = TypeTable.writeKnownType(MR); PointerKind PK = getPointerSizeInBytes() == 8 ? PointerKind::Near64 : PointerKind::Near32; @@ -1736,7 +1735,7 @@ PointerOptions PO = PointerOptions::None; PointerRecord PR(ModifiedTI, PK, PM, PO, getPointerSizeInBytes()); - VBPType = TypeTable.writePointer(PR); + VBPType = TypeTable.writeKnownType(PR); } return VBPType; Index: lib/DebugInfo/CodeView/CMakeLists.txt =================================================================== --- lib/DebugInfo/CodeView/CMakeLists.txt +++ lib/DebugInfo/CodeView/CMakeLists.txt @@ -11,6 +11,7 @@ ModuleSubstreamVisitor.cpp RecordSerialization.cpp SymbolDumper.cpp + TypeDeserializer.cpp TypeDumper.cpp TypeRecord.cpp TypeRecordBuilder.cpp Index: lib/DebugInfo/CodeView/CVTypeVisitor.cpp =================================================================== --- lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -8,47 +8,39 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" + #include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/Msf/ByteStream.h" using namespace llvm; using namespace llvm::codeview; +CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) + : Callbacks(Callbacks) {} + template -static Error takeObject(ArrayRef &Data, const T *&Res) { - if (Data.size() < sizeof(*Res)) - return llvm::make_error(cv_error_code::insufficient_buffer); - Res = reinterpret_cast(Data.data()); - Data = Data.drop_front(sizeof(*Res)); +static Error visitKnownRecord(const CVRecord &Record, + TypeVisitorCallbacks &Callbacks) { + TypeRecordKind RK = static_cast(Record.Type); + T KnownRecord(RK); + if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) + return EC; return Error::success(); } -CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) - : Callbacks(Callbacks) {} - Error CVTypeVisitor::visitTypeRecord(const CVRecord &Record) { ArrayRef LeafData = Record.Data; if (auto EC = Callbacks.visitTypeBegin(Record)) return EC; + switch (Record.Type) { default: if (auto EC = Callbacks.visitUnknownType(Record)) return EC; break; - case LF_FIELDLIST: - if (auto EC = Callbacks.visitFieldListBegin(Record)) - return EC; - if (auto EC = visitFieldList(Record)) - return EC; - if (auto EC = Callbacks.visitFieldListEnd(Record)) - return EC; - break; #define TYPE_RECORD(EnumName, EnumVal, Name) \ case EnumName: { \ - TypeRecordKind RK = static_cast(EnumName); \ - auto ExpectedRecord = Name##Record::deserialize(RK, LeafData); \ - if (!ExpectedRecord) \ - return ExpectedRecord.takeError(); \ - if (auto EC = Callbacks.visit##Name(*ExpectedRecord)) \ + if (auto EC = visitKnownRecord(Record, Callbacks)) \ return EC; \ break; \ } @@ -57,8 +49,10 @@ #define MEMBER_RECORD(EnumName, EnumVal, Name) #include "llvm/DebugInfo/CodeView/TypeRecords.def" } + if (auto EC = Callbacks.visitTypeEnd(Record)) return EC; + return Error::success(); } @@ -70,55 +64,3 @@ } return Error::success(); } - -Error CVTypeVisitor::skipPadding(ArrayRef &Data) { - if (Data.empty()) - return Error::success(); - uint8_t Leaf = Data.front(); - if (Leaf < LF_PAD0) - return Error::success(); - // Leaf is greater than 0xf0. We should advance by the number of bytes in - // the low 4 bits. - unsigned BytesToAdvance = Leaf & 0x0F; - if (Data.size() < BytesToAdvance) { - return llvm::make_error(cv_error_code::corrupt_record, - "Invalid padding bytes!"); - } - Data = Data.drop_front(BytesToAdvance); - return Error::success(); -} - -/// Visits individual member records of a field list record. Member records do -/// not describe their own length, and need special handling. -Error CVTypeVisitor::visitFieldList(const CVRecord &Record) { - ArrayRef RecordData = Record.Data; - while (!RecordData.empty()) { - const ulittle16_t *LeafPtr; - if (auto EC = takeObject(RecordData, LeafPtr)) - return EC; - TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr)); - switch (Leaf) { - default: - // Field list records do not describe their own length, so we cannot - // continue parsing past an unknown member type. - if (auto EC = Callbacks.visitUnknownMember(Record)) - return llvm::make_error(cv_error_code::corrupt_record); -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - case EnumName: { \ - TypeRecordKind RK = static_cast(EnumName); \ - auto ExpectedRecord = Name##Record::deserialize(RK, RecordData); \ - if (!ExpectedRecord) \ - return ExpectedRecord.takeError(); \ - if (auto EC = Callbacks.visit##Name(*ExpectedRecord)) \ - return EC; \ - break; \ - } -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ - MEMBER_RECORD(EnumVal, EnumVal, AliasName) -#include "llvm/DebugInfo/CodeView/TypeRecords.def" - } - if (auto EC = skipPadding(RecordData)) - return EC; - } - return Error::success(); -} Index: lib/DebugInfo/CodeView/CodeViewError.cpp =================================================================== --- lib/DebugInfo/CodeView/CodeViewError.cpp +++ lib/DebugInfo/CodeView/CodeViewError.cpp @@ -33,6 +33,8 @@ return "The CodeView record is corrupted."; case cv_error_code::operation_unsupported: return "The requested operation is not supported."; + case cv_error_code::unknown_member_record: + return "The member record is of an unknown type."; } llvm_unreachable("Unrecognized cv_error_code"); } Index: lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp =================================================================== --- lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp +++ lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp @@ -15,7 +15,7 @@ FieldListRecordBuilder::FieldListRecordBuilder() : ListRecordBuilder(TypeRecordKind::FieldList) {} -void FieldListRecordBuilder::writeBaseClass(const BaseClassRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const BaseClassRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(TypeRecordKind::BaseClass); @@ -26,7 +26,7 @@ finishSubRecord(); } -void FieldListRecordBuilder::writeEnumerator(const EnumeratorRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const EnumeratorRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(TypeRecordKind::Enumerator); @@ -38,7 +38,7 @@ finishSubRecord(); } -void FieldListRecordBuilder::writeDataMember(const DataMemberRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const DataMemberRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(Record.getKind()); @@ -50,7 +50,7 @@ finishSubRecord(); } -void FieldListRecordBuilder::writeOverloadedMethod( +void FieldListRecordBuilder::writeMemberType( const OverloadedMethodRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); @@ -62,7 +62,7 @@ finishSubRecord(); } -void FieldListRecordBuilder::writeOneMethod(const OneMethodRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const OneMethodRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); uint16_t Flags = static_cast(Record.getAccess()); @@ -84,7 +84,7 @@ finishSubRecord(); } -void FieldListRecordBuilder::writeNestedType(const NestedTypeRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const NestedTypeRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(Record.getKind()); @@ -95,7 +95,7 @@ finishSubRecord(); } -void FieldListRecordBuilder::writeStaticDataMember( +void FieldListRecordBuilder::writeMemberType( const StaticDataMemberRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); @@ -107,7 +107,7 @@ finishSubRecord(); } -void FieldListRecordBuilder::writeVirtualBaseClass( +void FieldListRecordBuilder::writeMemberType( const VirtualBaseClassRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); @@ -121,7 +121,7 @@ finishSubRecord(); } -void FieldListRecordBuilder::writeVFPtr(const VFPtrRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const VFPtrRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(TypeRecordKind::VFPtr); Index: lib/DebugInfo/CodeView/ListRecordBuilder.cpp =================================================================== --- lib/DebugInfo/CodeView/ListRecordBuilder.cpp +++ lib/DebugInfo/CodeView/ListRecordBuilder.cpp @@ -17,7 +17,7 @@ ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : Kind(Kind), Builder(Kind) {} -void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) { +void ListRecordBuilder::writeMemberType(const ListContinuationRecord &R) { TypeRecordBuilder &Builder = getBuilder(); assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit"); Index: lib/DebugInfo/CodeView/TypeDeserializer.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/CodeView/TypeDeserializer.cpp @@ -0,0 +1,81 @@ +//===- TypeDeserializer.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" + +using namespace llvm; +using namespace llvm::codeview; + +template +static Error takeObject(ArrayRef &Data, const T *&Res) { + if (Data.size() < sizeof(*Res)) + return llvm::make_error(cv_error_code::insufficient_buffer); + Res = reinterpret_cast(Data.data()); + Data = Data.drop_front(sizeof(*Res)); + return Error::success(); +} + +Error TypeDeserializer::visitKnownRecord(const CVRecord &CVR, + FieldListRecord &Record) { + ArrayRef FieldListRecordData = CVR.Data; + auto ExpectedRecord = FieldListRecord::deserialize(TypeRecordKind::FieldList, + FieldListRecordData); + if (!ExpectedRecord) + return ExpectedRecord.takeError(); + + Record = *ExpectedRecord; + ArrayRef MemberData = Record.getFieldListData(); + + while (!MemberData.empty()) { + const ulittle16_t *LeafPtr; + if (auto EC = takeObject(MemberData, LeafPtr)) + return EC; + TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr)); + switch (Leaf) { + default: + // Field list records do not describe their own length, so we cannot + // continue parsing past a type that we don't know how to deserialize. + if (auto EC = Recipient.visitUnknownMember(CVR)) + return EC; + return llvm::make_error( + cv_error_code::unknown_member_record); +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + TypeRecordKind RK = static_cast(Leaf); \ + Name##Record Member(RK); \ + if (auto EC = visitKnownMember(MemberData, Leaf, Member)) \ + return EC; \ + break; \ + } +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ + MEMBER_RECORD(EnumVal, EnumVal, AliasName) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + } + if (auto EC = skipPadding(MemberData)) + return EC; + } + return Error::success(); +} + +Error TypeDeserializer::skipPadding(ArrayRef &Data) { + if (Data.empty()) + return Error::success(); + uint8_t Leaf = Data.front(); + if (Leaf < LF_PAD0) + return Error::success(); + // Leaf is greater than 0xf0. We should advance by the number of bytes in + // the low 4 bits. + unsigned BytesToAdvance = Leaf & 0x0F; + if (Data.size() < BytesToAdvance) { + return llvm::make_error(cv_error_code::corrupt_record, + "Invalid padding bytes!"); + } + Data = Data.drop_front(BytesToAdvance); + return Error::success(); +} Index: lib/DebugInfo/CodeView/TypeDumper.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeDumper.cpp +++ lib/DebugInfo/CodeView/TypeDumper.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/CodeView/TypeDumper.h" #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/MSF/ByteStream.h" @@ -195,8 +196,6 @@ case ename: \ return #name; #include "llvm/DebugInfo/CodeView/TypeRecords.def" - case LF_FIELDLIST: - return "FieldList"; default: break; } @@ -231,7 +230,13 @@ return Error::success(); } -Error CVTypeDumper::visitStringId(StringIdRecord &String) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + FieldListRecord &FieldList) { + return Error::success(); +} + +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + StringIdRecord &String) { printTypeIndex("Id", String.getId()); W->printString("StringData", String.getString()); // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. @@ -239,7 +244,8 @@ return Error::success(); } -Error CVTypeDumper::visitArgList(ArgListRecord &Args) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + ArgListRecord &Args) { auto Indices = Args.getIndices(); uint32_t Size = Indices.size(); W->printNumber("NumArgs", Size); @@ -257,7 +263,8 @@ return Error::success(); } -Error CVTypeDumper::visitClass(ClassRecord &Class) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + ClassRecord &Class) { uint16_t Props = static_cast(Class.getOptions()); W->printNumber("MemberCount", Class.getMemberCount()); W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); @@ -272,7 +279,8 @@ return Error::success(); } -Error CVTypeDumper::visitUnion(UnionRecord &Union) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + UnionRecord &Union) { uint16_t Props = static_cast(Union.getOptions()); W->printNumber("MemberCount", Union.getMemberCount()); W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); @@ -285,7 +293,8 @@ return Error::success(); } -Error CVTypeDumper::visitEnum(EnumRecord &Enum) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + EnumRecord &Enum) { uint16_t Props = static_cast(Enum.getOptions()); W->printNumber("NumEnumerators", Enum.getMemberCount()); W->printFlags("Properties", uint16_t(Enum.getOptions()), @@ -299,7 +308,8 @@ return Error::success(); } -Error CVTypeDumper::visitArray(ArrayRecord &AT) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + ArrayRecord &AT) { printTypeIndex("ElementType", AT.getElementType()); printTypeIndex("IndexType", AT.getIndexType()); W->printNumber("SizeOf", AT.getSize()); @@ -308,7 +318,8 @@ return Error::success(); } -Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + VFTableRecord &VFT) { printTypeIndex("CompleteClass", VFT.getCompleteClass()); printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable()); W->printHex("VFPtrOffset", VFT.getVFPtrOffset()); @@ -319,7 +330,8 @@ return Error::success(); } -Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + MemberFuncIdRecord &Id) { printTypeIndex("ClassType", Id.getClassType()); printTypeIndex("FunctionType", Id.getFunctionType()); W->printString("Name", Id.getName()); @@ -327,7 +339,8 @@ return Error::success(); } -Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + ProcedureRecord &Proc) { printTypeIndex("ReturnType", Proc.getReturnType()); W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()), makeArrayRef(CallingConventions)); @@ -345,7 +358,8 @@ return Error::success(); } -Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + MemberFunctionRecord &MF) { printTypeIndex("ReturnType", MF.getReturnType()); printTypeIndex("ClassType", MF.getClassType()); printTypeIndex("ThisType", MF.getThisType()); @@ -369,8 +383,8 @@ return Error::success(); } -Error CVTypeDumper::visitMethodOverloadList( - MethodOverloadListRecord &MethodList) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + MethodOverloadListRecord &MethodList) { for (auto &M : MethodList.getMethods()) { ListScope S(*W, "Method"); printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions()); @@ -381,7 +395,8 @@ return Error::success(); } -Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + FuncIdRecord &Func) { printTypeIndex("ParentScope", Func.getParentScope()); printTypeIndex("FunctionType", Func.getFunctionType()); W->printString("Name", Func.getName()); @@ -389,7 +404,8 @@ return Error::success(); } -Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + TypeServer2Record &TS) { W->printBinary("Signature", TS.getGuid()); W->printNumber("Age", TS.getAge()); W->printString("Name", TS.getName()); @@ -397,7 +413,8 @@ return Error::success(); } -Error CVTypeDumper::visitPointer(PointerRecord &Ptr) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + PointerRecord &Ptr) { printTypeIndex("PointeeType", Ptr.getReferentType()); W->printHex("PointerAttributes", uint32_t(Ptr.getOptions())); W->printEnum("PtrType", unsigned(Ptr.getPointerKind()), @@ -448,7 +465,8 @@ return Error::success(); } -Error CVTypeDumper::visitModifier(ModifierRecord &Mod) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + ModifierRecord &Mod) { uint16_t Mods = static_cast(Mod.getModifiers()); printTypeIndex("ModifiedType", Mod.getModifiedType()); W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames)); @@ -466,26 +484,30 @@ return Error::success(); } -Error CVTypeDumper::visitBitField(BitFieldRecord &BitField) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + BitFieldRecord &BitField) { printTypeIndex("Type", BitField.getType()); W->printNumber("BitSize", BitField.getBitSize()); W->printNumber("BitOffset", BitField.getBitOffset()); return Error::success(); } -Error CVTypeDumper::visitVFTableShape(VFTableShapeRecord &Shape) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + VFTableShapeRecord &Shape) { W->printNumber("VFEntryCount", Shape.getEntryCount()); return Error::success(); } -Error CVTypeDumper::visitUdtSourceLine(UdtSourceLineRecord &Line) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + UdtSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printTypeIndex("SourceFile", Line.getSourceFile()); W->printNumber("LineNumber", Line.getLineNumber()); return Error::success(); } -Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + UdtModSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printTypeIndex("SourceFile", Line.getSourceFile()); W->printNumber("LineNumber", Line.getLineNumber()); @@ -493,7 +515,8 @@ return Error::success(); } -Error CVTypeDumper::visitBuildInfo(BuildInfoRecord &Args) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + BuildInfoRecord &Args) { W->printNumber("NumArgs", static_cast(Args.getArgs().size())); ListScope Arguments(*W, "Arguments"); @@ -533,7 +556,8 @@ return Error::success(); } -Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + NestedTypeRecord &Nested) { DictScope S(*W, "NestedType"); printTypeIndex("Type", Nested.getNestedType()); W->printString("Name", Nested.getName()); @@ -541,7 +565,8 @@ return Error::success(); } -Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + OneMethodRecord &Method) { DictScope S(*W, "OneMethod"); MethodKind K = Method.getKind(); printMemberAttributes(Method.getAccess(), K, Method.getOptions()); @@ -554,7 +579,8 @@ return Error::success(); } -Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + OverloadedMethodRecord &Method) { DictScope S(*W, "OverloadedMethod"); W->printHex("MethodCount", Method.getNumOverloads()); printTypeIndex("MethodListIndex", Method.getMethodList()); @@ -563,7 +589,8 @@ return Error::success(); } -Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + DataMemberRecord &Field) { DictScope S(*W, "DataMember"); printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -574,7 +601,8 @@ return Error::success(); } -Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + StaticDataMemberRecord &Field) { DictScope S(*W, "StaticDataMember"); printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -584,13 +612,15 @@ return Error::success(); } -Error CVTypeDumper::visitVFPtr(VFPtrRecord &VFTable) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + VFPtrRecord &VFTable) { DictScope S(*W, "VFPtr"); printTypeIndex("Type", VFTable.getType()); return Error::success(); } -Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + EnumeratorRecord &Enum) { DictScope S(*W, "Enumerator"); printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -600,7 +630,8 @@ return Error::success(); } -Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + BaseClassRecord &Base) { DictScope S(*W, "BaseClass"); printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -609,7 +640,8 @@ return Error::success(); } -Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + VirtualBaseClassRecord &Base) { DictScope S(*W, "VirtualBaseClass"); printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -620,7 +652,8 @@ return Error::success(); } -Error CVTypeDumper::visitListContinuation(ListContinuationRecord &Cont) { +Error CVTypeDumper::visitKnownRecord(const CVRecord &CVR, + ListContinuationRecord &Cont) { DictScope S(*W, "ListContinuation"); printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); return Error::success(); @@ -665,7 +698,8 @@ Error CVTypeDumper::dump(const CVRecord &Record) { assert(W && "printer should not be null"); - CVTypeVisitor Visitor(*this); + TypeDeserializer Deserializer(*this); + CVTypeVisitor Visitor(Deserializer); if (auto EC = Visitor.visitTypeRecord(Record)) return EC; @@ -674,7 +708,9 @@ Error CVTypeDumper::dump(const CVTypeArray &Types) { assert(W && "printer should not be null"); - CVTypeVisitor Visitor(*this); + TypeDeserializer Deserializer(*this); + CVTypeVisitor Visitor(Deserializer); + if (auto EC = Visitor.visitTypeStream(Types)) return EC; return Error::success(); Index: lib/DebugInfo/CodeView/TypeRecord.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeRecord.cpp +++ lib/DebugInfo/CodeView/TypeRecord.cpp @@ -114,6 +114,11 @@ return NestedTypeRecord(L->Type, Name); } +Expected +FieldListRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { + return FieldListRecord(Data); +} + Expected ArrayRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; Index: lib/DebugInfo/CodeView/TypeStreamMerger.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -58,7 +59,8 @@ /// TypeVisitorCallbacks overrides. #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visit##Name(Name##Record &Record) override; + Error visitKnownRecord(const CVRecord &CVR, \ + Name##Record &Record) override; #define MEMBER_RECORD(EnumName, EnumVal, Name) \ TYPE_RECORD(EnumName, EnumVal, Name) #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) @@ -70,11 +72,28 @@ Error visitTypeBegin(const CVRecord &Record) override; Error visitTypeEnd(const CVRecord &Record) override; - Error visitFieldListEnd(const CVRecord &Record) override; - bool mergeStream(const CVTypeArray &Types); private: + template + Error visitKnownRecordImpl(RecordType &Record) { + FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); + IndexMap.push_back(DestStream.writeKnownType(Record)); + return Error::success(); + } + + Error visitKnownRecordImpl(FieldListRecord &Record) { + // Don't do anything, this will get written in the call to visitTypeEnd(). + return Error::success(); + } + + template + Error visitKnownMemberRecordImpl(RecordType &Record) { + FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); + FieldBuilder.writeMemberType(Record); + return Error::success(); + } + bool hadError() { return FoundBadTypeIndex; } bool FoundBadTypeIndex = false; @@ -93,33 +112,31 @@ } // end anonymous namespace Error TypeStreamMerger::visitTypeBegin(const CVRecord &Rec) { - BeginIndexMapSize = IndexMap.size(); + if (Rec.Type != TypeLeafKind::LF_FIELDLIST) + BeginIndexMapSize = IndexMap.size(); return Error::success(); } Error TypeStreamMerger::visitTypeEnd(const CVRecord &Rec) { - assert(IndexMap.size() == BeginIndexMapSize + 1); - return Error::success(); -} - -Error TypeStreamMerger::visitFieldListEnd(const CVRecord &Rec) { - IndexMap.push_back(DestStream.writeFieldList(FieldBuilder)); - FieldBuilder.reset(); + if (Rec.Type == TypeLeafKind::LF_FIELDLIST) { + IndexMap.push_back(DestStream.writeFieldList(FieldBuilder)); + FieldBuilder.reset(); + } else { + assert(IndexMap.size() == BeginIndexMapSize + 1); + } return Error::success(); } #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error TypeStreamMerger::visit##Name(Name##Record &Record) { \ - FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \ - IndexMap.push_back(DestStream.write##Name(Record)); \ - return Error::success(); \ + Error TypeStreamMerger::visitKnownRecord(const CVRecord &CVR, \ + Name##Record &Record) { \ + return visitKnownRecordImpl(Record); \ } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - Error TypeStreamMerger::visit##Name(Name##Record &Record) { \ - FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \ - FieldBuilder.write##Name(Record); \ - return Error::success(); \ + Error TypeStreamMerger::visitKnownRecord(const CVRecord &CVR, \ + Name##Record &Record) { \ + return visitKnownMemberRecordImpl(Record); \ } #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" @@ -133,7 +150,9 @@ bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) { assert(IndexMap.empty()); - CVTypeVisitor Visitor(*this); + TypeDeserializer Deserializer(*this); + CVTypeVisitor Visitor(Deserializer); + if (auto EC = Visitor.visitTypeStream(Types)) { consumeError(std::move(EC)); return false; Index: lib/DebugInfo/CodeView/TypeTableBuilder.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeTableBuilder.cpp +++ lib/DebugInfo/CodeView/TypeTableBuilder.cpp @@ -21,7 +21,7 @@ TypeTableBuilder::~TypeTableBuilder() {} -TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ModifierRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getModifiedType()); @@ -30,7 +30,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ProcedureRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getReturnType()); @@ -42,8 +42,7 @@ return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const MemberFunctionRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getReturnType()); @@ -58,7 +57,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ArgListRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeUInt32(Record.getIndices().size()); @@ -69,7 +68,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const PointerRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getReferentType()); @@ -90,7 +89,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ArrayRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getElementType()); @@ -101,7 +100,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ClassRecord &Record) { assert((Record.getKind() == TypeRecordKind::Struct) || (Record.getKind() == TypeRecordKind::Class) || (Record.getKind() == TypeRecordKind::Interface)); @@ -128,7 +127,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const UnionRecord &Record) { TypeRecordBuilder Builder(TypeRecordKind::Union); Builder.writeUInt16(Record.getMemberCount()); uint16_t Flags = @@ -145,7 +144,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const EnumRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeUInt16(Record.getMemberCount()); @@ -161,7 +160,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const BitFieldRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getType()); @@ -171,8 +170,7 @@ return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const VFTableShapeRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); ArrayRef Slots = Record.getSlots(); @@ -189,8 +187,7 @@ return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeVFTable(const VFTableRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const VFTableRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getCompleteClass()); Builder.writeTypeIndex(Record.getOverriddenVTable()); @@ -209,15 +206,14 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeStringId(const StringIdRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const StringIdRecord &Record) { TypeRecordBuilder Builder(TypeRecordKind::StringId); Builder.writeTypeIndex(Record.getId()); Builder.writeNullTerminatedString(Record.getString()); return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const UdtSourceLineRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getUDT()); Builder.writeTypeIndex(Record.getSourceFile()); @@ -226,7 +222,7 @@ } TypeIndex -TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) { +TypeTableBuilder::writeKnownType(const UdtModSourceLineRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getUDT()); Builder.writeTypeIndex(Record.getSourceFile()); @@ -235,7 +231,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const FuncIdRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getParentScope()); Builder.writeTypeIndex(Record.getFunctionType()); @@ -243,8 +239,7 @@ return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const MemberFuncIdRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getClassType()); Builder.writeTypeIndex(Record.getFunctionType()); @@ -252,8 +247,7 @@ return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeBuildInfo(const BuildInfoRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const BuildInfoRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); assert(Record.getArgs().size() <= UINT16_MAX); Builder.writeUInt16(Record.getArgs().size()); @@ -270,8 +264,8 @@ return FieldList.writeListRecord(*this); } -TypeIndex TypeTableBuilder::writeMethodOverloadList( - const MethodOverloadListRecord &Record) { +TypeIndex +TypeTableBuilder::writeKnownType(const MethodOverloadListRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); for (const OneMethodRecord &Method : Record.getMethods()) { uint16_t Flags = static_cast(Method.getAccess()); @@ -294,7 +288,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeTypeServer2(const TypeServer2Record &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const TypeServer2Record &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeGuid(Record.getGuid()); Builder.writeUInt32(Record.getAge()); Index: lib/DebugInfo/PDB/Raw/TpiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -11,6 +11,7 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" @@ -96,17 +97,28 @@ uint32_t NumHashBuckets) : HashValues(HashValues), NumHashBuckets(NumHashBuckets) {} - Error visitUdtSourceLine(UdtSourceLineRecord &Rec) override { + Error visitKnownRecord(const CVRecord &CVR, + UdtSourceLineRecord &Rec) override { return verifySourceLine(Rec); } - Error visitUdtModSourceLine(UdtModSourceLineRecord &Rec) override { + Error visitKnownRecord(const CVRecord &CVR, + UdtModSourceLineRecord &Rec) override { return verifySourceLine(Rec); } - Error visitClass(ClassRecord &Rec) override { return verify(Rec); } - Error visitEnum(EnumRecord &Rec) override { return verify(Rec); } - Error visitUnion(UnionRecord &Rec) override { return verify(Rec); } + Error visitKnownRecord(const CVRecord &CVR, + ClassRecord &Rec) override { + return verify(Rec); + } + Error visitKnownRecord(const CVRecord &CVR, + EnumRecord &Rec) override { + return verify(Rec); + } + Error visitKnownRecord(const CVRecord &CVR, + UnionRecord &Rec) override { + return verify(Rec); + } Error visitTypeBegin(const CVRecord &Rec) override { ++Index; @@ -148,7 +160,8 @@ // Currently we only verify SRC_LINE records. Error TpiStream::verifyHashValues() { TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets); - CVTypeVisitor Visitor(Verifier); + TypeDeserializer Deserializer(Verifier); + CVTypeVisitor Visitor(Deserializer); return Visitor.visitTypeStream(TypeRecords); } Index: tools/llvm-pdbdump/LLVMOutputStyle.h =================================================================== --- tools/llvm-pdbdump/LLVMOutputStyle.h +++ tools/llvm-pdbdump/LLVMOutputStyle.h @@ -46,7 +46,7 @@ PDBFile &File; ScopedPrinter P; - codeview::CVTypeDumper TD; + codeview::CVTypeDumper Dumper; }; } } Index: tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -83,7 +83,7 @@ } LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) - : File(File), P(outs()), TD(&P, false) {} + : File(File), P(outs()), Dumper(&P, false) {} Error LLVMOutputStyle::dump() { if (auto EC = dumpFileHeaders()) @@ -482,7 +482,7 @@ DictScope DD(P, ""); if (DumpRecords) { - if (auto EC = TD.dump(Type)) + if (auto EC = Dumper.dump(Type)) return EC; } @@ -498,16 +498,16 @@ // iterate them in order to build the list of types so that we can print // them when dumping module symbols. So when they want to dump symbols // but not types, use a null output stream. - ScopedPrinter *OldP = TD.getPrinter(); - TD.setPrinter(nullptr); + ScopedPrinter *OldP = Dumper.getPrinter(); + Dumper.setPrinter(nullptr); bool HadError = false; for (auto &Type : Tpi->types(&HadError)) { - if (auto EC = TD.dump(Type)) + if (auto EC = Dumper.dump(Type)) return EC; } - TD.setPrinter(OldP); + Dumper.setPrinter(OldP); dumpTpiHash(P, *Tpi); if (HadError) return make_error(raw_error_code::corrupt_file, @@ -586,7 +586,7 @@ if (ShouldDumpSymbols) { ListScope SS(P, "Symbols"); - codeview::CVSymbolDumper SD(P, TD, nullptr, false); + codeview::CVSymbolDumper SD(P, Dumper, nullptr, false); bool HadError = false; for (const auto &S : ModS.symbols(&HadError)) { DictScope DD(P, ""); @@ -796,7 +796,7 @@ P.printList("Section Offsets", Publics->getSectionOffsets(), printSectionOffset); ListScope L(P, "Symbols"); - codeview::CVSymbolDumper SD(P, TD, nullptr, false); + codeview::CVSymbolDumper SD(P, Dumper, nullptr, false); bool HadError = false; for (auto S : Publics->getSymbols(&HadError)) { DictScope DD(P, ""); Index: tools/llvm-readobj/llvm-readobj.h =================================================================== --- tools/llvm-readobj/llvm-readobj.h +++ tools/llvm-readobj/llvm-readobj.h @@ -23,6 +23,7 @@ // Various helper functions. LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg); + void error(llvm::Error ec); void error(std::error_code ec); void error(llvm::Error EC); template T unwrapOrError(ErrorOr EO) { Index: tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- tools/llvm-readobj/llvm-readobj.cpp +++ tools/llvm-readobj/llvm-readobj.cpp @@ -272,19 +272,17 @@ exit(1); } -void error(llvm::Error EC) { +void error(Error EC) { if (!EC) return; - handleAllErrors(std::move(EC), - [&](ErrorInfoBase &EI) { reportError(EI.message()); }); + [&](const ErrorInfoBase &EI) { reportError(EI.message()); }); } -void error(std::error_code EC) { - if (!EC) +void error(std::error_code ec) { + if (!ec) return; - - reportError(EC.message()); + reportError(ec.message()); } bool relocAddressLess(RelocationRef a, RelocationRef b) {