Index: include/llvm/DebugInfo/CodeView/CVTypeVisitor.h =================================================================== --- include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/CodeView/RecordIterator.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/ErrorOr.h" namespace llvm { namespace codeview { @@ -42,12 +43,10 @@ /// FIXME: Make the visitor interpret the trailing bytes so that clients don't /// need to. #define TYPE_RECORD(ClassName, LeafEnum) \ - void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ - ArrayRef LeafData) {} + void visit##ClassName(TypeLeafKind LeafType, ClassName &Record) {} #define TYPE_RECORD_ALIAS(ClassName, LeafEnum) #define MEMBER_RECORD(ClassName, LeafEnum) \ - void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ - ArrayRef &FieldData) {} + void visit##ClassName(TypeLeafKind LeafType, ClassName &Record) {} #define MEMBER_RECORD_ALIAS(ClassName, LeafEnum) #include "TypeRecords.def" @@ -68,10 +67,11 @@ break; #define TYPE_RECORD(ClassName, LeafEnum) \ case LeafEnum: { \ - const ClassName *Rec; \ - if (!CVTypeVisitor::consumeObject(LeafData, Rec)) \ - return; \ - DerivedThis->visit##ClassName(Record.Type, Rec, LeafData); \ + TypeRecordKind RK = static_cast(LeafEnum); \ + auto Result = ClassName::deserialize(RK, LeafData); \ + if (Result.getError()) \ + return parseError(); \ + DerivedThis->visit##ClassName(Record.Type, *Result); \ break; \ } #include "TypeRecords.def" @@ -120,10 +120,11 @@ return parseError(); #define MEMBER_RECORD(ClassName, LeafEnum) \ case LeafEnum: { \ - const ClassName *Rec; \ - if (!CVTypeVisitor::consumeObject(FieldData, Rec)) \ - return; \ - static_cast(this)->visit##ClassName(Leaf, Rec, FieldData); \ + TypeRecordKind RK = static_cast(LeafEnum); \ + auto Result = ClassName::deserialize(RK, FieldData); \ + if (Result.getError()) \ + return parseError(); \ + static_cast(this)->visit##ClassName(Leaf, *Result); \ break; \ } #include "TypeRecords.def" Index: include/llvm/DebugInfo/CodeView/CodeView.h =================================================================== --- include/llvm/DebugInfo/CodeView/CodeView.h +++ include/llvm/DebugInfo/CodeView/CodeView.h @@ -423,9 +423,10 @@ Alias = 0x150a, Member = 0x150d, StaticMember = 0x150e, - Method = 0x150f, + OverloadedMethod = 0x150f, NestedType = 0x1510, OneMethod = 0x1511, + TypeServer2 = 0x1515, VirtualFunctionTable = 0x151d, FunctionId = 0x1601, Index: include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeRecord.h +++ include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -10,11 +10,14 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORD_H #define LLVM_DEBUGINFO_CODEVIEW_TYPERECORD_H +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/ErrorOr.h" #include +#include namespace llvm { namespace codeview { @@ -23,6 +26,151 @@ using llvm::support::ulittle16_t; using llvm::support::ulittle32_t; +/// Decodes a numeric "leaf" value. These are integer literals encountered in +/// the type stream. If the value is positive and less than LF_NUMERIC (1 << +/// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR +/// that indicates the bitwidth and sign of the numeric data. +bool decodeNumericLeaf(ArrayRef &Data, APSInt &Num); + +inline bool decodeNumericLeaf(StringRef &Data, APSInt &Num) { + ArrayRef Bytes(reinterpret_cast(Data.data()), + Data.size()); + bool Success = decodeNumericLeaf(Bytes, Num); + Data = StringRef(reinterpret_cast(Bytes.data()), Bytes.size()); + return Success; +} + +/// Decode a numeric leaf value that is known to be a uint32_t. +bool decodeUIntLeaf(ArrayRef &Data, uint64_t &Num); + +/// Reinterpret a byte array as an array of characters. Does not interpret as +/// a C string, as StringRef has several helpers (split) that make that easy. +inline StringRef getBytesAsCharacters(ArrayRef LeafData) { + return StringRef(reinterpret_cast(LeafData.data()), + LeafData.size()); +} + +inline StringRef getBytesAsCString(ArrayRef LeafData) { + return getBytesAsCharacters(LeafData).split('\0').first; +} + +/// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if +/// there are not enough bytes remaining. Reinterprets the consumed bytes as a +/// T object and points 'Res' at them. +template +inline std::error_code consumeObject(U &Data, const T *&Res) { + if (Data.size() < sizeof(*Res)) + return std::make_error_code(std::errc::illegal_byte_sequence); + Res = reinterpret_cast(Data.data()); + Data = Data.drop_front(sizeof(*Res)); + return std::error_code(); +} + +inline std::error_code consumeCString(ArrayRef &Data, StringRef &Str) { + if (Data.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + + StringRef Rest; + std::tie(Str, Rest) = getBytesAsCharacters(Data).split('\0'); + Data = ArrayRef(Rest.bytes_begin(), Rest.bytes_end()); + return std::error_code(); +} + +template +inline std::error_code consumeArray(ArrayRef &Data, + ArrayRef &Result, uint32_t N) { + uint32_t Size = sizeof(T) * N; + if (Data.size() < N) + return std::make_error_code(std::errc::illegal_byte_sequence); + + Result = ArrayRef(reinterpret_cast(Data.data()), N); + Data = Data.drop_front(Size); + return std::error_code(); +} + +inline std::error_code consumeUInt32(StringRef &Data, uint32_t &Res) { + const support::ulittle32_t *IntPtr; + if (auto EC = consumeObject(Data, IntPtr)) + return EC; + Res = *IntPtr; + return std::error_code(); +} + +/// Equvalent to CV_fldattr_t in cvinfo.h. +struct MemberAttributes { + ulittle16_t Attrs; + + /// Get the access specifier. Valid for any kind of member. + MemberAccess getAccess() const { + return MemberAccess(unsigned(Attrs) & unsigned(MethodOptions::AccessMask)); + } + + /// Indicates if a method is defined with friend, virtual, static, etc. + MethodKind getMethodKind() const { + return MethodKind( + (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> 2); + } + + /// Get the flags that are not included in access control or method + /// properties. + MethodOptions getFlags() const { + return MethodOptions( + unsigned(Attrs) & + ~unsigned(MethodOptions::AccessMask | MethodOptions::MethodKindMask)); + } + + /// Is this method virtual. + bool isVirtual() const { + auto MP = getMethodKind(); + return MP != MethodKind::Vanilla && MP != MethodKind::Friend && + MP != MethodKind::Static; + } + + /// Does this member introduce a new virtual method. + bool isIntroducedVirtual() const { + auto MP = getMethodKind(); + return MP == MethodKind::IntroducingVirtual || + MP == MethodKind::PureIntroducingVirtual; + } +}; + +// Does not correspond to any tag, this is the tail of an LF_POINTER record +// if it represents a member pointer. +class MemberPointerInfo { +public: + MemberPointerInfo() {} + + MemberPointerInfo(TypeIndex ContainingType, + PointerToMemberRepresentation Representation) + : ContainingType(ContainingType), Representation(Representation) {} + + static ErrorOr deserialize(ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + TypeIndex T = L->ClassType; + uint16_t R = L->Representation; + PointerToMemberRepresentation PMR = + static_cast(R); + return MemberPointerInfo(T, PMR); + } + + TypeIndex getContainingType() const { return ContainingType; } + PointerToMemberRepresentation getRepresentation() const { + return Representation; + } + +private: + struct Layout { + TypeIndex ClassType; + ulittle16_t Representation; // PointerToMemberRepresentation + }; + + TypeIndex ContainingType; + PointerToMemberRepresentation Representation; +}; + class TypeRecord { protected: explicit TypeRecord(TypeRecordKind Kind) : Kind(Kind) {} @@ -34,20 +182,39 @@ TypeRecordKind Kind; }; +// LF_MODIFIER class ModifierRecord : public TypeRecord { public: - ModifierRecord(TypeIndex ModifiedType, ModifierOptions Options) + ModifierRecord(TypeIndex ModifiedType, ModifierOptions Modifiers) : TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType), - Options(Options) {} + Modifiers(Modifiers) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + TypeIndex M = L->ModifiedType; + uint16_t O = L->Modifiers; + ModifierOptions MO = static_cast(O); + return ModifierRecord(M, MO); + } TypeIndex getModifiedType() const { return ModifiedType; } - ModifierOptions getOptions() const { return Options; } + ModifierOptions getModifiers() const { return Modifiers; } private: + struct Layout { + TypeIndex ModifiedType; + ulittle16_t Modifiers; // ModifierOptions + }; + TypeIndex ModifiedType; - ModifierOptions Options; + ModifierOptions Modifiers; }; +// LF_PROCEDURE class ProcedureRecord : public TypeRecord { public: ProcedureRecord(TypeIndex ReturnType, CallingConvention CallConv, @@ -57,6 +224,18 @@ CallConv(CallConv), Options(Options), ParameterCount(ParameterCount), ArgumentList(ArgumentList) {} + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + return ProcedureRecord(L->ReturnType, L->CallConv, L->Options, + L->NumParameters, L->ArgListType); + } + + static uint32_t getLayoutSize() { return 2 + sizeof(Layout); } + TypeIndex getReturnType() const { return ReturnType; } CallingConvention getCallConv() const { return CallConv; } FunctionOptions getOptions() const { return Options; } @@ -64,6 +243,14 @@ TypeIndex getArgumentList() const { return ArgumentList; } private: + struct Layout { + TypeIndex ReturnType; + CallingConvention CallConv; + FunctionOptions Options; + ulittle16_t NumParameters; + TypeIndex ArgListType; + }; + TypeIndex ReturnType; CallingConvention CallConv; FunctionOptions Options; @@ -71,6 +258,7 @@ TypeIndex ArgumentList; }; +// LF_MFUNCTION class MemberFunctionRecord : public TypeRecord { public: MemberFunctionRecord(TypeIndex ReturnType, TypeIndex ClassType, @@ -83,6 +271,17 @@ ArgumentList(ArgumentList), ThisPointerAdjustment(ThisPointerAdjustment) {} + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + return MemberFunctionRecord(L->ReturnType, L->ClassType, L->ThisType, + L->CallConv, L->Options, L->NumParameters, + L->ArgListType, L->ThisAdjustment); + } + TypeIndex getReturnType() const { return ReturnType; } TypeIndex getClassType() const { return ClassType; } TypeIndex getThisType() const { return ThisType; } @@ -93,6 +292,17 @@ int32_t getThisPointerAdjustment() const { return ThisPointerAdjustment; } private: + struct Layout { + TypeIndex ReturnType; + TypeIndex ClassType; + TypeIndex ThisType; + CallingConvention CallConv; + FunctionOptions Options; + ulittle16_t NumParameters; + TypeIndex ArgListType; + little32_t ThisAdjustment; + }; + TypeIndex ReturnType; TypeIndex ClassType; TypeIndex ThisType; @@ -103,78 +313,253 @@ int32_t ThisPointerAdjustment; }; -class ArgumentListRecord : public TypeRecord { +// LF_MFUNC_ID +class MemberFunctionIdRecord : public TypeRecord { +public: + MemberFunctionIdRecord(TypeIndex ClassType, TypeIndex FunctionType, + StringRef Name) + : TypeRecord(TypeRecordKind::MemberFunctionId), ClassType(ClassType), + FunctionType(FunctionType), Name(Name) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + return MemberFunctionIdRecord(L->ClassType, L->FunctionType, Name); + } + + TypeIndex getClassType() const { return ClassType; } + TypeIndex getFunctionType() const { return FunctionType; } + StringRef getName() const { return Name; } + +private: + struct Layout { + TypeIndex ClassType; + TypeIndex FunctionType; + // Name: The null-terminated name follows. + }; + TypeIndex ClassType; + TypeIndex FunctionType; + StringRef Name; +}; + +// LF_ARGLIST, LF_SUBSTR_LIST +class StringListRecord : public TypeRecord { public: - explicit ArgumentListRecord(llvm::ArrayRef ArgumentTypes) - : TypeRecord(TypeRecordKind::ArgumentList), ArgumentTypes(ArgumentTypes) { + StringListRecord(TypeRecordKind Kind, ArrayRef Indices) + : TypeRecord(Kind), StringIndices(Indices) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + if (Kind != TypeRecordKind::SubstringList && + Kind != TypeRecordKind::ArgumentList) + return std::make_error_code(std::errc::illegal_byte_sequence); + + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + ArrayRef Indices; + if (auto EC = consumeArray(Data, Indices, L->NumArgs)) + return EC; + return StringListRecord(Kind, Indices); } - llvm::ArrayRef getArgumentTypes() const { return ArgumentTypes; } + ArrayRef getIndices() const { return StringIndices; } + + static uint32_t getLayoutSize() { return 2 + sizeof(Layout); } private: - llvm::ArrayRef ArgumentTypes; + struct Layout { + ulittle32_t NumArgs; // Number of arguments + // ArgTypes[]: Type indicies of arguments + }; + + ArrayRef StringIndices; }; -class PointerRecordBase : public TypeRecord { +// LF_POINTER +class PointerRecord : public TypeRecord { public: - PointerRecordBase(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, - PointerOptions Options, uint8_t Size) + static const uint32_t PointerKindShift = 0; + static const uint32_t PointerKindMask = 0x1F; + + static const uint32_t PointerModeShift = 5; + static const uint32_t PointerModeMask = 0x07; + + static const uint32_t PointerSizeShift = 13; + static const uint32_t PointerSizeMask = 0xFF; + + PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, + PointerOptions Options, uint8_t Size) + : PointerRecord(ReferentType, Kind, Mode, Options, Size, + MemberPointerInfo()) {} + + PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, + PointerOptions Options, uint8_t Size, + const MemberPointerInfo &Member) : TypeRecord(TypeRecordKind::Pointer), ReferentType(ReferentType), - PtrKind(Kind), Mode(Mode), Options(Options), Size(Size) {} + PtrKind(Kind), Mode(Mode), Options(Options), Size(Size), + MemberInfo(Member) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + PointerKind PtrKind = L->getPtrKind(); + PointerMode Mode = L->getPtrMode(); + uint32_t Opts = L->Attrs; + PointerOptions Options = static_cast(Opts); + uint8_t Size = L->getPtrSize(); + + if (L->isPointerToMember()) { + auto E = MemberPointerInfo::deserialize(Data); + if (E.getError()) + return std::make_error_code(std::errc::illegal_byte_sequence); + return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size, *E); + } + + return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size); + } TypeIndex getReferentType() const { return ReferentType; } PointerKind getPointerKind() const { return PtrKind; } PointerMode getMode() const { return Mode; } PointerOptions getOptions() const { return Options; } uint8_t getSize() const { return Size; } + MemberPointerInfo getMemberInfo() const { return MemberInfo; } + + bool isPointerToMember() const { + return Mode == PointerMode::PointerToDataMember || + Mode == PointerMode::PointerToMemberFunction; + } + bool isFlat() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Flat32)); + } + bool isConst() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Const)); + } + bool isVolatile() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Volatile)); + } + bool isUnaligned() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Unaligned)); + } private: + struct Layout { + TypeIndex PointeeType; + ulittle32_t Attrs; // pointer attributes + // if pointer to member: + // PointerToMemberTail + PointerKind getPtrKind() const { + return PointerKind(Attrs & PointerKindMask); + } + PointerMode getPtrMode() const { + return PointerMode((Attrs >> PointerModeShift) & PointerModeMask); + } + uint8_t getPtrSize() const { + return (Attrs >> PointerSizeShift) & PointerSizeMask; + } + bool isFlat() const { return Attrs & (1 << 8); } + bool isVolatile() const { return Attrs & (1 << 9); } + bool isConst() const { return Attrs & (1 << 10); } + bool isUnaligned() const { return Attrs & (1 << 11); } + + bool isPointerToDataMember() const { + return getPtrMode() == PointerMode::PointerToDataMember; + } + bool isPointerToMemberFunction() const { + return getPtrMode() == PointerMode::PointerToMemberFunction; + } + bool isPointerToMember() const { + return isPointerToMemberFunction() || isPointerToDataMember(); + } + }; + TypeIndex ReferentType; PointerKind PtrKind; PointerMode Mode; PointerOptions Options; uint8_t Size; + MemberPointerInfo MemberInfo; }; -class PointerRecord : public PointerRecordBase { -public: - PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, - PointerOptions Options, uint8_t Size) - : PointerRecordBase(ReferentType, Kind, Mode, Options, Size) {} -}; - -class PointerToMemberRecord : public PointerRecordBase { +// LF_NESTTYPE +class NestedTypeRecord : public TypeRecord { public: - PointerToMemberRecord(TypeIndex ReferentType, PointerKind Kind, - PointerMode Mode, PointerOptions Options, uint8_t Size, - TypeIndex ContainingType, - PointerToMemberRepresentation Representation) - : PointerRecordBase(ReferentType, Kind, Mode, Options, Size), - ContainingType(ContainingType), Representation(Representation) {} - - TypeIndex getContainingType() const { return ContainingType; } - PointerToMemberRepresentation getRepresentation() const { - return Representation; + NestedTypeRecord(TypeIndex Type, StringRef Name) + : TypeRecord(TypeRecordKind::NestedType), Type(Type), Name(Name) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + return NestedTypeRecord(L->Type, Name); } + TypeIndex getNestedType() const { return Type; } + StringRef getName() const { return Name; } + private: - TypeIndex ContainingType; - PointerToMemberRepresentation Representation; + struct Layout { + ulittle16_t Pad0; // Should be zero + TypeIndex Type; // Type index of nested type + // Name: Null-terminated string + }; + + TypeIndex Type; + StringRef Name; }; +// LF_ARRAY class ArrayRecord : public TypeRecord { public: ArrayRecord(TypeIndex ElementType, TypeIndex IndexType, uint64_t Size, - llvm::StringRef Name) + StringRef Name) : TypeRecord(TypeRecordKind::Array), ElementType(ElementType), IndexType(IndexType), Size(Size), Name(Name) {} + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + uint64_t Size; + if (!decodeUIntLeaf(Data, Size)) + return std::make_error_code(std::errc::illegal_byte_sequence); + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + return ArrayRecord(L->ElementType, L->IndexType, Size, Name); + } + TypeIndex getElementType() const { return ElementType; } TypeIndex getIndexType() const { return IndexType; } uint64_t getSize() const { return Size; } llvm::StringRef getName() const { return Name; } private: + struct Layout { + TypeIndex ElementType; + TypeIndex IndexType; + // SizeOf: LF_NUMERIC encoded size in bytes. Not element count! + // Name: The null-terminated name follows. + }; + TypeIndex ElementType; TypeIndex IndexType; uint64_t Size; @@ -189,6 +574,11 @@ FieldList(FieldList), Name(Name), UniqueName(UniqueName) {} public: + static const int HfaKindShift = 11; + static const int HfaKindMask = 0x1800; + static const int WinRTKindShift = 14; + static const int WinRTKindMask = 0xC000; + uint16_t getMemberCount() const { return MemberCount; } ClassOptions getOptions() const { return Options; } TypeIndex getFieldList() const { return FieldList; } @@ -203,17 +593,50 @@ StringRef UniqueName; }; -class AggregateRecord : public TagRecord { +// LF_CLASS, LF_STRUCTURE, LF_INTERFACE +class ClassRecord : public TagRecord { public: - AggregateRecord(TypeRecordKind Kind, uint16_t MemberCount, - ClassOptions Options, HfaKind Hfa, - WindowsRTClassKind WinRTKind, TypeIndex FieldList, - TypeIndex DerivationList, TypeIndex VTableShape, - uint64_t Size, StringRef Name, StringRef UniqueName) + ClassRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options, + HfaKind Hfa, WindowsRTClassKind WinRTKind, TypeIndex FieldList, + TypeIndex DerivationList, TypeIndex VTableShape, uint64_t Size, + StringRef Name, StringRef UniqueName) : TagRecord(Kind, MemberCount, Options, FieldList, Name, UniqueName), Hfa(Hfa), WinRTKind(WinRTKind), DerivationList(DerivationList), VTableShape(VTableShape), Size(Size) {} + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + uint64_t Size = 0; + StringRef Name; + StringRef UniqueName; + uint16_t Props; + + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + Props = L->Properties; + uint16_t WrtValue = (Props & WinRTKindMask) >> WinRTKindShift; + WindowsRTClassKind WRT = static_cast(WrtValue); + uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift; + HfaKind Hfa = static_cast(HfaMask); + + if (!decodeUIntLeaf(Data, Size)) + return std::make_error_code(std::errc::illegal_byte_sequence); + if (auto EC = consumeCString(Data, Name)) + return EC; + if (Props & uint16_t(ClassOptions::HasUniqueName)) { + UniqueName = StringRef(reinterpret_cast(Data.data())); + Data = Data.slice(UniqueName.size() + 1); + if (UniqueName.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + } + + ClassOptions Options = static_cast(Props); + return ClassRecord(Kind, L->MemberCount, Options, Hfa, WRT, L->FieldList, + L->DerivedFrom, L->VShape, Size, Name, UniqueName); + } + HfaKind getHfa() const { return Hfa; } WindowsRTClassKind getWinRTKind() const { return WinRTKind; } TypeIndex getDerivationList() const { return DerivationList; } @@ -221,6 +644,17 @@ uint64_t getSize() const { return Size; } private: + struct Layout { + ulittle16_t MemberCount; // Number of members in FieldList. + ulittle16_t Properties; // ClassOptions bitset + TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members + TypeIndex DerivedFrom; // LF_DERIVED: List of known derived classes + TypeIndex VShape; // LF_VTSHAPE: Shape of the vftable + // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC + // integer. + // Name: The null-terminated name follows. + }; + HfaKind Hfa; WindowsRTClassKind WinRTKind; TypeIndex DerivationList; @@ -228,6 +662,65 @@ uint64_t Size; }; +// LF_UNION +struct UnionRecord : public TagRecord { + UnionRecord(uint16_t MemberCount, ClassOptions Options, HfaKind Hfa, + TypeIndex FieldList, uint64_t Size, StringRef Name, + StringRef UniqueName) + : TagRecord(TypeRecordKind::Union, MemberCount, Options, FieldList, Name, + UniqueName), + Hfa(Hfa), Size(Size) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + uint64_t Size = 0; + StringRef Name; + StringRef UniqueName; + uint16_t Props; + + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + Props = L->Properties; + + uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift; + HfaKind Hfa = static_cast(HfaMask); + + if (!decodeUIntLeaf(Data, Size)) + return std::make_error_code(std::errc::illegal_byte_sequence); + if (auto EC = consumeCString(Data, Name)) + return EC; + if (Props & uint16_t(ClassOptions::HasUniqueName)) { + UniqueName = StringRef(reinterpret_cast(Data.data())); + Data = Data.slice(UniqueName.size() + 1); + if (UniqueName.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + } + + ClassOptions Options = static_cast(Props); + return UnionRecord(L->MemberCount, Options, Hfa, L->FieldList, Size, Name, + UniqueName); + } + + HfaKind getHfa() const { return Hfa; } + uint64_t getSize() const { return Size; } + +private: + struct Layout { + ulittle16_t MemberCount; // Number of members in FieldList. + ulittle16_t Properties; // ClassOptions bitset + TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members + // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC + // integer. + // Name: The null-terminated name follows. + }; + + HfaKind Hfa; + uint64_t Size; +}; + +// LF_ENUM class EnumRecord : public TagRecord { public: EnumRecord(uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList, @@ -236,9 +729,32 @@ UniqueName), UnderlyingType(UnderlyingType) {} + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + uint16_t P = L->Properties; + ClassOptions Options = static_cast(P); + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + return EnumRecord(L->NumEnumerators, Options, L->FieldListType, Name, Name, + L->UnderlyingType); + } + TypeIndex getUnderlyingType() const { return UnderlyingType; } private: + struct Layout { + ulittle16_t NumEnumerators; // Number of enumerators + ulittle16_t Properties; + TypeIndex UnderlyingType; + TypeIndex FieldListType; + // Name: The null-terminated name follows. + }; + TypeIndex UnderlyingType; }; @@ -258,311 +774,667 @@ uint8_t BitOffset; }; +// LF_VTSHAPE class VirtualTableShapeRecord : TypeRecord { public: explicit VirtualTableShapeRecord(ArrayRef Slots) + : TypeRecord(TypeRecordKind::VirtualTableShape), SlotsRef(Slots) {} + explicit VirtualTableShapeRecord(std::vector Slots) : TypeRecord(TypeRecordKind::VirtualTableShape), Slots(Slots) {} - ArrayRef getSlots() const { return Slots; } + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + std::vector Slots; + for (int I = 0; I < L->VFEntryCount; ++I) { + if (Data.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + + uint8_t Value = 0; + if (I % 2 == 0) + Value = Data[0] & 0x0F; + else { + Value = (Data[0] & 0xF0) >> 4; + Data = Data.slice(1); + } + Slots.push_back(static_cast(Value)); + } + if (L->VFEntryCount % 2 != 0) + Data = Data.slice(1); + return VirtualTableShapeRecord(Slots); + } -private: - ArrayRef Slots; -}; + ArrayRef getSlots() const { + if (!SlotsRef.empty()) + return SlotsRef; + return Slots; + } + uint32_t getEntryCount() const { return getSlots().size(); } -//===----------------------------------------------------------------------===// -// On-disk representation of type information +private: + struct Layout { + // Number of vftable entries. Each method may have more than one entry due + // to + // things like covariant return types. + ulittle16_t VFEntryCount; + // Descriptors[]: 4-bit virtual method descriptors of type CV_VTS_desc_e. + }; -// A CodeView type stream is a sequence of TypeRecords. Records larger than -// 65536 must chain on to a second record. Each TypeRecord is followed by one of -// the leaf types described below. +private: + ArrayRef SlotsRef; + std::vector Slots; +}; // LF_TYPESERVER2 -struct TypeServer2 { - char Signature[16]; // GUID - ulittle32_t Age; - // Name: Name of the PDB as a null-terminated string -}; +class TypeServer2Record : TypeRecord { +public: + TypeServer2Record(StringRef Guid, uint32_t Age, StringRef Name) + : TypeRecord(TypeRecordKind::TypeServer2), Guid(Guid), Age(Age), + Name(Name) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + return TypeServer2Record(StringRef(L->Guid, 16), L->Age, Name); + } -// LF_STRING_ID -struct StringId { - TypeIndex id; -}; + StringRef getGuid() const { return Guid; } -// LF_FUNC_ID -struct FuncId { - TypeIndex ParentScope; - TypeIndex FunctionType; - // Name: The null-terminated name follows. -}; + uint32_t getAge() const { return Age; } -// LF_CLASS, LF_STRUCTURE, LF_INTERFACE -struct ClassType { - ulittle16_t MemberCount; // Number of members in FieldList. - ulittle16_t Properties; // ClassOptions bitset - TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members - TypeIndex DerivedFrom; // LF_DERIVED: List of known derived classes - TypeIndex VShape; // LF_VTSHAPE: Shape of the vftable - // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer. - // Name: The null-terminated name follows. -}; + StringRef getName() const { return Name; } -// LF_UNION -struct UnionType { - ulittle16_t MemberCount; // Number of members in FieldList. - ulittle16_t Properties; // ClassOptions bitset - TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members - // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer. - // Name: The null-terminated name follows. +private: + struct Layout { + char Guid[16]; // GUID + ulittle32_t Age; + // Name: Name of the PDB as a null-terminated string + }; + + StringRef Guid; + uint32_t Age; + StringRef Name; }; -// LF_POINTER -struct PointerType { - TypeIndex PointeeType; - ulittle32_t Attrs; // pointer attributes - // if pointer to member: - // PointerToMemberTail +// LF_STRING_ID +class StringIdRecord : public TypeRecord { +public: + StringIdRecord(TypeIndex Id, StringRef String) + : TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + return StringIdRecord(L->id, Name); + } - PointerKind getPtrKind() const { return PointerKind(Attrs & 0x1f); } - PointerMode getPtrMode() const { return PointerMode((Attrs >> 5) & 0x07); } - bool isFlat() const { return Attrs & (1 << 8); } - bool isVolatile() const { return Attrs & (1 << 9); } - bool isConst() const { return Attrs & (1 << 10); } - bool isUnaligned() const { return Attrs & (1 << 11); } + TypeIndex getId() const { return Id; } - bool isPointerToDataMember() const { - return getPtrMode() == PointerMode::PointerToDataMember; - } - bool isPointerToMemberFunction() const { - return getPtrMode() == PointerMode::PointerToMemberFunction; - } - bool isPointerToMember() const { - return isPointerToMemberFunction() || isPointerToDataMember(); - } -}; + StringRef getString() const { return String; } -struct PointerToMemberTail { - TypeIndex ClassType; - ulittle16_t Representation; // PointerToMemberRepresentation -}; +private: + struct Layout { + TypeIndex id; + // Name: Name of the PDB as a null-terminated string + }; -/// In Clang parlance, these are "qualifiers". LF_MODIFIER -struct TypeModifier { - TypeIndex ModifiedType; - ulittle16_t Modifiers; // ModifierOptions + TypeIndex Id; + StringRef String; }; -// LF_VTSHAPE -struct VTableShape { - // Number of vftable entries. Each method may have more than one entry due to - // things like covariant return types. - ulittle16_t VFEntryCount; - // Descriptors[]: 4-bit virtual method descriptors of type CV_VTS_desc_e. -}; +// LF_FUNC_ID +class FuncIdRecord : public TypeRecord { +public: + FuncIdRecord(TypeIndex ParentScope, TypeIndex FunctionType, StringRef Name) + : TypeRecord(TypeRecordKind::FunctionId), ParentScope(ParentScope), + FunctionType(FunctionType), Name(Name) {} -// LF_UDT_SRC_LINE -struct UDTSrcLine { - TypeIndex UDT; // The user-defined type - TypeIndex SourceFile; // StringID containing the source filename - ulittle32_t LineNumber; -}; + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; -// LF_ARGLIST, LF_SUBSTR_LIST -struct ArgList { - ulittle32_t NumArgs; // Number of arguments - // ArgTypes[]: Type indicies of arguments -}; + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; -// LF_BUILDINFO -struct BuildInfo { - ulittle16_t NumArgs; // Number of arguments - // ArgTypes[]: Type indicies of arguments -}; + return FuncIdRecord(L->ParentScope, L->FunctionType, Name); + } -// LF_ENUM -struct EnumType { - ulittle16_t NumEnumerators; // Number of enumerators - ulittle16_t Properties; - TypeIndex UnderlyingType; - TypeIndex FieldListType; - // Name: The null-terminated name follows. -}; + TypeIndex getParentScope() const { return ParentScope; } -// LF_ARRAY -struct ArrayType { - TypeIndex ElementType; - TypeIndex IndexType; - // SizeOf: LF_NUMERIC encoded size in bytes. Not element count! - // Name: The null-terminated name follows. -}; + TypeIndex getFunctionType() const { return FunctionType; } -// LF_VFTABLE -struct VFTableType { - TypeIndex CompleteClass; // Class that owns this vftable. - TypeIndex OverriddenVFTable; // VFTable that this overrides. - ulittle32_t VFPtrOffset; // VFPtr offset in CompleteClass - ulittle32_t NamesLen; // Length of subsequent names array in bytes. - // Names: A sequence of null-terminated strings. First string is vftable - // names. -}; + StringRef getName() const { return Name; } -// LF_MFUNC_ID -struct MemberFuncId { - TypeIndex ClassType; +private: + struct Layout { + TypeIndex ParentScope; + TypeIndex FunctionType; + // Name: The null-terminated name follows. + }; + + TypeIndex ParentScope; TypeIndex FunctionType; - // Name: The null-terminated name follows. + StringRef Name; }; -// LF_PROCEDURE -struct ProcedureType { - TypeIndex ReturnType; - CallingConvention CallConv; - FunctionOptions Options; - ulittle16_t NumParameters; - TypeIndex ArgListType; -}; +// LF_UDT_SRC_LINE +class UdtSourceLineRecord : public TypeRecord { +public: + UdtSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, uint32_t LineNumber) + : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), + SourceFile(SourceFile), LineNumber(LineNumber) {} -// LF_MFUNCTION -struct MemberFunctionType { - TypeIndex ReturnType; - TypeIndex ClassType; - TypeIndex ThisType; - CallingConvention CallConv; - FunctionOptions Options; - ulittle16_t NumParameters; - TypeIndex ArgListType; - little32_t ThisAdjustment; -}; + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; -//===----------------------------------------------------------------------===// -// Field list records, which do not include leafs or sizes + return UdtSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber); + } -/// Equvalent to CV_fldattr_t in cvinfo.h. -struct MemberAttributes { - ulittle16_t Attrs; + TypeIndex getUDT() const { return UDT; } + TypeIndex getSourceFile() const { return SourceFile; } + uint32_t getLineNumber() const { return LineNumber; } - /// Get the access specifier. Valid for any kind of member. - MemberAccess getAccess() const { - return MemberAccess(unsigned(Attrs) & unsigned(MethodOptions::AccessMask)); - } +private: + struct Layout { + TypeIndex UDT; // The user-defined type + TypeIndex SourceFile; // StringID containing the source filename + ulittle32_t LineNumber; + }; + + TypeIndex UDT; + TypeIndex SourceFile; + uint32_t LineNumber; +}; - /// Indicates if a method is defined with friend, virtual, static, etc. - MethodKind getMethodKind() const { - return MethodKind( - (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> 2); +// LF_BUILDINFO +class BuildInfoRecord : public TypeRecord { +public: + BuildInfoRecord(ArrayRef ArgIndices) + : TypeRecord(TypeRecordKind::Modifier), ArgIndices(ArgIndices) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + ArrayRef Indices; + if (auto EC = consumeArray(Data, Indices, L->NumArgs)) + return EC; + return BuildInfoRecord(Indices); } - /// Get the flags that are not included in access control or method - /// properties. - MethodOptions getFlags() const { - return MethodOptions( - unsigned(Attrs) & - ~unsigned(MethodOptions::AccessMask | MethodOptions::MethodKindMask)); - } + ArrayRef getArgs() const { return ArgIndices; } - /// Is this method virtual. - bool isVirtual() const { - auto MP = getMethodKind(); - return MP != MethodKind::Vanilla && MP != MethodKind::Friend && - MP != MethodKind::Static; +private: + struct Layout { + ulittle16_t NumArgs; // Number of arguments + // ArgTypes[]: Type indicies of arguments + }; + ArrayRef ArgIndices; +}; + +// LF_VFTABLE +class VirtualTableRecord : public TypeRecord { +public: + VirtualTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable, + uint32_t VFPtrOffset, StringRef Name, + ArrayRef Methods) + : TypeRecord(TypeRecordKind::VirtualFunctionTable), + CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable), + VFPtrOffset(VFPtrOffset), Name(Name), MethodNamesRef(Methods) {} + VirtualTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable, + uint32_t VFPtrOffset, StringRef Name, + const std::vector &Methods) + : TypeRecord(TypeRecordKind::VirtualFunctionTable), + CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable), + VFPtrOffset(VFPtrOffset), Name(Name), MethodNames(Methods) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + + std::vector Names; + while (!Data.empty()) { + if (auto EC = consumeCString(Data, Name)) + return EC; + Names.push_back(Name); + } + return VirtualTableRecord(L->CompleteClass, L->OverriddenVFTable, + L->VFPtrOffset, Name, Names); } - /// Does this member introduce a new virtual method. - bool isIntroducedVirtual() const { - auto MP = getMethodKind(); - return MP == MethodKind::IntroducingVirtual || - MP == MethodKind::PureIntroducingVirtual; + TypeIndex getCompleteClass() const { return CompleteClass; } + TypeIndex getOverriddenVTable() const { return OverriddenVFTable; } + uint32_t getVFPtrOffset() const { return VFPtrOffset; } + StringRef getName() const { return Name; } + ArrayRef getMethodNames() const { + if (!MethodNamesRef.empty()) + return MethodNamesRef; + return MethodNames; } -}; -// LF_NESTTYPE -struct NestedType { - ulittle16_t Pad0; // Should be zero - TypeIndex Type; // Type index of nested type - // Name: Null-terminated string +private: + struct Layout { + TypeIndex CompleteClass; // Class that owns this vftable. + TypeIndex OverriddenVFTable; // VFTable that this overrides. + ulittle32_t VFPtrOffset; // VFPtr offset in CompleteClass + ulittle32_t NamesLen; // Length of subsequent names array in bytes. + // Names: A sequence of null-terminated strings. First string is vftable + // names. + }; + + TypeIndex CompleteClass; + TypeIndex OverriddenVFTable; + ulittle32_t VFPtrOffset; + StringRef Name; + ArrayRef MethodNamesRef; + std::vector MethodNames; }; // LF_ONEMETHOD -struct OneMethod { - MemberAttributes Attrs; - TypeIndex Type; - // If is introduced virtual method: - // VFTableOffset: int32_t offset in vftable - // Name: Null-terminated string +class OneMethodRecord : public TypeRecord { +public: + OneMethodRecord(TypeIndex Type, MethodKind Kind, MethodOptions Options, + MemberAccess Access, int32_t VFTableOffset, StringRef Name) + : TypeRecord(TypeRecordKind::OneMethod), Type(Type), Kind(Kind), + Options(Options), Access(Access), VFTableOffset(VFTableOffset), + Name(Name) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + MethodOptions Options = L->Attrs.getFlags(); + MethodKind MethKind = L->Attrs.getMethodKind(); + MemberAccess Access = L->Attrs.getAccess(); + int32_t VFTableOffset = 0; + if (L->Attrs.isIntroducedVirtual()) { + const little32_t *L; + if (consumeObject(Data, L)) + return std::make_error_code(std::errc::illegal_byte_sequence); + VFTableOffset = *L; + } + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + + return OneMethodRecord(L->Type, MethKind, Options, Access, VFTableOffset, + Name); + } - MethodKind getMethodKind() const { - return Attrs.getMethodKind(); + TypeIndex getType() const { return Type; } + MethodKind getKind() const { return Kind; } + MethodOptions getOptions() const { return Options; } + MemberAccess getAccess() const { return Access; } + int32_t getVFTableOffset() const { return VFTableOffset; } + StringRef getName() const { return Name; } + + bool isIntroducingVirtual() const { + const uint8_t K = static_cast(Kind); + const uint8_t V = static_cast(MethodKind::IntroducingVirtual); + const uint8_t PV = static_cast(MethodKind::PureIntroducingVirtual); + return (K & V) || (K & PV); } - bool isVirtual() const { return Attrs.isVirtual(); } - bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); } +private: + struct Layout { + MemberAttributes Attrs; + TypeIndex Type; + // If is introduced virtual method: + // VFTableOffset: int32_t offset in vftable + // Name: Null-terminated string + }; + + TypeIndex Type; + MethodKind Kind; + MethodOptions Options; + MemberAccess Access; + int32_t VFTableOffset; + StringRef Name; }; // LF_METHODLIST -struct MethodListEntry { - MemberAttributes Attrs; - ulittle16_t Padding; +class MethodListRecord : public TypeRecord { +public: + MethodListRecord(TypeIndex Type, MethodKind Kind, MethodOptions Options, + MemberAccess Access, int32_t VFTableOffset) + : TypeRecord(TypeRecordKind::MethodList), Type(Type), Kind(Kind), + Options(Options), Access(Access), VFTableOffset(VFTableOffset) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + MethodOptions Options = L->Attrs.getFlags(); + MethodKind MethKind = L->Attrs.getMethodKind(); + MemberAccess Access = L->Attrs.getAccess(); + int32_t VFTableOffset = 0; + if (L->Attrs.isIntroducedVirtual()) { + const little32_t *L; + if (consumeObject(Data, L)) + return std::make_error_code(std::errc::illegal_byte_sequence); + VFTableOffset = *L; + } + + return MethodListRecord(L->Type, MethKind, Options, Access, VFTableOffset); + } - TypeIndex Type; - // If is introduced virtual method: - // VFTableOffset: int32_t offset in vftable + TypeIndex getType() const { return Type; } + MethodKind getMethodKind() const { return Kind; } + MethodOptions getOptions() const { return Options; } + MemberAccess getAccess() const { return Access; } + int32_t getVFTableOffset() const { return VFTableOffset; } - MethodKind getMethodKind() const { - return Attrs.getMethodKind(); - } +private: + struct Layout { + MemberAttributes Attrs; + ulittle16_t Padding; + + TypeIndex Type; + // If is introduced virtual method: + // VFTableOffset: int32_t offset in vftable + }; - bool isVirtual() const { return Attrs.isVirtual(); } - bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); } + TypeIndex Type; + MethodKind Kind; + MethodOptions Options; + MemberAccess Access; + int32_t VFTableOffset; }; /// For method overload sets. LF_METHOD -struct OverloadedMethod { - ulittle16_t MethodCount; // Size of overload set - TypeIndex MethList; // Type index of methods in overload set - // Name: Null-terminated string -}; +class OverloadedMethodRecord : public TypeRecord { +public: + OverloadedMethodRecord(uint16_t NumOverloads, TypeIndex MethodList, + StringRef Name) + : TypeRecord(TypeRecordKind::OverloadedMethod), + NumOverloads(NumOverloads), MethodList(MethodList), Name(Name) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + + return OverloadedMethodRecord(L->MethodCount, L->MethList, Name); + } -// LF_VFUNCTAB -struct VirtualFunctionPointer { - ulittle16_t Pad0; - TypeIndex Type; // Type of vfptr + uint16_t getNumOverloads() const { return NumOverloads; } + TypeIndex getMethodList() const { return MethodList; } + StringRef getName() const { return Name; } + +private: + struct Layout { + ulittle16_t MethodCount; // Size of overload set + TypeIndex MethList; // Type index of methods in overload set + // Name: Null-terminated string + }; + + uint16_t NumOverloads; + TypeIndex MethodList; + StringRef Name; }; // LF_MEMBER -struct DataMember { - MemberAttributes Attrs; // Access control attributes, etc +class DataMemberRecord : public TypeRecord { +public: + DataMemberRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset, + StringRef Name) + : TypeRecord(TypeRecordKind::Member), Access(Access), Type(Type), + FieldOffset(Offset), Name(Name) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + uint64_t Offset; + if (!decodeUIntLeaf(Data, Offset)) + return std::make_error_code(std::errc::illegal_byte_sequence); + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + + return DataMemberRecord(L->Attrs.getAccess(), L->Type, Offset, Name); + } + + MemberAccess getAccess() const { return Access; } + TypeIndex getType() const { return Type; } + uint64_t getFieldOffset() const { return FieldOffset; } + StringRef getName() const { return Name; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex Type; + // FieldOffset: LF_NUMERIC encoded byte offset + // Name: Null-terminated string + }; + + MemberAccess Access; TypeIndex Type; - // FieldOffset: LF_NUMERIC encoded byte offset - // Name: Null-terminated string + uint64_t FieldOffset; + StringRef Name; }; // LF_STMEMBER -struct StaticDataMember { - MemberAttributes Attrs; // Access control attributes, etc +class StaticDataMemberRecord : public TypeRecord { +public: + StaticDataMemberRecord(MemberAccess Access, TypeIndex Type, StringRef Name) + : TypeRecord(TypeRecordKind::StaticMember), Access(Access), Type(Type), + Name(Name) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + + return StaticDataMemberRecord(L->Attrs.getAccess(), L->Type, Name); + } + + MemberAccess getAccess() const { return Access; } + TypeIndex getType() const { return Type; } + StringRef getName() const { return Name; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex Type; + // Name: Null-terminated string + }; + + MemberAccess Access; TypeIndex Type; - // Name: Null-terminated string + StringRef Name; }; // LF_ENUMERATE -struct Enumerator { - MemberAttributes Attrs; // Access control attributes, etc - // EnumValue: LF_NUMERIC encoded enumerator value - // Name: Null-terminated string +class EnumeratorRecord : public TypeRecord { +public: + EnumeratorRecord(MemberAccess Access, APSInt Value, StringRef Name) + : TypeRecord(TypeRecordKind::Enumerate), Access(Access), Value(Value), + Name(Name) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + if (Data.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + APSInt Value; + if (!decodeNumericLeaf(Data, Value)) + return std::make_error_code(std::errc::illegal_byte_sequence); + + StringRef Name; + if (auto EC = consumeCString(Data, Name)) + return EC; + + return EnumeratorRecord(L->Attrs.getAccess(), Value, Name); + } + + MemberAccess getAccess() const { return Access; } + APSInt getValue() const { return Value; } + StringRef getName() const { return Name; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + // EnumValue: LF_NUMERIC encoded enumerator value + // Name: Null-terminated string + }; + + MemberAccess Access; + APSInt Value; + StringRef Name; +}; + +// LF_VFUNCTAB +class VirtualFunctionPointerRecord : public TypeRecord { +public: + VirtualFunctionPointerRecord(TypeIndex Type) + : TypeRecord(TypeRecordKind::VirtualFunctionTablePointer), Type(Type) {} + static ErrorOr + deserialize(TypeRecordKind Kind, ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + return VirtualFunctionPointerRecord(L->Type); + } + + TypeIndex getType() const { return Type; } + +private: + struct Layout { + ulittle16_t Pad0; + TypeIndex Type; // Type of vfptr + }; + TypeIndex Type; }; // LF_BCLASS, LF_BINTERFACE -struct BaseClass { - MemberAttributes Attrs; // Access control attributes, etc - TypeIndex BaseType; // Base class type - // BaseOffset: LF_NUMERIC encoded byte offset of base from derived. +class BaseClassRecord : public TypeRecord { +public: + BaseClassRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset) + : TypeRecord(TypeRecordKind::BaseClass), Access(Access), Type(Type), + Offset(Offset) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + uint64_t Offset; + if (!decodeUIntLeaf(Data, Offset)) + return std::make_error_code(std::errc::illegal_byte_sequence); + + return BaseClassRecord(L->Attrs.getAccess(), L->BaseType, Offset); + } + + MemberAccess getAccess() const { return Access; } + TypeIndex getBaseType() const { return Type; } + uint64_t getBaseOffset() const { return Offset; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex BaseType; // Base class type + // BaseOffset: LF_NUMERIC encoded byte offset of base from derived. + }; + MemberAccess Access; + TypeIndex Type; + uint64_t Offset; }; // LF_VBCLASS, LF_IVBCLASS -struct VirtualBaseClass { - MemberAttributes Attrs; // Access control attributes, etc. - TypeIndex BaseType; // Base class type - TypeIndex VBPtrType; // Virtual base pointer type - // VBPtrOffset: Offset of vbptr from vfptr encoded as LF_NUMERIC. - // VBTableIndex: Index of vbase within vbtable encoded as LF_NUMERIC. +class VirtualBaseClassRecord : public TypeRecord { +public: + VirtualBaseClassRecord(MemberAccess Access, TypeIndex BaseType, + TypeIndex VBPtrType, uint64_t Offset, uint64_t Index) + : TypeRecord(TypeRecordKind::VirtualBaseClass), Access(Access), + BaseType(BaseType), VBPtrType(VBPtrType), VBPtrOffset(Offset), + VTableIndex(Index) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + uint64_t Offset; + uint64_t Index; + if (!decodeUIntLeaf(Data, Offset)) + return std::make_error_code(std::errc::illegal_byte_sequence); + if (!decodeUIntLeaf(Data, Index)) + return std::make_error_code(std::errc::illegal_byte_sequence); + + return VirtualBaseClassRecord(L->Attrs.getAccess(), L->BaseType, + L->VBPtrType, Offset, Index); + } + + MemberAccess getAccess() const { return Access; } + TypeIndex getBaseType() const { return BaseType; } + TypeIndex getVBPtrType() const { return VBPtrType; } + uint64_t getVBPtrOffset() const { return VBPtrOffset; } + uint64_t getVTableIndex() const { return VTableIndex; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc. + TypeIndex BaseType; // Base class type + TypeIndex VBPtrType; // Virtual base pointer type + // VBPtrOffset: Offset of vbptr from vfptr encoded as LF_NUMERIC. + // VBTableIndex: Index of vbase within vbtable encoded as LF_NUMERIC. + }; + MemberAccess Access; + TypeIndex BaseType; + TypeIndex VBPtrType; + uint64_t VBPtrOffset; + uint64_t VTableIndex; }; } } Index: include/llvm/DebugInfo/CodeView/TypeRecords.def =================================================================== --- include/llvm/DebugInfo/CodeView/TypeRecords.def +++ include/llvm/DebugInfo/CodeView/TypeRecords.def @@ -30,44 +30,44 @@ #endif -TYPE_RECORD(PointerType, LF_POINTER) -TYPE_RECORD(TypeModifier, LF_MODIFIER) -TYPE_RECORD(ProcedureType, LF_PROCEDURE) -TYPE_RECORD(MemberFunctionType, LF_MFUNCTION) -TYPE_RECORD(ArgList, LF_ARGLIST) +TYPE_RECORD(PointerRecord, LF_POINTER) +TYPE_RECORD(ModifierRecord, LF_MODIFIER) +TYPE_RECORD(ProcedureRecord, LF_PROCEDURE) +TYPE_RECORD(MemberFunctionRecord, LF_MFUNCTION) +TYPE_RECORD(StringListRecord, LF_ARGLIST) -TYPE_RECORD(ArrayType, LF_ARRAY) -TYPE_RECORD(ClassType, LF_CLASS) -TYPE_RECORD_ALIAS(ClassType, LF_STRUCTURE) -TYPE_RECORD_ALIAS(ClassType, LF_INTERFACE) -TYPE_RECORD(UnionType, LF_UNION) -TYPE_RECORD(EnumType, LF_ENUM) -TYPE_RECORD(TypeServer2, LF_TYPESERVER2) -TYPE_RECORD(VFTableType, LF_VFTABLE) -TYPE_RECORD(VTableShape, LF_VTSHAPE) +TYPE_RECORD(ArrayRecord, LF_ARRAY) +TYPE_RECORD(ClassRecord, LF_CLASS) +TYPE_RECORD_ALIAS(ClassRecord, LF_STRUCTURE) +TYPE_RECORD_ALIAS(ClassRecord, LF_INTERFACE) +TYPE_RECORD(UnionRecord, LF_UNION) +TYPE_RECORD(EnumRecord, LF_ENUM) +TYPE_RECORD(TypeServer2Record, LF_TYPESERVER2) +TYPE_RECORD(VirtualTableRecord, LF_VFTABLE) +TYPE_RECORD(VirtualTableShapeRecord, LF_VTSHAPE) // Member type records. These are generally not length prefixed, and appear // inside of a field list record. -MEMBER_RECORD(BaseClass, LF_BCLASS) -MEMBER_RECORD_ALIAS(BaseClass, LF_BINTERFACE) -MEMBER_RECORD(VirtualBaseClass, LF_VBCLASS) -MEMBER_RECORD_ALIAS(VirtualBaseClass, LF_IVBCLASS) -MEMBER_RECORD(VirtualFunctionPointer, LF_VFUNCTAB) -MEMBER_RECORD(StaticDataMember, LF_STMEMBER) -MEMBER_RECORD(OverloadedMethod, LF_METHOD) -MEMBER_RECORD(DataMember, LF_MEMBER) -MEMBER_RECORD(NestedType, LF_NESTTYPE) -MEMBER_RECORD(OneMethod, LF_ONEMETHOD) -MEMBER_RECORD(Enumerator, LF_ENUMERATE) +MEMBER_RECORD(BaseClassRecord, LF_BCLASS) +MEMBER_RECORD_ALIAS(BaseClassRecord, LF_BINTERFACE) +MEMBER_RECORD(VirtualBaseClassRecord, LF_VBCLASS) +MEMBER_RECORD_ALIAS(VirtualBaseClassRecord, LF_IVBCLASS) +MEMBER_RECORD(VirtualFunctionPointerRecord, LF_VFUNCTAB) +MEMBER_RECORD(StaticDataMemberRecord, LF_STMEMBER) +MEMBER_RECORD(OverloadedMethodRecord, LF_METHOD) +MEMBER_RECORD(DataMemberRecord, LF_MEMBER) +MEMBER_RECORD(NestedTypeRecord, LF_NESTTYPE) +MEMBER_RECORD(OneMethodRecord, LF_ONEMETHOD) +MEMBER_RECORD(EnumeratorRecord, LF_ENUMERATE) // ID leaf records. Subsequent leaf types may be referenced from .debug$S. -TYPE_RECORD(FuncId, LF_FUNC_ID) -TYPE_RECORD(MemberFuncId, LF_MFUNC_ID) -TYPE_RECORD(BuildInfo, LF_BUILDINFO) -TYPE_RECORD_ALIAS(ArgList, LF_SUBSTR_LIST) -TYPE_RECORD(StringId, LF_STRING_ID) -TYPE_RECORD(UDTSrcLine, LF_UDT_SRC_LINE) +TYPE_RECORD(FuncIdRecord, LF_FUNC_ID) +TYPE_RECORD(MemberFunctionIdRecord, LF_MFUNC_ID) +TYPE_RECORD(BuildInfoRecord, LF_BUILDINFO) +TYPE_RECORD_ALIAS(StringListRecord, LF_SUBSTR_LIST) +TYPE_RECORD(StringIdRecord, LF_STRING_ID) +TYPE_RECORD(UdtSourceLineRecord, LF_UDT_SRC_LINE) #undef TYPE_RECORD #undef TYPE_RECORD_ALIAS Index: include/llvm/DebugInfo/CodeView/TypeStream.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeStream.h +++ include/llvm/DebugInfo/CodeView/TypeStream.h @@ -13,7 +13,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/RecordIterator.h" -#include "llvm/Object/Error.h" #include "llvm/Support/Endian.h" #include @@ -23,43 +22,6 @@ namespace codeview { -/// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if -/// there are not enough bytes remaining. Reinterprets the consumed bytes as a -/// T object and points 'Res' at them. -template -inline std::error_code consumeObject(StringRef &Data, const T *&Res) { - if (Data.size() < sizeof(*Res)) - return object::object_error::parse_failed; - Res = reinterpret_cast(Data.data()); - Data = Data.drop_front(sizeof(*Res)); - return std::error_code(); -} - -inline std::error_code consumeUInt32(StringRef &Data, uint32_t &Res) { - const support::ulittle32_t *IntPtr; - if (auto EC = consumeObject(Data, IntPtr)) - return EC; - Res = *IntPtr; - return std::error_code(); -} - -/// Decodes a numeric "leaf" value. These are integer literals encountered in -/// the type stream. If the value is positive and less than LF_NUMERIC (1 << -/// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR -/// that indicates the bitwidth and sign of the numeric data. -bool decodeNumericLeaf(ArrayRef &Data, APSInt &Num); - -inline bool decodeNumericLeaf(StringRef &Data, APSInt &Num) { - ArrayRef Bytes(reinterpret_cast(Data.data()), - Data.size()); - bool Success = decodeNumericLeaf(Bytes, Num); - Data = StringRef(reinterpret_cast(Bytes.data()), Bytes.size()); - return Success; -} - -/// Decode a numeric leaf value that is known to be a uint32_t. -bool decodeUIntLeaf(ArrayRef &Data, uint64_t &Num); - typedef RecordIterator TypeIterator; inline iterator_range makeTypeRange(ArrayRef Data) { Index: include/llvm/DebugInfo/CodeView/TypeTableBuilder.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -40,12 +40,11 @@ TypeIndex writeModifier(const ModifierRecord &Record); TypeIndex writeProcedure(const ProcedureRecord &Record); TypeIndex writeMemberFunction(const MemberFunctionRecord &Record); - TypeIndex writeArgumentList(const ArgumentListRecord &Record); + TypeIndex writeArgumentList(const StringListRecord &Record); TypeIndex writeRecord(TypeRecordBuilder &builder); TypeIndex writePointer(const PointerRecord &Record); - TypeIndex writePointerToMember(const PointerToMemberRecord &Record); TypeIndex writeArray(const ArrayRecord &Record); - TypeIndex writeAggregate(const AggregateRecord &Record); + TypeIndex writeClass(const ClassRecord &Record); TypeIndex writeEnum(const EnumRecord &Record); TypeIndex writeBitField(const BitFieldRecord &Record); TypeIndex writeVirtualTableShape(const VirtualTableShapeRecord &Record); Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -263,7 +263,7 @@ // type here. unsigned ArgListIndex = getNextTypeIndex(); OS.AddComment("Type record length"); - OS.EmitIntValue(2 + sizeof(ArgList), 2); + OS.EmitIntValue(StringListRecord::getLayoutSize(), 2); OS.AddComment("Leaf type: LF_ARGLIST"); OS.EmitIntValue(LF_ARGLIST, 2); OS.AddComment("Number of arguments"); @@ -271,7 +271,7 @@ unsigned VoidFnTyIdx = getNextTypeIndex(); OS.AddComment("Type record length"); - OS.EmitIntValue(2 + sizeof(ProcedureType), 2); + OS.EmitIntValue(ProcedureRecord::getLayoutSize(), 2); OS.AddComment("Leaf type: LF_PROCEDURE"); OS.EmitIntValue(LF_PROCEDURE, 2); OS.AddComment("Return type index"); Index: lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp =================================================================== --- lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp +++ lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp @@ -56,7 +56,7 @@ TypeIndex MethodList, StringRef Name) { TypeRecordBuilder &Builder = getBuilder(); - Builder.writeTypeRecordKind(TypeRecordKind::Method); + Builder.writeTypeRecordKind(TypeRecordKind::OverloadedMethod); Builder.writeUInt16(OverloadCount); Builder.writeTypeIndex(MethodList); Builder.writeNullTerminatedString(Name); Index: lib/DebugInfo/CodeView/TypeDumper.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeDumper.cpp +++ lib/DebugInfo/CodeView/TypeDumper.cpp @@ -201,12 +201,10 @@ /// CVTypeVisitor overrides. #define TYPE_RECORD(ClassName, LeafEnum) \ - void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ - ArrayRef LeafData); + void visit##ClassName(TypeLeafKind LeafType, ClassName &Record); #define TYPE_RECORD_ALIAS(ClassName, LeafEnum) #define MEMBER_RECORD(ClassName, LeafEnum) \ - void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ - ArrayRef &FieldData); + void visit##ClassName(TypeLeafKind LeafType, ClassName &Record); #define MEMBER_RECORD_ALIAS(ClassName, LeafEnum) #include "llvm/DebugInfo/CodeView/TypeRecords.def" @@ -219,6 +217,8 @@ void visitTypeEnd(TypeLeafKind Leaf, ArrayRef LeafData); void printMemberAttributes(MemberAttributes Attrs); + void printMemberAttributes(MemberAccess Access, MethodKind Kind, + MethodOptions Options); private: /// Forwards to the dumper, which holds the persistent state from visitation. @@ -240,17 +240,6 @@ } // end anonymous namespace -/// Reinterpret a byte array as an array of characters. Does not interpret as -/// a C string, as StringRef has several helpers (split) that make that easy. -static StringRef getBytesAsCharacters(ArrayRef LeafData) { - return StringRef(reinterpret_cast(LeafData.data()), - LeafData.size()); -} - -static StringRef getBytesAsCString(ArrayRef LeafData) { - return getBytesAsCharacters(LeafData).split('\0').first; -} - static StringRef getLeafTypeName(TypeLeafKind LT) { switch (LT) { #define KNOWN_TYPE(LeafName, Value, ClassName) \ @@ -286,164 +275,128 @@ W.startLine() << "}\n"; } -void CVTypeDumperImpl::visitStringId(TypeLeafKind Leaf, const StringId *String, - ArrayRef LeafData) { - W.printHex("Id", String->id.getIndex()); - StringRef StringData = getBytesAsCString(LeafData); - W.printString("StringData", StringData); +void CVTypeDumperImpl::visitStringIdRecord(TypeLeafKind Leaf, + StringIdRecord &String) { + printTypeIndex("Id", String.getId()); + W.printString("StringData", String.getString()); // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. - Name = StringData; + Name = String.getString(); } - -void CVTypeDumperImpl::visitArgList(TypeLeafKind Leaf, const ArgList *Args, - ArrayRef LeafData) { - W.printNumber("NumArgs", Args->NumArgs); +void CVTypeDumperImpl::visitStringListRecord(TypeLeafKind Leaf, + StringListRecord &Args) { + auto Indices = Args.getIndices(); + uint32_t Size = Indices.size(); + W.printNumber("NumArgs", Size); ListScope Arguments(W, "Arguments"); SmallString<256> TypeName("("); - for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) { - const TypeIndex *Type; - if (!consumeObject(LeafData, Type)) - return; - printTypeIndex("ArgType", *Type); - StringRef ArgTypeName = getTypeName(*Type); + for (uint32_t I = 0; I < Size; ++I) { + printTypeIndex("ArgType", Indices[I]); + StringRef ArgTypeName = getTypeName(Indices[I]); TypeName.append(ArgTypeName); - if (ArgI + 1 != Args->NumArgs) + if (I + 1 != Size) TypeName.append(", "); } TypeName.push_back(')'); Name = CVTD.saveName(TypeName); } -void CVTypeDumperImpl::visitClassType(TypeLeafKind Leaf, const ClassType *Class, - ArrayRef LeafData) { - W.printNumber("MemberCount", Class->MemberCount); - uint16_t Props = Class->Properties; +void CVTypeDumperImpl::visitClassRecord(TypeLeafKind Leaf, ClassRecord &Class) { + uint16_t Props = static_cast(Class.getOptions()); + W.printNumber("MemberCount", Class.getMemberCount()); W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); - printTypeIndex("FieldList", Class->FieldList); - printTypeIndex("DerivedFrom", Class->DerivedFrom); - printTypeIndex("VShape", Class->VShape); - uint64_t SizeOf; - if (!decodeUIntLeaf(LeafData, SizeOf)) - return parseError(); - W.printNumber("SizeOf", SizeOf); - StringRef LeafChars = getBytesAsCharacters(LeafData); - StringRef LinkageName; - std::tie(Name, LinkageName) = LeafChars.split('\0'); - W.printString("Name", Name); - if (Props & uint16_t(ClassOptions::HasUniqueName)) { - LinkageName = LinkageName.split('\0').first; - if (LinkageName.empty()) - return parseError(); - W.printString("LinkageName", LinkageName); - } -} - -void CVTypeDumperImpl::visitUnionType(TypeLeafKind Leaf, const UnionType *Union, - ArrayRef LeafData) { - W.printNumber("MemberCount", Union->MemberCount); - uint16_t Props = Union->Properties; + printTypeIndex("FieldList", Class.getFieldList()); + printTypeIndex("DerivedFrom", Class.getDerivationList()); + printTypeIndex("VShape", Class.getVTableShape()); + W.printNumber("SizeOf", Class.getSize()); + W.printString("Name", Class.getName()); + if (Props & uint16_t(ClassOptions::HasUniqueName)) + W.printString("LinkageName", Class.getUniqueName()); + Name = Class.getName(); +} + +void CVTypeDumperImpl::visitUnionRecord(TypeLeafKind Leaf, UnionRecord &Union) { + uint16_t Props = static_cast(Union.getOptions()); + W.printNumber("MemberCount", Union.getMemberCount()); W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); - printTypeIndex("FieldList", Union->FieldList); - uint64_t SizeOf; - if (!decodeUIntLeaf(LeafData, SizeOf)) - return parseError(); - W.printNumber("SizeOf", SizeOf); - StringRef LeafChars = getBytesAsCharacters(LeafData); - StringRef LinkageName; - std::tie(Name, LinkageName) = LeafChars.split('\0'); - W.printString("Name", Name); - if (Props & uint16_t(ClassOptions::HasUniqueName)) { - LinkageName = LinkageName.split('\0').first; - if (LinkageName.empty()) - return parseError(); - W.printString("LinkageName", LinkageName); - } + printTypeIndex("FieldList", Union.getFieldList()); + W.printNumber("SizeOf", Union.getSize()); + W.printString("Name", Union.getName()); + if (Props & uint16_t(ClassOptions::HasUniqueName)) + W.printString("LinkageName", Union.getUniqueName()); + Name = Union.getName(); } -void CVTypeDumperImpl::visitEnumType(TypeLeafKind Leaf, const EnumType *Enum, - ArrayRef LeafData) { - W.printNumber("NumEnumerators", Enum->NumEnumerators); - W.printFlags("Properties", uint16_t(Enum->Properties), +void CVTypeDumperImpl::visitEnumRecord(TypeLeafKind Leaf, EnumRecord &Enum) { + W.printNumber("NumEnumerators", Enum.getMemberCount()); + W.printFlags("Properties", uint16_t(Enum.getOptions()), makeArrayRef(ClassOptionNames)); - printTypeIndex("UnderlyingType", Enum->UnderlyingType); - printTypeIndex("FieldListType", Enum->FieldListType); - Name = getBytesAsCString(LeafData); - W.printString("Name", Name); -} - -void CVTypeDumperImpl::visitArrayType(TypeLeafKind Leaf, const ArrayType *AT, - ArrayRef LeafData) { - printTypeIndex("ElementType", AT->ElementType); - printTypeIndex("IndexType", AT->IndexType); - uint64_t SizeOf; - if (!decodeUIntLeaf(LeafData, SizeOf)) - return parseError(); - W.printNumber("SizeOf", SizeOf); - Name = getBytesAsCString(LeafData); - W.printString("Name", Name); -} - -void CVTypeDumperImpl::visitVFTableType(TypeLeafKind Leaf, - const VFTableType *VFT, - ArrayRef LeafData) { - printTypeIndex("CompleteClass", VFT->CompleteClass); - printTypeIndex("OverriddenVFTable", VFT->OverriddenVFTable); - W.printHex("VFPtrOffset", VFT->VFPtrOffset); - StringRef NamesData = getBytesAsCharacters(LeafData.slice(0, VFT->NamesLen)); - std::tie(Name, NamesData) = NamesData.split('\0'); - W.printString("VFTableName", Name); - while (!NamesData.empty()) { - StringRef MethodName; - std::tie(MethodName, NamesData) = NamesData.split('\0'); - W.printString("MethodName", MethodName); - } -} - -void CVTypeDumperImpl::visitMemberFuncId(TypeLeafKind Leaf, - const MemberFuncId *Id, - ArrayRef LeafData) { - printTypeIndex("ClassType", Id->ClassType); - printTypeIndex("FunctionType", Id->FunctionType); - Name = getBytesAsCString(LeafData); - W.printString("Name", Name); -} - -void CVTypeDumperImpl::visitProcedureType(TypeLeafKind Leaf, - const ProcedureType *Proc, - ArrayRef LeafData) { - printTypeIndex("ReturnType", Proc->ReturnType); - W.printEnum("CallingConvention", uint8_t(Proc->CallConv), + printTypeIndex("UnderlyingType", Enum.getUnderlyingType()); + printTypeIndex("FieldListType", Enum.getFieldList()); + W.printString("Name", Enum.getName()); + Name = Enum.getName(); +} + +void CVTypeDumperImpl::visitArrayRecord(TypeLeafKind Leaf, ArrayRecord &AT) { + printTypeIndex("ElementType", AT.getElementType()); + printTypeIndex("IndexType", AT.getIndexType()); + W.printNumber("SizeOf", AT.getSize()); + W.printString("Name", AT.getName()); + Name = AT.getName(); +} + +void CVTypeDumperImpl::visitVirtualTableRecord(TypeLeafKind Leaf, + VirtualTableRecord &VFT) { + printTypeIndex("CompleteClass", VFT.getCompleteClass()); + printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable()); + W.printHex("VFPtrOffset", VFT.getVFPtrOffset()); + W.printString("VFTableName", VFT.getName()); + for (auto N : VFT.getMethodNames()) + W.printString("MethodName", N); + Name = VFT.getName(); +} + +void CVTypeDumperImpl::visitMemberFunctionIdRecord(TypeLeafKind Leaf, + MemberFunctionIdRecord &Id) { + printTypeIndex("ClassType", Id.getClassType()); + printTypeIndex("FunctionType", Id.getFunctionType()); + W.printString("Name", Id.getName()); + Name = Id.getName(); +} + +void CVTypeDumperImpl::visitProcedureRecord(TypeLeafKind Leaf, + ProcedureRecord &Proc) { + printTypeIndex("ReturnType", Proc.getReturnType()); + W.printEnum("CallingConvention", uint8_t(Proc.getCallConv()), makeArrayRef(CallingConventions)); - W.printFlags("FunctionOptions", uint8_t(Proc->Options), + W.printFlags("FunctionOptions", uint8_t(Proc.getOptions()), makeArrayRef(FunctionOptionEnum)); - W.printNumber("NumParameters", Proc->NumParameters); - printTypeIndex("ArgListType", Proc->ArgListType); + W.printNumber("NumParameters", Proc.getParameterCount()); + printTypeIndex("ArgListType", Proc.getArgumentList()); - StringRef ReturnTypeName = getTypeName(Proc->ReturnType); - StringRef ArgListTypeName = getTypeName(Proc->ArgListType); + StringRef ReturnTypeName = getTypeName(Proc.getReturnType()); + StringRef ArgListTypeName = getTypeName(Proc.getArgumentList()); SmallString<256> TypeName(ReturnTypeName); TypeName.push_back(' '); TypeName.append(ArgListTypeName); Name = CVTD.saveName(TypeName); } -void CVTypeDumperImpl::visitMemberFunctionType( - TypeLeafKind Leaf, const MemberFunctionType *MemberFunc, - ArrayRef LeafData) { - printTypeIndex("ReturnType", MemberFunc->ReturnType); - printTypeIndex("ClassType", MemberFunc->ClassType); - printTypeIndex("ThisType", MemberFunc->ThisType); - W.printEnum("CallingConvention", uint8_t(MemberFunc->CallConv), +void CVTypeDumperImpl::visitMemberFunctionRecord(TypeLeafKind Leaf, + MemberFunctionRecord &MF) { + printTypeIndex("ReturnType", MF.getReturnType()); + printTypeIndex("ClassType", MF.getClassType()); + printTypeIndex("ThisType", MF.getThisType()); + W.printEnum("CallingConvention", uint8_t(MF.getCallConv()), makeArrayRef(CallingConventions)); - W.printFlags("FunctionOptions", uint8_t(MemberFunc->Options), + W.printFlags("FunctionOptions", uint8_t(MF.getOptions()), makeArrayRef(FunctionOptionEnum)); - W.printNumber("NumParameters", MemberFunc->NumParameters); - printTypeIndex("ArgListType", MemberFunc->ArgListType); - W.printNumber("ThisAdjustment", MemberFunc->ThisAdjustment); + W.printNumber("NumParameters", MF.getParameterCount()); + printTypeIndex("ArgListType", MF.getArgumentList()); + W.printNumber("ThisAdjustment", MF.getThisPointerAdjustment()); - StringRef ReturnTypeName = getTypeName(MemberFunc->ReturnType); - StringRef ClassTypeName = getTypeName(MemberFunc->ClassType); - StringRef ArgListTypeName = getTypeName(MemberFunc->ArgListType); + StringRef ReturnTypeName = getTypeName(MF.getReturnType()); + StringRef ClassTypeName = getTypeName(MF.getClassType()); + StringRef ArgListTypeName = getTypeName(MF.getArgumentList()); SmallString<256> TypeName(ReturnTypeName); TypeName.push_back(' '); TypeName.append(ClassTypeName); @@ -455,148 +408,141 @@ void CVTypeDumperImpl::visitMethodList(TypeLeafKind Leaf, ArrayRef LeafData) { while (!LeafData.empty()) { - const MethodListEntry *Method; - if (!consumeObject(LeafData, Method)) + auto Method = + MethodListRecord::deserialize(TypeRecordKind::MethodList, LeafData); + if (Method) return; + const MethodListRecord &M = *Method; + ListScope S(W, "Method"); - printMemberAttributes(Method->Attrs); - printTypeIndex("Type", Method->Type); - if (Method->isIntroducedVirtual()) { - const little32_t *VFTOffsetPtr; - if (!consumeObject(LeafData, VFTOffsetPtr)) - return; - W.printHex("VFTableOffset", *VFTOffsetPtr); - } + printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions()); + printTypeIndex("Type", Method->getType()); + if (Method->getMethodKind() == MethodKind::IntroducingVirtual || + Method->getMethodKind() == MethodKind::PureIntroducingVirtual) + W.printHex("VFTableOffset", Method->getVFTableOffset()); } } -void CVTypeDumperImpl::visitFuncId(TypeLeafKind Leaf, const FuncId *Func, - ArrayRef LeafData) { - printTypeIndex("ParentScope", Func->ParentScope); - printTypeIndex("FunctionType", Func->FunctionType); - Name = getBytesAsCString(LeafData); - W.printString("Name", Name); +void CVTypeDumperImpl::visitFuncIdRecord(TypeLeafKind Leaf, + FuncIdRecord &Func) { + printTypeIndex("ParentScope", Func.getParentScope()); + printTypeIndex("FunctionType", Func.getFunctionType()); + W.printString("Name", Func.getName()); + Name = Func.getName(); } -void CVTypeDumperImpl::visitTypeServer2(TypeLeafKind Leaf, - const TypeServer2 *TypeServer, - ArrayRef LeafData) { - W.printBinary("Signature", StringRef(TypeServer->Signature, 16)); - W.printNumber("Age", TypeServer->Age); - Name = getBytesAsCString(LeafData); - W.printString("Name", Name); +void CVTypeDumperImpl::visitTypeServer2Record(TypeLeafKind Leaf, + TypeServer2Record &TS) { + W.printBinary("Signature", TS.getGuid()); + W.printNumber("Age", TS.getAge()); + W.printString("Name", TS.getName()); + Name = TS.getName(); } -void CVTypeDumperImpl::visitPointerType(TypeLeafKind Leaf, - const PointerType *Ptr, - ArrayRef LeafData) { - printTypeIndex("PointeeType", Ptr->PointeeType); - W.printHex("PointerAttributes", Ptr->Attrs); - W.printEnum("PtrType", unsigned(Ptr->getPtrKind()), +void CVTypeDumperImpl::visitPointerRecord(TypeLeafKind Leaf, + PointerRecord &Ptr) { + printTypeIndex("PointeeType", Ptr.getReferentType()); + W.printHex("PointerAttributes", uint32_t(Ptr.getOptions())); + W.printEnum("PtrType", unsigned(Ptr.getPointerKind()), makeArrayRef(PtrKindNames)); - W.printEnum("PtrMode", unsigned(Ptr->getPtrMode()), - makeArrayRef(PtrModeNames)); - W.printNumber("IsFlat", Ptr->isFlat()); - W.printNumber("IsConst", Ptr->isConst()); - W.printNumber("IsVolatile", Ptr->isVolatile()); - W.printNumber("IsUnaligned", Ptr->isUnaligned()); - - if (Ptr->isPointerToMember()) { - const PointerToMemberTail *PMT; - if (!consumeObject(LeafData, PMT)) - return; - printTypeIndex("ClassType", PMT->ClassType); - W.printEnum("Representation", PMT->Representation, + W.printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames)); + + W.printNumber("IsFlat", Ptr.isFlat()); + W.printNumber("IsConst", Ptr.isConst()); + W.printNumber("IsVolatile", Ptr.isVolatile()); + W.printNumber("IsUnaligned", Ptr.isUnaligned()); + + if (Ptr.isPointerToMember()) { + const MemberPointerInfo &MI = Ptr.getMemberInfo(); + + printTypeIndex("ClassType", MI.getContainingType()); + W.printEnum("Representation", uint16_t(MI.getRepresentation()), makeArrayRef(PtrMemberRepNames)); - StringRef PointeeName = getTypeName(Ptr->PointeeType); - StringRef ClassName = getTypeName(PMT->ClassType); + StringRef PointeeName = getTypeName(Ptr.getReferentType()); + StringRef ClassName = getTypeName(MI.getContainingType()); SmallString<256> TypeName(PointeeName); TypeName.push_back(' '); TypeName.append(ClassName); TypeName.append("::*"); Name = CVTD.saveName(TypeName); } else { - W.printBinaryBlock("TailData", getBytesAsCharacters(LeafData)); - SmallString<256> TypeName; - if (Ptr->isConst()) + if (Ptr.isConst()) TypeName.append("const "); - if (Ptr->isVolatile()) + if (Ptr.isVolatile()) TypeName.append("volatile "); - if (Ptr->isUnaligned()) + if (Ptr.isUnaligned()) TypeName.append("__unaligned "); - TypeName.append(getTypeName(Ptr->PointeeType)); + TypeName.append(getTypeName(Ptr.getReferentType())); - if (Ptr->getPtrMode() == PointerMode::LValueReference) + if (Ptr.getMode() == PointerMode::LValueReference) TypeName.append("&"); - else if (Ptr->getPtrMode() == PointerMode::RValueReference) + else if (Ptr.getMode() == PointerMode::RValueReference) TypeName.append("&&"); - else if (Ptr->getPtrMode() == PointerMode::Pointer) + else if (Ptr.getMode() == PointerMode::Pointer) TypeName.append("*"); Name = CVTD.saveName(TypeName); } } -void CVTypeDumperImpl::visitTypeModifier(TypeLeafKind Leaf, - const TypeModifier *Mod, - ArrayRef LeafData) { - printTypeIndex("ModifiedType", Mod->ModifiedType); - W.printFlags("Modifiers", Mod->Modifiers, makeArrayRef(TypeModifierNames)); +void CVTypeDumperImpl::visitModifierRecord(TypeLeafKind Leaf, + ModifierRecord &Mod) { + uint16_t Mods = static_cast(Mod.getModifiers()); + printTypeIndex("ModifiedType", Mod.getModifiedType()); + W.printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames)); - StringRef ModifiedName = getTypeName(Mod->ModifiedType); + StringRef ModifiedName = getTypeName(Mod.getModifiedType()); SmallString<256> TypeName; - if (Mod->Modifiers & uint16_t(ModifierOptions::Const)) + if (Mods & uint16_t(ModifierOptions::Const)) TypeName.append("const "); - if (Mod->Modifiers & uint16_t(ModifierOptions::Volatile)) + if (Mods & uint16_t(ModifierOptions::Volatile)) TypeName.append("volatile "); - if (Mod->Modifiers & uint16_t(ModifierOptions::Unaligned)) + if (Mods & uint16_t(ModifierOptions::Unaligned)) TypeName.append("__unaligned "); TypeName.append(ModifiedName); Name = CVTD.saveName(TypeName); } -void CVTypeDumperImpl::visitVTableShape(TypeLeafKind Leaf, - const VTableShape *Shape, - ArrayRef LeafData) { - unsigned VFEntryCount = Shape->VFEntryCount; - W.printNumber("VFEntryCount", VFEntryCount); - // We could print out whether the methods are near or far, but in practice - // today everything is CV_VTS_near32, so it's just noise. +void CVTypeDumperImpl::visitVirtualTableShapeRecord( + TypeLeafKind Leaf, VirtualTableShapeRecord &Shape) { + W.printNumber("VFEntryCount", Shape.getEntryCount()); } -void CVTypeDumperImpl::visitUDTSrcLine(TypeLeafKind Leaf, - const UDTSrcLine *Line, - ArrayRef LeafData) { - printTypeIndex("UDT", Line->UDT); - printTypeIndex("SourceFile", Line->SourceFile); - W.printNumber("LineNumber", Line->LineNumber); +void CVTypeDumperImpl::visitUdtSourceLineRecord(TypeLeafKind Leaf, + UdtSourceLineRecord &Line) { + printTypeIndex("UDT", Line.getUDT()); + printTypeIndex("SourceFile", Line.getSourceFile()); + W.printNumber("LineNumber", Line.getLineNumber()); } -void CVTypeDumperImpl::visitBuildInfo(TypeLeafKind Leaf, const BuildInfo *Args, - ArrayRef LeafData) { - W.printNumber("NumArgs", Args->NumArgs); +void CVTypeDumperImpl::visitBuildInfoRecord(TypeLeafKind Leaf, + BuildInfoRecord &Args) { + W.printNumber("NumArgs", Args.getArgs().size()); ListScope Arguments(W, "Arguments"); - for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) { - const TypeIndex *Type; - if (!consumeObject(LeafData, Type)) - return; - printTypeIndex("ArgType", *Type); + for (auto Arg : Args.getArgs()) { + printTypeIndex("ArgType", Arg); } } void CVTypeDumperImpl::printMemberAttributes(MemberAttributes Attrs) { - W.printEnum("AccessSpecifier", uint8_t(Attrs.getAccess()), + return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(), + Attrs.getFlags()); +} + +void CVTypeDumperImpl::printMemberAttributes(MemberAccess Access, + MethodKind Kind, + MethodOptions Options) { + W.printEnum("AccessSpecifier", uint8_t(Access), makeArrayRef(MemberAccessNames)); - auto MK = Attrs.getMethodKind(); // Data members will be vanilla. Don't try to print a method kind for them. - if (MK != MethodKind::Vanilla) - W.printEnum("MethodKind", unsigned(MK), makeArrayRef(MemberKindNames)); - if (Attrs.getFlags() != MethodOptions::None) { - W.printFlags("MethodOptions", unsigned(Attrs.getFlags()), + if (Kind != MethodKind::Vanilla) + W.printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames)); + if (Options != MethodOptions::None) { + W.printFlags("MethodOptions", unsigned(Options), makeArrayRef(MethodOptionNames)); } } @@ -605,117 +551,91 @@ W.printHex("UnknownMember", unsigned(Leaf)); } -void CVTypeDumperImpl::visitNestedType(TypeLeafKind Leaf, - const NestedType *Nested, - ArrayRef &FieldData) { +void CVTypeDumperImpl::visitNestedTypeRecord(TypeLeafKind Leaf, + NestedTypeRecord &Nested) { DictScope S(W, "NestedType"); - printTypeIndex("Type", Nested->Type); - StringRef Name = getBytesAsCString(FieldData); - FieldData = FieldData.drop_front(Name.size() + 1); - W.printString("Name", Name); + printTypeIndex("Type", Nested.getNestedType()); + W.printString("Name", Nested.getName()); + Name = Nested.getName(); } -void CVTypeDumperImpl::visitOneMethod(TypeLeafKind Leaf, - const OneMethod *Method, - ArrayRef &FieldData) { +void CVTypeDumperImpl::visitOneMethodRecord(TypeLeafKind Leaf, + OneMethodRecord &Method) { DictScope S(W, "OneMethod"); - printMemberAttributes(Method->Attrs); - printTypeIndex("Type", Method->Type); + MethodKind K = Method.getKind(); + printMemberAttributes(Method.getAccess(), K, Method.getOptions()); + printTypeIndex("Type", Method.getType()); // If virtual, then read the vftable offset. - if (Method->isIntroducedVirtual()) { - const little32_t *VFTOffsetPtr; - if (!consumeObject(FieldData, VFTOffsetPtr)) - return; - W.printHex("VFTableOffset", *VFTOffsetPtr); - } - StringRef Name = getBytesAsCString(FieldData); - FieldData = FieldData.drop_front(Name.size() + 1); - W.printString("Name", Name); + if (Method.isIntroducingVirtual()) + W.printHex("VFTableOffset", Method.getVFTableOffset()); + W.printString("Name", Method.getName()); + Name = Method.getName(); } -void CVTypeDumperImpl::visitOverloadedMethod(TypeLeafKind Leaf, - const OverloadedMethod *Method, - ArrayRef &FieldData) { +void CVTypeDumperImpl::visitOverloadedMethodRecord( + TypeLeafKind Leaf, OverloadedMethodRecord &Method) { DictScope S(W, "OverloadedMethod"); - W.printHex("MethodCount", Method->MethodCount); - W.printHex("MethodListIndex", Method->MethList.getIndex()); - StringRef Name = getBytesAsCString(FieldData); - FieldData = FieldData.drop_front(Name.size() + 1); - W.printString("Name", Name); + W.printHex("MethodCount", Method.getNumOverloads()); + printTypeIndex("MethodListIndex", Method.getMethodList()); + W.printString("Name", Method.getName()); + Name = Method.getName(); } -void CVTypeDumperImpl::visitDataMember(TypeLeafKind Leaf, - const DataMember *Field, - ArrayRef &FieldData) { +void CVTypeDumperImpl::visitDataMemberRecord(TypeLeafKind Leaf, + DataMemberRecord &Field) { DictScope S(W, "DataMember"); - printMemberAttributes(Field->Attrs); - printTypeIndex("Type", Field->Type); - uint64_t FieldOffset; - if (!decodeUIntLeaf(FieldData, FieldOffset)) - return parseError(); - W.printHex("FieldOffset", FieldOffset); - StringRef Name = getBytesAsCString(FieldData); - FieldData = FieldData.drop_front(Name.size() + 1); - W.printString("Name", Name); -} - -void CVTypeDumperImpl::visitStaticDataMember(TypeLeafKind Leaf, - const StaticDataMember *Field, - ArrayRef &FieldData) { + printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("Type", Field.getType()); + W.printHex("FieldOffset", Field.getFieldOffset()); + W.printString("Name", Field.getName()); + Name = Field.getName(); +} + +void CVTypeDumperImpl::visitStaticDataMemberRecord( + TypeLeafKind Leaf, StaticDataMemberRecord &Field) { DictScope S(W, "StaticDataMember"); - printMemberAttributes(Field->Attrs); - printTypeIndex("Type", Field->Type); - StringRef Name = getBytesAsCString(FieldData); - FieldData = FieldData.drop_front(Name.size() + 1); - W.printString("Name", Name); + printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("Type", Field.getType()); + W.printString("Name", Field.getName()); + Name = Field.getName(); } -void CVTypeDumperImpl::visitVirtualFunctionPointer( - TypeLeafKind Leaf, const VirtualFunctionPointer *VFTable, - ArrayRef &FieldData) { +void CVTypeDumperImpl::visitVirtualFunctionPointerRecord( + TypeLeafKind Leaf, VirtualFunctionPointerRecord &VFTable) { DictScope S(W, "VirtualFunctionPointer"); - printTypeIndex("Type", VFTable->Type); + printTypeIndex("Type", VFTable.getType()); } -void CVTypeDumperImpl::visitEnumerator(TypeLeafKind Leaf, - const Enumerator *Enum, - ArrayRef &FieldData) { +void CVTypeDumperImpl::visitEnumeratorRecord(TypeLeafKind Leaf, + EnumeratorRecord &Enum) { DictScope S(W, "Enumerator"); - printMemberAttributes(Enum->Attrs); - APSInt EnumValue; - if (!decodeNumericLeaf(FieldData, EnumValue)) - return parseError(); - W.printNumber("EnumValue", EnumValue); - StringRef Name = getBytesAsCString(FieldData); - FieldData = FieldData.drop_front(Name.size() + 1); - W.printString("Name", Name); -} - -void CVTypeDumperImpl::visitBaseClass(TypeLeafKind Leaf, const BaseClass *Base, - ArrayRef &FieldData) { + printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + W.printNumber("EnumValue", Enum.getValue()); + W.printString("Name", Enum.getName()); + Name = Enum.getName(); +} + +void CVTypeDumperImpl::visitBaseClassRecord(TypeLeafKind Leaf, + BaseClassRecord &Base) { DictScope S(W, "BaseClass"); - printMemberAttributes(Base->Attrs); - printTypeIndex("BaseType", Base->BaseType); - uint64_t BaseOffset; - if (!decodeUIntLeaf(FieldData, BaseOffset)) - return parseError(); - W.printHex("BaseOffset", BaseOffset); + printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("BaseType", Base.getBaseType()); + W.printHex("BaseOffset", Base.getBaseOffset()); } -void CVTypeDumperImpl::visitVirtualBaseClass(TypeLeafKind Leaf, - const VirtualBaseClass *Base, - ArrayRef &FieldData) { +void CVTypeDumperImpl::visitVirtualBaseClassRecord( + TypeLeafKind Leaf, VirtualBaseClassRecord &Base) { DictScope S(W, "VirtualBaseClass"); - printMemberAttributes(Base->Attrs); - printTypeIndex("BaseType", Base->BaseType); - printTypeIndex("VBPtrType", Base->VBPtrType); - uint64_t VBPtrOffset, VBTableIndex; - if (!decodeUIntLeaf(FieldData, VBPtrOffset)) - return parseError(); - if (!decodeUIntLeaf(FieldData, VBTableIndex)) - return parseError(); - W.printHex("VBPtrOffset", VBPtrOffset); - W.printHex("VBTableIndex", VBTableIndex); + printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("BaseType", Base.getBaseType()); + printTypeIndex("VBPtrType", Base.getVBPtrType()); + W.printHex("VBPtrOffset", Base.getVBPtrOffset()); + W.printHex("VBTableIndex", Base.getVTableIndex()); } StringRef CVTypeDumper::getTypeName(TypeIndex TI) { Index: lib/DebugInfo/CodeView/TypeStream.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeStream.cpp +++ lib/DebugInfo/CodeView/TypeStream.cpp @@ -13,7 +13,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" -#include "llvm/DebugInfo/CodeView/TypeStream.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" using namespace llvm; using namespace llvm::codeview; Index: lib/DebugInfo/CodeView/TypeTableBuilder.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeTableBuilder.cpp +++ lib/DebugInfo/CodeView/TypeTableBuilder.cpp @@ -17,27 +17,6 @@ using namespace llvm; using namespace codeview; -namespace { - -const int PointerKindShift = 0; -const int PointerModeShift = 5; -const int PointerSizeShift = 13; - -const int ClassHfaKindShift = 11; -const int ClassWindowsRTClassKindShift = 14; - -void writePointerBase(TypeRecordBuilder &Builder, - const PointerRecordBase &Record) { - Builder.writeTypeIndex(Record.getReferentType()); - uint32_t flags = - static_cast(Record.getOptions()) | - (Record.getSize() << PointerSizeShift) | - (static_cast(Record.getMode()) << PointerModeShift) | - (static_cast(Record.getPointerKind()) << PointerKindShift); - Builder.writeUInt32(flags); -} -} - TypeTableBuilder::TypeTableBuilder() {} TypeTableBuilder::~TypeTableBuilder() {} @@ -46,7 +25,7 @@ TypeRecordBuilder Builder(TypeRecordKind::Modifier); Builder.writeTypeIndex(Record.getModifiedType()); - Builder.writeUInt16(static_cast(Record.getOptions())); + Builder.writeUInt16(static_cast(Record.getModifiers())); return writeRecord(Builder); } @@ -79,12 +58,11 @@ return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeArgumentList(const ArgumentListRecord &Record) { +TypeIndex TypeTableBuilder::writeArgumentList(const StringListRecord &Record) { TypeRecordBuilder Builder(TypeRecordKind::ArgumentList); - Builder.writeUInt32(Record.getArgumentTypes().size()); - for (TypeIndex TI : Record.getArgumentTypes()) { + Builder.writeUInt32(Record.getIndices().size()); + for (TypeIndex TI : Record.getIndices()) { Builder.writeTypeIndex(TI); } @@ -94,19 +72,20 @@ TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) { TypeRecordBuilder Builder(TypeRecordKind::Pointer); - writePointerBase(Builder, Record); - - return writeRecord(Builder); -} - -TypeIndex -TypeTableBuilder::writePointerToMember(const PointerToMemberRecord &Record) { - TypeRecordBuilder Builder(TypeRecordKind::Pointer); - - writePointerBase(Builder, Record); + Builder.writeTypeIndex(Record.getReferentType()); + uint32_t flags = static_cast(Record.getOptions()) | + (Record.getSize() << PointerRecord::PointerSizeShift) | + (static_cast(Record.getMode()) + << PointerRecord::PointerModeShift) | + (static_cast(Record.getPointerKind()) + << PointerRecord::PointerKindShift); + Builder.writeUInt32(flags); - Builder.writeTypeIndex(Record.getContainingType()); - Builder.writeUInt16(static_cast(Record.getRepresentation())); + if (Record.isPointerToMember()) { + const MemberPointerInfo &M = Record.getMemberInfo(); + Builder.writeTypeIndex(M.getContainingType()); + Builder.writeUInt16(static_cast(M.getRepresentation())); + } return writeRecord(Builder); } @@ -122,7 +101,7 @@ return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeAggregate(const AggregateRecord &Record) { +TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) { assert((Record.getKind() == TypeRecordKind::Structure) || (Record.getKind() == TypeRecordKind::Class) || (Record.getKind() == TypeRecordKind::Union)); @@ -132,18 +111,13 @@ Builder.writeUInt16(Record.getMemberCount()); uint16_t Flags = static_cast(Record.getOptions()) | - (static_cast(Record.getHfa()) << ClassHfaKindShift) | + (static_cast(Record.getHfa()) << ClassRecord::HfaKindShift) | (static_cast(Record.getWinRTKind()) - << ClassWindowsRTClassKindShift); + << ClassRecord::WinRTKindShift); Builder.writeUInt16(Flags); Builder.writeTypeIndex(Record.getFieldList()); - if (Record.getKind() != TypeRecordKind::Union) { - Builder.writeTypeIndex(Record.getDerivationList()); - Builder.writeTypeIndex(Record.getVTableShape()); - } else { - assert(Record.getDerivationList() == TypeIndex()); - assert(Record.getVTableShape() == TypeIndex()); - } + Builder.writeTypeIndex(Record.getDerivationList()); + Builder.writeTypeIndex(Record.getVTableShape()); Builder.writeEncodedUnsignedInteger(Record.getSize()); Builder.writeNullTerminatedString(Record.getName()); if ((Record.getOptions() & ClassOptions::HasUniqueName) !=