From 12329871702d45f8d7861465ce28e6f1b61dfc3c Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 5 May 2016 00:34:33 +0000 Subject: [PATCH] [codeview] Move dumper into lib/DebugInfo/CodeView So that we can call it from llvm-pdbdump. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@268580 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../llvm/DebugInfo/CodeView/CVTypeVisitor.h | 6 +- include/llvm/DebugInfo/CodeView/TypeDumper.h | 65 ++ include/llvm/DebugInfo/CodeView/TypeStream.h | 19 + lib/DebugInfo/CodeView/CMakeLists.txt | 2 + lib/DebugInfo/CodeView/TypeDumper.cpp | 753 ++++++++++++++++ lib/DebugInfo/CodeView/TypeStream.cpp | 97 +++ tools/llvm-readobj/CMakeLists.txt | 1 + tools/llvm-readobj/COFFDumper.cpp | 819 +----------------- 8 files changed, 949 insertions(+), 813 deletions(-) create mode 100644 include/llvm/DebugInfo/CodeView/TypeDumper.h create mode 100644 lib/DebugInfo/CodeView/TypeDumper.cpp create mode 100644 lib/DebugInfo/CodeView/TypeStream.cpp diff --git a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h index a9e25219a7d2..385ba3969b7e 100644 --- a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -115,8 +115,7 @@ class CVTypeVisitor { // Field list records do not describe their own length, so we cannot // continue parsing past an unknown member type. visitUnknownMember(Leaf); - HadError = true; - return; + return parseError(); #define MEMBER_RECORD(ClassName, LeafEnum) \ case LeafEnum: { \ const ClassName *Rec; \ @@ -142,6 +141,9 @@ class CVTypeVisitor { /// method is only called at most once per field list record. void visitUnknownMember(TypeLeafKind Leaf) {} + /// Helper for returning from a void function when the stream is corrupted. + void parseError() { HadError = true; } + private: /// Whether a type stream parsing error was encountered. bool HadError = false; diff --git a/include/llvm/DebugInfo/CodeView/TypeDumper.h b/include/llvm/DebugInfo/CodeView/TypeDumper.h new file mode 100644 index 000000000000..9f7b8555c91b --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeDumper.h @@ -0,0 +1,65 @@ +//===-- TypeDumper.h - CodeView type info dumper ----------------*- 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_TYPEDUMPER_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" + +namespace llvm { +class ScopedPrinter; + +namespace codeview { + +/// Dumper for CodeView type streams found in COFF object files and PDB files. +class CVTypeDumper { +public: + CVTypeDumper(ScopedPrinter &W, bool PrintRecordBytes) + : W(W), PrintRecordBytes(PrintRecordBytes) {} + + StringRef getTypeName(TypeIndex TI); + void printTypeIndex(StringRef FieldName, TypeIndex TI); + + /// Dumps the type records in Data. Returns false if there was a type stream + /// parse error, and true otherwise. + bool dump(ArrayRef Data); + + /// Gets the type index for the next type record. + unsigned getNextTypeIndex() const { + return 0x1000 + CVUDTNames.size(); + } + + /// Records the name of a type, and reserves its type index. + void recordType(StringRef Name) { CVUDTNames.push_back(Name); } + + /// Saves the name in a StringSet and creates a stable StringRef. + StringRef saveName(StringRef TypeName) { + return TypeNames.insert(TypeName).first->getKey(); + } + +private: + ScopedPrinter &W; + + bool PrintRecordBytes = false; + + /// All user defined type records in .debug$T live in here. Type indices + /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to + /// index into this vector. + SmallVector CVUDTNames; + + StringSet<> TypeNames; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H diff --git a/include/llvm/DebugInfo/CodeView/TypeStream.h b/include/llvm/DebugInfo/CodeView/TypeStream.h index 64d2ba1f5967..f91dd473e67a 100644 --- a/include/llvm/DebugInfo/CodeView/TypeStream.h +++ b/include/llvm/DebugInfo/CodeView/TypeStream.h @@ -21,6 +21,8 @@ #include namespace llvm { +class APSInt; + namespace codeview { /// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if @@ -43,6 +45,23 @@ inline std::error_code consumeUInt32(StringRef &Data, uint32_t &Res) { 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); + // A const input iterator interface to the CodeView type stream. class TypeIterator { public: diff --git a/lib/DebugInfo/CodeView/CMakeLists.txt b/lib/DebugInfo/CodeView/CMakeLists.txt index cfa0e4d8b401..2be582f8c1a1 100644 --- a/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/lib/DebugInfo/CodeView/CMakeLists.txt @@ -4,8 +4,10 @@ add_llvm_library(LLVMDebugInfoCodeView ListRecordBuilder.cpp MemoryTypeTableBuilder.cpp MethodListRecordBuilder.cpp + TypeDumper.cpp TypeRecordBuilder.cpp TypeTableBuilder.cpp + TypeStream.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView diff --git a/lib/DebugInfo/CodeView/TypeDumper.cpp b/lib/DebugInfo/CodeView/TypeDumper.cpp new file mode 100644 index 000000000000..9fcc4a24cbe7 --- /dev/null +++ b/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -0,0 +1,753 @@ +//===-- TypeDumper.cpp - CodeView type info dumper --------------*- 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/TypeDumper.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeStream.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace llvm::codeview; + +/// The names here all end in "*". If the simple type is a pointer type, we +/// return the whole name. Otherwise we lop off the last character in our +/// StringRef. +static const EnumEntry SimpleTypeNames[] = { + {"void*", SimpleTypeKind::Void}, + {"*", SimpleTypeKind::NotTranslated}, + {"HRESULT*", SimpleTypeKind::HResult}, + {"signed char*", SimpleTypeKind::SignedCharacter}, + {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, + {"char*", SimpleTypeKind::NarrowCharacter}, + {"wchar_t*", SimpleTypeKind::WideCharacter}, + {"char16_t*", SimpleTypeKind::Character16}, + {"char32_t*", SimpleTypeKind::Character32}, + {"__int8*", SimpleTypeKind::SByte}, + {"unsigned __int8*", SimpleTypeKind::Byte}, + {"short*", SimpleTypeKind::Int16Short}, + {"unsigned short*", SimpleTypeKind::UInt16Short}, + {"__int16*", SimpleTypeKind::Int16}, + {"unsigned __int16*", SimpleTypeKind::UInt16}, + {"long*", SimpleTypeKind::Int32Long}, + {"unsigned long*", SimpleTypeKind::UInt32Long}, + {"int*", SimpleTypeKind::Int32}, + {"unsigned*", SimpleTypeKind::UInt32}, + {"__int64*", SimpleTypeKind::Int64Quad}, + {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, + {"__int64*", SimpleTypeKind::Int64}, + {"unsigned __int64*", SimpleTypeKind::UInt64}, + {"__int128*", SimpleTypeKind::Int128}, + {"unsigned __int128*", SimpleTypeKind::UInt128}, + {"__half*", SimpleTypeKind::Float16}, + {"float*", SimpleTypeKind::Float32}, + {"float*", SimpleTypeKind::Float32PartialPrecision}, + {"__float48*", SimpleTypeKind::Float48}, + {"double*", SimpleTypeKind::Float64}, + {"long double*", SimpleTypeKind::Float80}, + {"__float128*", SimpleTypeKind::Float128}, + {"_Complex float*", SimpleTypeKind::Complex32}, + {"_Complex double*", SimpleTypeKind::Complex64}, + {"_Complex long double*", SimpleTypeKind::Complex80}, + {"_Complex __float128*", SimpleTypeKind::Complex128}, + {"bool*", SimpleTypeKind::Boolean8}, + {"__bool16*", SimpleTypeKind::Boolean16}, + {"__bool32*", SimpleTypeKind::Boolean32}, + {"__bool64*", SimpleTypeKind::Boolean64}, +}; + +static const EnumEntry LeafTypeNames[] = { +#define LEAF_TYPE(enum, val) { #enum, enum }, +#include "llvm/DebugInfo/CodeView/CVLeafTypes.def" +}; + +#define ENUM_ENTRY(enum_class, enum) \ + { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) } + +static const EnumEntry ClassOptionNames[] = { + ENUM_ENTRY(ClassOptions, Packed), + ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor), + ENUM_ENTRY(ClassOptions, HasOverloadedOperator), + ENUM_ENTRY(ClassOptions, Nested), + ENUM_ENTRY(ClassOptions, ContainsNestedClass), + ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator), + ENUM_ENTRY(ClassOptions, HasConversionOperator), + ENUM_ENTRY(ClassOptions, ForwardReference), + ENUM_ENTRY(ClassOptions, Scoped), + ENUM_ENTRY(ClassOptions, HasUniqueName), + ENUM_ENTRY(ClassOptions, Sealed), + ENUM_ENTRY(ClassOptions, Intrinsic), +}; + +static const EnumEntry MemberAccessNames[] = { + ENUM_ENTRY(MemberAccess, None), + ENUM_ENTRY(MemberAccess, Private), + ENUM_ENTRY(MemberAccess, Protected), + ENUM_ENTRY(MemberAccess, Public), +}; + +static const EnumEntry MethodOptionNames[] = { + ENUM_ENTRY(MethodOptions, Pseudo), + ENUM_ENTRY(MethodOptions, NoInherit), + ENUM_ENTRY(MethodOptions, NoConstruct), + ENUM_ENTRY(MethodOptions, CompilerGenerated), + ENUM_ENTRY(MethodOptions, Sealed), +}; + +static const EnumEntry MemberKindNames[] = { + ENUM_ENTRY(MethodKind, Vanilla), + ENUM_ENTRY(MethodKind, Virtual), + ENUM_ENTRY(MethodKind, Static), + ENUM_ENTRY(MethodKind, Friend), + ENUM_ENTRY(MethodKind, IntroducingVirtual), + ENUM_ENTRY(MethodKind, PureVirtual), + ENUM_ENTRY(MethodKind, PureIntroducingVirtual), +}; + +static const EnumEntry PtrKindNames[] = { + ENUM_ENTRY(PointerKind, Near16), + ENUM_ENTRY(PointerKind, Far16), + ENUM_ENTRY(PointerKind, Huge16), + ENUM_ENTRY(PointerKind, BasedOnSegment), + ENUM_ENTRY(PointerKind, BasedOnValue), + ENUM_ENTRY(PointerKind, BasedOnSegmentValue), + ENUM_ENTRY(PointerKind, BasedOnAddress), + ENUM_ENTRY(PointerKind, BasedOnSegmentAddress), + ENUM_ENTRY(PointerKind, BasedOnType), + ENUM_ENTRY(PointerKind, BasedOnSelf), + ENUM_ENTRY(PointerKind, Near32), + ENUM_ENTRY(PointerKind, Far32), + ENUM_ENTRY(PointerKind, Near64), +}; + +static const EnumEntry PtrModeNames[] = { + ENUM_ENTRY(PointerMode, Pointer), + ENUM_ENTRY(PointerMode, LValueReference), + ENUM_ENTRY(PointerMode, PointerToDataMember), + ENUM_ENTRY(PointerMode, PointerToMemberFunction), + ENUM_ENTRY(PointerMode, RValueReference), +}; + +static const EnumEntry PtrMemberRepNames[] = { + ENUM_ENTRY(PointerToMemberRepresentation, Unknown), + ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData), + ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData), + ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData), + ENUM_ENTRY(PointerToMemberRepresentation, GeneralData), + ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction), + ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction), + ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction), + ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction), +}; + +static const EnumEntry TypeModifierNames[] = { + ENUM_ENTRY(ModifierOptions, Const), + ENUM_ENTRY(ModifierOptions, Volatile), + ENUM_ENTRY(ModifierOptions, Unaligned), +}; + +static const EnumEntry CallingConventions[] = { + ENUM_ENTRY(CallingConvention, NearC), + ENUM_ENTRY(CallingConvention, FarC), + ENUM_ENTRY(CallingConvention, NearPascal), + ENUM_ENTRY(CallingConvention, FarPascal), + ENUM_ENTRY(CallingConvention, NearFast), + ENUM_ENTRY(CallingConvention, FarFast), + ENUM_ENTRY(CallingConvention, NearStdCall), + ENUM_ENTRY(CallingConvention, FarStdCall), + ENUM_ENTRY(CallingConvention, NearSysCall), + ENUM_ENTRY(CallingConvention, FarSysCall), + ENUM_ENTRY(CallingConvention, ThisCall), + ENUM_ENTRY(CallingConvention, MipsCall), + ENUM_ENTRY(CallingConvention, Generic), + ENUM_ENTRY(CallingConvention, AlphaCall), + ENUM_ENTRY(CallingConvention, PpcCall), + ENUM_ENTRY(CallingConvention, SHCall), + ENUM_ENTRY(CallingConvention, ArmCall), + ENUM_ENTRY(CallingConvention, AM33Call), + ENUM_ENTRY(CallingConvention, TriCall), + ENUM_ENTRY(CallingConvention, SH5Call), + ENUM_ENTRY(CallingConvention, M32RCall), + ENUM_ENTRY(CallingConvention, ClrCall), + ENUM_ENTRY(CallingConvention, Inline), + ENUM_ENTRY(CallingConvention, NearVector), +}; + +static const EnumEntry FunctionOptionEnum[] = { + ENUM_ENTRY(FunctionOptions, CxxReturnUdt), + ENUM_ENTRY(FunctionOptions, Constructor), + ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases), +}; + +#undef ENUM_ENTRY + + +namespace { + +/// Use this private dumper implementation to keep implementation details about +/// the visitor out of TypeDumper.h. +class CVTypeDumperImpl : public CVTypeVisitor { +public: + CVTypeDumperImpl(CVTypeDumper &CVTD, ScopedPrinter &W, bool PrintRecordBytes) + : CVTD(CVTD), W(W), PrintRecordBytes(PrintRecordBytes) {} + + /// CVTypeVisitor overrides. + /// FIXME: Bury these in the .cc file to hide implementation details. +#define TYPE_RECORD(ClassName, LeafEnum) \ + void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ + ArrayRef LeafData); +#define TYPE_RECORD_ALIAS(ClassName, LeafEnum) +#define MEMBER_RECORD(ClassName, LeafEnum) \ + void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ + ArrayRef &FieldData); +#define MEMBER_RECORD_ALIAS(ClassName, LeafEnum) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + + /// Method overload lists are a special case. + void visitMethodList(TypeLeafKind Leaf, ArrayRef LeafData); + + void visitUnknownMember(TypeLeafKind Leaf); + + void visitTypeBegin(TypeLeafKind Leaf, ArrayRef LeafData); + void visitTypeEnd(TypeLeafKind Leaf, ArrayRef LeafData); + + void printMemberAttributes(MemberAttributes Attrs); + +private: + /// Forwards to the dumper, which holds the persistent state from visitation. + StringRef getTypeName(TypeIndex TI) { + return CVTD.getTypeName(TI); + } + + void printTypeIndex(StringRef FieldName, TypeIndex TI) { + CVTD.printTypeIndex(FieldName, TI); + } + + CVTypeDumper &CVTD; + ScopedPrinter &W; + bool PrintRecordBytes = false; + + /// Name of the current type. Only valid before visitTypeEnd. + StringRef Name; +}; + +} // 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) \ + case LeafName: return #ClassName; +#include "llvm/DebugInfo/CodeView/CVLeafTypes.def" + default: + break; + } + return "UnknownLeaf"; +} + +void CVTypeDumperImpl::visitTypeBegin(TypeLeafKind Leaf, + ArrayRef LeafData) { + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + + W.startLine() << getLeafTypeName(Leaf) << " {\n"; + W.indent(); + W.printEnum("TypeLeafKind", unsigned(Leaf), makeArrayRef(LeafTypeNames)); + W.printHex("TypeIndex", CVTD.getNextTypeIndex()); +} + +void CVTypeDumperImpl::visitTypeEnd(TypeLeafKind Leaf, + ArrayRef LeafData) { + // Always record some name for every type, even if Name is empty. CVUDTNames + // is indexed by type index, and must have one entry for every type. + CVTD.recordType(Name); + + if (PrintRecordBytes) + W.printBinaryBlock("LeafData", getBytesAsCharacters(LeafData)); + + W.unindent(); + 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); + // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. + Name = StringData; +} + +void CVTypeDumperImpl::visitArgList(TypeLeafKind Leaf, const ArgList *Args, + ArrayRef LeafData) { + W.printNumber("NumArgs", Args->NumArgs); + 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); + TypeName.append(ArgTypeName); + if (ArgI + 1 != Args->NumArgs) + 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; + 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; + 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); + } +} + +void CVTypeDumperImpl::visitEnumType(TypeLeafKind Leaf, const EnumType *Enum, + ArrayRef LeafData) { + W.printNumber("NumEnumerators", Enum->NumEnumerators); + W.printFlags("Properties", uint16_t(Enum->Properties), + 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), + makeArrayRef(CallingConventions)); + W.printFlags("FunctionOptions", uint8_t(Proc->Options), + makeArrayRef(FunctionOptionEnum)); + W.printNumber("NumParameters", Proc->NumParameters); + printTypeIndex("ArgListType", Proc->ArgListType); + + StringRef ReturnTypeName = getTypeName(Proc->ReturnType); + StringRef ArgListTypeName = getTypeName(Proc->ArgListType); + 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), + makeArrayRef(CallingConventions)); + W.printFlags("FunctionOptions", uint8_t(MemberFunc->Options), + makeArrayRef(FunctionOptionEnum)); + W.printNumber("NumParameters", MemberFunc->NumParameters); + printTypeIndex("ArgListType", MemberFunc->ArgListType); + W.printNumber("ThisAdjustment", MemberFunc->ThisAdjustment); + + StringRef ReturnTypeName = getTypeName(MemberFunc->ReturnType); + StringRef ClassTypeName = getTypeName(MemberFunc->ClassType); + StringRef ArgListTypeName = getTypeName(MemberFunc->ArgListType); + SmallString<256> TypeName(ReturnTypeName); + TypeName.push_back(' '); + TypeName.append(ClassTypeName); + TypeName.append("::"); + TypeName.append(ArgListTypeName); + Name = CVTD.saveName(TypeName); +} + +void CVTypeDumperImpl::visitMethodList(TypeLeafKind Leaf, + ArrayRef LeafData) { + while (!LeafData.empty()) { + const MethodListEntry *Method; + if (!consumeObject(LeafData, Method)) + return; + 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); + } + } +} + +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::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::visitPointerType(TypeLeafKind Leaf, const PointerType *Ptr, + ArrayRef LeafData) { + printTypeIndex("PointeeType", Ptr->PointeeType); + W.printHex("PointerAttributes", Ptr->Attrs); + W.printEnum("PtrType", unsigned(Ptr->getPtrKind()), + 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, + makeArrayRef(PtrMemberRepNames)); + + StringRef PointeeName = getTypeName(Ptr->PointeeType); + StringRef ClassName = getTypeName(PMT->ClassType); + 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()) + TypeName.append("const "); + if (Ptr->isVolatile()) + TypeName.append("volatile "); + if (Ptr->isUnaligned()) + TypeName.append("__unaligned "); + + TypeName.append(getTypeName(Ptr->PointeeType)); + + if (Ptr->getPtrMode() == PointerMode::LValueReference) + TypeName.append("&"); + else if (Ptr->getPtrMode() == PointerMode::RValueReference) + TypeName.append("&&"); + else if (Ptr->getPtrMode() == 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)); + + StringRef ModifiedName = getTypeName(Mod->ModifiedType); + SmallString<256> TypeName; + if (Mod->Modifiers & uint16_t(ModifierOptions::Const)) + TypeName.append("const "); + if (Mod->Modifiers & uint16_t(ModifierOptions::Volatile)) + TypeName.append("volatile "); + if (Mod->Modifiers & 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::visitUDTSrcLine(TypeLeafKind Leaf, const UDTSrcLine *Line, + ArrayRef LeafData) { + printTypeIndex("UDT", Line->UDT); + printTypeIndex("SourceFile", Line->SourceFile); + W.printNumber("LineNumber", Line->LineNumber); +} + +void CVTypeDumperImpl::visitBuildInfo(TypeLeafKind Leaf, const BuildInfo *Args, + ArrayRef LeafData) { + W.printNumber("NumArgs", Args->NumArgs); + + ListScope Arguments(W, "Arguments"); + for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) { + const TypeIndex *Type; + if (!consumeObject(LeafData, Type)) + return; + printTypeIndex("ArgType", *Type); + } +} + +void CVTypeDumperImpl::printMemberAttributes(MemberAttributes Attrs) { + W.printEnum("AccessSpecifier", uint8_t(Attrs.getAccess()), + 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()), + makeArrayRef(MethodOptionNames)); + } +} + +void CVTypeDumperImpl::visitUnknownMember(TypeLeafKind Leaf) { + W.printHex("UnknownMember", unsigned(Leaf)); +} + +void CVTypeDumperImpl::visitNestedType(TypeLeafKind Leaf, const NestedType *Nested, + ArrayRef &FieldData) { + DictScope S(W, "NestedType"); + printTypeIndex("Type", Nested->Type); + StringRef Name = getBytesAsCString(FieldData); + FieldData = FieldData.drop_front(Name.size() + 1); + W.printString("Name", Name); +} + +void CVTypeDumperImpl::visitOneMethod(TypeLeafKind Leaf, const OneMethod *Method, + ArrayRef &FieldData) { + DictScope S(W, "OneMethod"); + printMemberAttributes(Method->Attrs); + printTypeIndex("Type", Method->Type); + // 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); +} + +void CVTypeDumperImpl::visitOverloadedMethod(TypeLeafKind Leaf, + const OverloadedMethod *Method, + ArrayRef &FieldData) { + 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); +} + +void CVTypeDumperImpl::visitDataMember(TypeLeafKind Leaf, const DataMember *Field, + ArrayRef &FieldData) { + 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) { + 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); +} + +void CVTypeDumperImpl::visitVirtualFunctionPointer( + TypeLeafKind Leaf, const VirtualFunctionPointer *VFTable, + ArrayRef &FieldData) { + DictScope S(W, "VirtualFunctionPointer"); + printTypeIndex("Type", VFTable->Type); +} + +void CVTypeDumperImpl::visitEnumerator(TypeLeafKind Leaf, const Enumerator *Enum, + ArrayRef &FieldData) { + 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) { + DictScope S(W, "BaseClass"); + printMemberAttributes(Base->Attrs); + printTypeIndex("BaseType", Base->BaseType); + uint64_t BaseOffset; + if (!decodeUIntLeaf(FieldData, BaseOffset)) + return parseError(); + W.printHex("BaseOffset", BaseOffset); +} + +void CVTypeDumperImpl::visitVirtualBaseClass(TypeLeafKind Leaf, + const VirtualBaseClass *Base, + ArrayRef &FieldData) { + 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); +} + +StringRef CVTypeDumper::getTypeName(TypeIndex TI) { + if (TI.isNoType()) + return ""; + + if (TI.isSimple()) { + // This is a simple type. + for (const auto &SimpleTypeName : SimpleTypeNames) { + if (SimpleTypeName.Value == TI.getSimpleKind()) { + if (TI.getSimpleMode() == SimpleTypeMode::Direct) + return SimpleTypeName.Name.drop_back(1); + // Otherwise, this is a pointer type. We gloss over the distinction + // between near, far, 64, 32, etc, and just give a pointer type. + return SimpleTypeName.Name; + } + } + return ""; + } + + // User-defined type. + StringRef UDTName; + unsigned UDTIndex = TI.getIndex() - 0x1000; + if (UDTIndex < CVUDTNames.size()) + return CVUDTNames[UDTIndex]; + + return ""; +} + +void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { + StringRef TypeName; + if (!TI.isNoType()) + TypeName = getTypeName(TI); + if (!TypeName.empty()) + W.printHex(FieldName, TypeName, TI.getIndex()); + else + W.printHex(FieldName, TI.getIndex()); +} + +bool CVTypeDumper::dump(ArrayRef Data) { + CVTypeDumperImpl Dumper(*this, W, PrintRecordBytes); + Dumper.visitTypeStream(Data); + return !Dumper.hadError(); +} diff --git a/lib/DebugInfo/CodeView/TypeStream.cpp b/lib/DebugInfo/CodeView/TypeStream.cpp new file mode 100644 index 000000000000..73dfc50c8ab7 --- /dev/null +++ b/lib/DebugInfo/CodeView/TypeStream.cpp @@ -0,0 +1,97 @@ +//===-- TypeStream.cpp ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Utilities for parsing CodeView type streams. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/DebugInfo/CodeView/TypeStream.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::support; + +bool llvm::codeview::decodeNumericLeaf(ArrayRef &Data, APSInt &Num) { + // Used to avoid overload ambiguity on APInt construtor. + bool FalseVal = false; + if (Data.size() < 2) + return false; + uint16_t Short = *reinterpret_cast(Data.data()); + Data = Data.drop_front(2); + if (Short < LF_NUMERIC) { + Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), + /*isUnsigned=*/true); + return true; + } + switch (Short) { + case LF_CHAR: + Num = APSInt(APInt(/*numBits=*/8, + *reinterpret_cast(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(1); + return true; + case LF_SHORT: + Num = APSInt(APInt(/*numBits=*/16, + *reinterpret_cast(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(2); + return true; + case LF_USHORT: + Num = APSInt(APInt(/*numBits=*/16, + *reinterpret_cast(Data.data()), + /*isSigned=*/false), + /*isUnsigned=*/true); + Data = Data.drop_front(2); + return true; + case LF_LONG: + Num = APSInt(APInt(/*numBits=*/32, + *reinterpret_cast(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(4); + return true; + case LF_ULONG: + Num = APSInt(APInt(/*numBits=*/32, + *reinterpret_cast(Data.data()), + /*isSigned=*/FalseVal), + /*isUnsigned=*/true); + Data = Data.drop_front(4); + return true; + case LF_QUADWORD: + Num = APSInt(APInt(/*numBits=*/64, + *reinterpret_cast(Data.data()), + /*isSigned=*/true), + /*isUnsigned=*/false); + Data = Data.drop_front(8); + return true; + case LF_UQUADWORD: + Num = APSInt(APInt(/*numBits=*/64, + *reinterpret_cast(Data.data()), + /*isSigned=*/false), + /*isUnsigned=*/true); + Data = Data.drop_front(8); + return true; + } + return false; +} + +/// Decode a numeric leaf value that is known to be a uint32_t. +bool llvm::codeview::decodeUIntLeaf(ArrayRef &Data, uint64_t &Num) { + APSInt N; + if (!decodeNumericLeaf(Data, N)) + return false; + if (N.isSigned() || !N.isIntN(64)) + return false; + Num = N.getLimitedValue(); + return true; +} diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index e167874c1a18..70a7632627d8 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + DebugInfoCodeView Object Support ) diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 8e6d2276e0d2..ebb52aa2acd4 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -22,11 +22,10 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeDumper.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeStream.h" @@ -54,65 +53,11 @@ using namespace llvm::Win64EH; namespace { -class CVTypeDumper : public CVTypeVisitor { -public: - CVTypeDumper(ScopedPrinter &W) : W(W) {} - - StringRef getTypeName(TypeIndex TI); - void printTypeIndex(StringRef FieldName, TypeIndex TI); - - void dump(ArrayRef Data); - - /// CVTypeVisitor overrides. -#define TYPE_RECORD(ClassName, LeafEnum) \ - void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ - ArrayRef LeafData); -#define TYPE_RECORD_ALIAS(ClassName, LeafEnum) -#define MEMBER_RECORD(ClassName, LeafEnum) \ - void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ - ArrayRef &FieldData); -#define MEMBER_RECORD_ALIAS(ClassName, LeafEnum) -#include "llvm/DebugInfo/CodeView/TypeRecords.def" - - /// Method overload lists are a special case. - void visitMethodList(TypeLeafKind Leaf, ArrayRef LeafData); - - void visitUnknownMember(TypeLeafKind Leaf); - - void visitTypeBegin(TypeLeafKind Leaf, ArrayRef LeafData); - void visitTypeEnd(TypeLeafKind Leaf, ArrayRef LeafData); - -private: - void printMemberAttributes(MemberAttributes Attrs); - - /// 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; - } - - ScopedPrinter &W; - - /// Name of the current type. Only valid before visitTypeEnd. - StringRef Name; - - /// All user defined type records in .debug$T live in here. Type indices - /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to - /// index into this vector. - SmallVector CVUDTNames; - - StringSet<> TypeNames; -}; - class COFFDumper : public ObjDumper { public: COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer) - : ObjDumper(Writer), Obj(Obj), CVTD(Writer) {} + : ObjDumper(Writer), Obj(Obj), + CVTD(Writer, opts::CodeViewSubsectionBytes) {} void printFileHeaders() override; void printSections() override; @@ -194,8 +139,7 @@ class COFFDumper : public ObjDumper { CVTypeDumper CVTD; }; -} // namespace - +} // end namespace namespace llvm { @@ -653,178 +597,6 @@ static const EnumEntry FrameCookieKinds[] = { LLVM_READOBJ_ENUM_ENT(FrameCookieSym, XorR13), }; -static const EnumEntry ClassOptionNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Packed), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasConstructorOrDestructor), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasOverloadedOperator), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Nested), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, ContainsNestedClass), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasOverloadedAssignmentOperator), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasConversionOperator), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, ForwardReference), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Scoped), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasUniqueName), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Sealed), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Intrinsic), -}; - -static const EnumEntry MemberAccessNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, None), - LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, Private), - LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, Protected), - LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, Public), -}; - -static const EnumEntry MethodOptionNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, Pseudo), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, NoInherit), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, NoConstruct), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, CompilerGenerated), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, Sealed), -}; - -static const EnumEntry MemberKindNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Vanilla), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Virtual), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Static), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Friend), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, IntroducingVirtual), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, PureVirtual), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, PureIntroducingVirtual), -}; - -/// The names here all end in "*". If the simple type is a pointer type, we -/// return the whole name. Otherwise we lop off the last character in our -/// StringRef. -static const EnumEntry SimpleTypeNames[] = { - {"void*", SimpleTypeKind::Void}, - {"*", SimpleTypeKind::NotTranslated}, - {"HRESULT*", SimpleTypeKind::HResult}, - {"signed char*", SimpleTypeKind::SignedCharacter}, - {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, - {"char*", SimpleTypeKind::NarrowCharacter}, - {"wchar_t*", SimpleTypeKind::WideCharacter}, - {"char16_t*", SimpleTypeKind::Character16}, - {"char32_t*", SimpleTypeKind::Character32}, - {"__int8*", SimpleTypeKind::SByte}, - {"unsigned __int8*", SimpleTypeKind::Byte}, - {"short*", SimpleTypeKind::Int16Short}, - {"unsigned short*", SimpleTypeKind::UInt16Short}, - {"__int16*", SimpleTypeKind::Int16}, - {"unsigned __int16*", SimpleTypeKind::UInt16}, - {"long*", SimpleTypeKind::Int32Long}, - {"unsigned long*", SimpleTypeKind::UInt32Long}, - {"int*", SimpleTypeKind::Int32}, - {"unsigned*", SimpleTypeKind::UInt32}, - {"__int64*", SimpleTypeKind::Int64Quad}, - {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, - {"__int64*", SimpleTypeKind::Int64}, - {"unsigned __int64*", SimpleTypeKind::UInt64}, - {"__int128*", SimpleTypeKind::Int128}, - {"unsigned __int128*", SimpleTypeKind::UInt128}, - {"__half*", SimpleTypeKind::Float16}, - {"float*", SimpleTypeKind::Float32}, - {"float*", SimpleTypeKind::Float32PartialPrecision}, - {"__float48*", SimpleTypeKind::Float48}, - {"double*", SimpleTypeKind::Float64}, - {"long double*", SimpleTypeKind::Float80}, - {"__float128*", SimpleTypeKind::Float128}, - {"_Complex float*", SimpleTypeKind::Complex32}, - {"_Complex double*", SimpleTypeKind::Complex64}, - {"_Complex long double*", SimpleTypeKind::Complex80}, - {"_Complex __float128*", SimpleTypeKind::Complex128}, - {"bool*", SimpleTypeKind::Boolean8}, - {"__bool16*", SimpleTypeKind::Boolean16}, - {"__bool32*", SimpleTypeKind::Boolean32}, - {"__bool64*", SimpleTypeKind::Boolean64}, -}; - -static const EnumEntry LeafTypeNames[] = { -#define LEAF_TYPE(name, val) LLVM_READOBJ_ENUM_ENT(TypeLeafKind, name), -#include "llvm/DebugInfo/CodeView/CVLeafTypes.def" -}; - -static const EnumEntry PtrKindNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Near16), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Far16), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Huge16), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnSegment), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnValue), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentValue), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnAddress), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentAddress), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnType), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnSelf), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Near32), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Far32), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Near64), -}; - -static const EnumEntry PtrModeNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, Pointer), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, LValueReference), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, PointerToDataMember), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, PointerToMemberFunction), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, RValueReference), -}; - -static const EnumEntry PtrMemberRepNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, Unknown), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - SingleInheritanceData), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - MultipleInheritanceData), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - VirtualInheritanceData), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralData), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - SingleInheritanceFunction), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - MultipleInheritanceFunction), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - VirtualInheritanceFunction), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralFunction), -}; - -static const EnumEntry TypeModifierNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(ModifierOptions, Const), - LLVM_READOBJ_ENUM_CLASS_ENT(ModifierOptions, Volatile), - LLVM_READOBJ_ENUM_CLASS_ENT(ModifierOptions, Unaligned), -}; - -static const EnumEntry CallingConventions[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearC), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarC), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearPascal), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarPascal), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearFast), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarFast), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearStdCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarStdCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearSysCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarSysCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, ThisCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, MipsCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, Generic), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, AlphaCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, PpcCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, SHCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, ArmCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, AM33Call), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, TriCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, SH5Call), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, M32RCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, ClrCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, Inline), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearVector), -}; - -static const EnumEntry FunctionOptionEnum[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(FunctionOptions, CxxReturnUdt), - LLVM_READOBJ_ENUM_CLASS_ENT(FunctionOptions, Constructor), - LLVM_READOBJ_ENUM_CLASS_ENT(FunctionOptions, ConstructorWithVirtualBases), -}; - static const EnumEntry FileChecksumKindNames[] = { LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, None), LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, MD5), @@ -1214,92 +986,6 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, } } -static std::error_code decodeNumerictLeaf(ArrayRef &Data, - APSInt &Num) { - // Used to avoid overload ambiguity on APInt construtor. - bool FalseVal = false; - if (Data.size() < 2) - return object_error::parse_failed; - uint16_t Short = *reinterpret_cast(Data.data()); - Data = Data.drop_front(2); - if (Short < LF_NUMERIC) { - Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), - /*isUnsigned=*/true); - return std::error_code(); - } - switch (Short) { - case LF_CHAR: - Num = APSInt(APInt(/*numBits=*/8, - *reinterpret_cast(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(1); - return std::error_code(); - case LF_SHORT: - Num = APSInt(APInt(/*numBits=*/16, - *reinterpret_cast(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(2); - return std::error_code(); - case LF_USHORT: - Num = APSInt(APInt(/*numBits=*/16, - *reinterpret_cast(Data.data()), - /*isSigned=*/false), - /*isUnsigned=*/true); - Data = Data.drop_front(2); - return std::error_code(); - case LF_LONG: - Num = APSInt(APInt(/*numBits=*/32, - *reinterpret_cast(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(4); - return std::error_code(); - case LF_ULONG: - Num = APSInt(APInt(/*numBits=*/32, - *reinterpret_cast(Data.data()), - /*isSigned=*/FalseVal), - /*isUnsigned=*/true); - Data = Data.drop_front(4); - return std::error_code(); - case LF_QUADWORD: - Num = APSInt(APInt(/*numBits=*/64, - *reinterpret_cast(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(8); - return std::error_code(); - case LF_UQUADWORD: - Num = APSInt(APInt(/*numBits=*/64, - *reinterpret_cast(Data.data()), - /*isSigned=*/false), - /*isUnsigned=*/true); - Data = Data.drop_front(8); - return std::error_code(); - } - return object_error::parse_failed; -} - -static std::error_code decodeNumerictLeaf(StringRef &Data, APSInt &Num) { - ArrayRef Bytes(reinterpret_cast(Data.data()), - Data.size()); - auto EC = decodeNumerictLeaf(Bytes, Num); - Data = StringRef(reinterpret_cast(Bytes.data()), Bytes.size()); - return EC; -} - -/// Decode an unsigned integer numeric leaf value. -std::error_code decodeUIntLeaf(ArrayRef &Data, uint64_t &Num) { - APSInt N; - if (std::error_code err = decodeNumerictLeaf(Data, N)) - return err; - if (N.isSigned() || !N.isIntN(64)) - return object_error::parse_failed; - Num = N.getLimitedValue(); - return std::error_code(); -} - void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, const SectionRef &Section, StringRef SectionContents) { @@ -1814,7 +1500,8 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, error(consumeObject(SymData, Constant)); printTypeIndex("Type", Constant->Type); APSInt Value; - error(decodeNumerictLeaf(SymData, Value)); + if (!decodeNumericLeaf(SymData, Value)) + error(object_error::parse_failed); W.printNumber("Value", Value); StringRef Name = SymData.split('\0').first; W.printString("Name", Name); @@ -1889,43 +1576,6 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { } } -StringRef CVTypeDumper::getTypeName(TypeIndex TI) { - if (TI.isNoType()) - return ""; - - if (TI.isSimple()) { - // This is a simple type. - for (const auto &SimpleTypeName : SimpleTypeNames) { - if (SimpleTypeName.Value == TI.getSimpleKind()) { - if (TI.getSimpleMode() == SimpleTypeMode::Direct) - return SimpleTypeName.Name.drop_back(1); - // Otherwise, this is a pointer type. We gloss over the distinction - // between near, far, 64, 32, etc, and just give a pointer type. - return SimpleTypeName.Name; - } - } - return ""; - } - - // User-defined type. - StringRef UDTName; - unsigned UDTIndex = TI.getIndex() - 0x1000; - if (UDTIndex < CVUDTNames.size()) - return CVUDTNames[UDTIndex]; - - return ""; -} - -void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { - StringRef TypeName; - if (!TI.isNoType()) - TypeName = getTypeName(TI); - if (!TypeName.empty()) - W.printHex(FieldName, TypeName, TI.getIndex()); - else - W.printHex(FieldName, TI.getIndex()); -} - void COFFDumper::printLocalVariableAddrRange( const LocalVariableAddrRange &Range, const coff_section *Sec, StringRef SectionContents) { @@ -1970,17 +1620,6 @@ void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) { W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset); } -static StringRef getLeafTypeName(TypeLeafKind LT) { - switch (LT) { -#define KNOWN_TYPE(LeafName, Value, ClassName) \ - case LeafName: return #ClassName; -#include "llvm/DebugInfo/CodeView/CVLeafTypes.def" - default: - break; - } - return "UnknownLeaf"; -} - void COFFDumper::printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section) { ListScope D(W, "CodeViewTypes"); @@ -1999,454 +1638,12 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName, ArrayRef BinaryData(reinterpret_cast(Data.data()), Data.size()); - CVTD.dump(BinaryData); -} - -void CVTypeDumper::dump(ArrayRef Data) { - visitTypeStream(Data); - if (hadError()) + if (!CVTD.dump(BinaryData)) { + W.flush(); error(object_error::parse_failed); -} - -void CVTypeDumper::visitTypeBegin(TypeLeafKind Leaf, ArrayRef LeafData) { - // Reset Name to the empty string. If the visitor sets it, we know it. - Name = ""; - - W.startLine() << getLeafTypeName(Leaf) << " {\n"; - W.indent(); - unsigned NextTypeIndex = 0x1000 + CVUDTNames.size(); - W.printEnum("TypeLeafKind", unsigned(Leaf), makeArrayRef(LeafTypeNames)); - W.printHex("TypeIndex", NextTypeIndex); - W.flush(); -} - -void CVTypeDumper::visitTypeEnd(TypeLeafKind Leaf, ArrayRef LeafData) { - // Always record some name for every type, even if Name is empty, since - // CVUDTNames is indexed by TypeIndex. - CVUDTNames.push_back(Name); - - if (opts::CodeViewSubsectionBytes) - W.printBinaryBlock("LeafData", getBytesAsCharacters(LeafData)); - - W.unindent(); - W.startLine() << "}\n"; - W.flush(); -} - -void CVTypeDumper::visitStringId(TypeLeafKind Leaf, const StringId *String, - ArrayRef LeafData) { - W.printHex("Id", String->id.getIndex()); - StringRef StringData = getBytesAsCString(LeafData); - W.printString("StringData", StringData); - // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. - Name = StringData; -} - -void CVTypeDumper::visitArgList(TypeLeafKind Leaf, const ArgList *Args, - ArrayRef LeafData) { - W.printNumber("NumArgs", Args->NumArgs); - 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); - TypeName.append(ArgTypeName); - if (ArgI + 1 != Args->NumArgs) - TypeName.append(", "); - } - TypeName.push_back(')'); - Name = TypeNames.insert(TypeName).first->getKey(); -} - -void CVTypeDumper::visitClassType(TypeLeafKind Leaf, const ClassType *Class, - ArrayRef LeafData) { - W.printNumber("MemberCount", Class->MemberCount); - uint16_t Props = Class->Properties; - W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); - printTypeIndex("FieldList", Class->FieldList); - printTypeIndex("DerivedFrom", Class->DerivedFrom); - printTypeIndex("VShape", Class->VShape); - uint64_t SizeOf; - error(decodeUIntLeaf(LeafData, SizeOf)); - 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 error(object_error::parse_failed); - W.printString("LinkageName", LinkageName); - } -} - -void CVTypeDumper::visitUnionType(TypeLeafKind Leaf, const UnionType *Union, - ArrayRef LeafData) { - W.printNumber("MemberCount", Union->MemberCount); - uint16_t Props = Union->Properties; - W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); - printTypeIndex("FieldList", Union->FieldList); - uint64_t SizeOf; - error(decodeUIntLeaf(LeafData, SizeOf)); - 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 error(object_error::parse_failed); - W.printString("LinkageName", LinkageName); } } -void CVTypeDumper::visitEnumType(TypeLeafKind Leaf, const EnumType *Enum, - ArrayRef LeafData) { - W.printNumber("NumEnumerators", Enum->NumEnumerators); - W.printFlags("Properties", uint16_t(Enum->Properties), - makeArrayRef(ClassOptionNames)); - printTypeIndex("UnderlyingType", Enum->UnderlyingType); - printTypeIndex("FieldListType", Enum->FieldListType); - Name = getBytesAsCString(LeafData); - W.printString("Name", Name); -} - -void CVTypeDumper::visitArrayType(TypeLeafKind Leaf, const ArrayType *AT, - ArrayRef LeafData) { - printTypeIndex("ElementType", AT->ElementType); - printTypeIndex("IndexType", AT->IndexType); - uint64_t SizeOf; - error(decodeUIntLeaf(LeafData, SizeOf)); - W.printNumber("SizeOf", SizeOf); - Name = getBytesAsCString(LeafData); - W.printString("Name", Name); -} - -void CVTypeDumper::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 CVTypeDumper::visitMemberFuncId(TypeLeafKind Leaf, const MemberFuncId *Id, - ArrayRef LeafData) { - printTypeIndex("ClassType", Id->ClassType); - printTypeIndex("FunctionType", Id->FunctionType); - Name = getBytesAsCString(LeafData); - W.printString("Name", Name); -} - -void CVTypeDumper::visitProcedureType(TypeLeafKind Leaf, - const ProcedureType *Proc, - ArrayRef LeafData) { - printTypeIndex("ReturnType", Proc->ReturnType); - W.printEnum("CallingConvention", uint8_t(Proc->CallConv), - makeArrayRef(CallingConventions)); - W.printFlags("FunctionOptions", uint8_t(Proc->Options), - makeArrayRef(FunctionOptionEnum)); - W.printNumber("NumParameters", Proc->NumParameters); - printTypeIndex("ArgListType", Proc->ArgListType); - - StringRef ReturnTypeName = getTypeName(Proc->ReturnType); - StringRef ArgListTypeName = getTypeName(Proc->ArgListType); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ArgListTypeName); - Name = TypeNames.insert(TypeName).first->getKey(); -} - -void CVTypeDumper::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), - makeArrayRef(CallingConventions)); - W.printFlags("FunctionOptions", uint8_t(MemberFunc->Options), - makeArrayRef(FunctionOptionEnum)); - W.printNumber("NumParameters", MemberFunc->NumParameters); - printTypeIndex("ArgListType", MemberFunc->ArgListType); - W.printNumber("ThisAdjustment", MemberFunc->ThisAdjustment); - - StringRef ReturnTypeName = getTypeName(MemberFunc->ReturnType); - StringRef ClassTypeName = getTypeName(MemberFunc->ClassType); - StringRef ArgListTypeName = getTypeName(MemberFunc->ArgListType); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ClassTypeName); - TypeName.append("::"); - TypeName.append(ArgListTypeName); - Name = TypeNames.insert(TypeName).first->getKey(); -} - -void CVTypeDumper::visitMethodList(TypeLeafKind Leaf, - ArrayRef LeafData) { - while (!LeafData.empty()) { - const MethodListEntry *Method; - if (!consumeObject(LeafData, Method)) - return; - 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); - } - } -} - -void CVTypeDumper::visitFuncId(TypeLeafKind Leaf, const FuncId *Func, - ArrayRef LeafData) { - printTypeIndex("ParentScope", Func->ParentScope); - printTypeIndex("FunctionType", Func->FunctionType); - Name = getBytesAsCString(LeafData); - W.printString("Name", Name); -} - -void CVTypeDumper::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 CVTypeDumper::visitPointerType(TypeLeafKind Leaf, const PointerType *Ptr, - ArrayRef LeafData) { - printTypeIndex("PointeeType", Ptr->PointeeType); - W.printHex("PointerAttributes", Ptr->Attrs); - W.printEnum("PtrType", unsigned(Ptr->getPtrKind()), - 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, - makeArrayRef(PtrMemberRepNames)); - - StringRef PointeeName = getTypeName(Ptr->PointeeType); - StringRef ClassName = getTypeName(PMT->ClassType); - SmallString<256> TypeName(PointeeName); - TypeName.push_back(' '); - TypeName.append(ClassName); - TypeName.append("::*"); - Name = TypeNames.insert(TypeName).first->getKey(); - } else { - W.printBinaryBlock("TailData", getBytesAsCharacters(LeafData)); - - SmallString<256> TypeName; - if (Ptr->isConst()) - TypeName.append("const "); - if (Ptr->isVolatile()) - TypeName.append("volatile "); - if (Ptr->isUnaligned()) - TypeName.append("__unaligned "); - - TypeName.append(getTypeName(Ptr->PointeeType)); - - if (Ptr->getPtrMode() == PointerMode::LValueReference) - TypeName.append("&"); - else if (Ptr->getPtrMode() == PointerMode::RValueReference) - TypeName.append("&&"); - else if (Ptr->getPtrMode() == PointerMode::Pointer) - TypeName.append("*"); - - Name = TypeNames.insert(TypeName).first->getKey(); - } -} - -void CVTypeDumper::visitTypeModifier(TypeLeafKind Leaf, const TypeModifier *Mod, - ArrayRef LeafData) { - printTypeIndex("ModifiedType", Mod->ModifiedType); - W.printFlags("Modifiers", Mod->Modifiers, makeArrayRef(TypeModifierNames)); - - StringRef ModifiedName = getTypeName(Mod->ModifiedType); - SmallString<256> TypeName; - if (Mod->Modifiers & uint16_t(ModifierOptions::Const)) - TypeName.append("const "); - if (Mod->Modifiers & uint16_t(ModifierOptions::Volatile)) - TypeName.append("volatile "); - if (Mod->Modifiers & uint16_t(ModifierOptions::Unaligned)) - TypeName.append("__unaligned "); - TypeName.append(ModifiedName); - Name = TypeNames.insert(TypeName).first->getKey(); -} - -void CVTypeDumper::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 CVTypeDumper::visitUDTSrcLine(TypeLeafKind Leaf, const UDTSrcLine *Line, - ArrayRef LeafData) { - printTypeIndex("UDT", Line->UDT); - printTypeIndex("SourceFile", Line->SourceFile); - W.printNumber("LineNumber", Line->LineNumber); -} - -void CVTypeDumper::visitBuildInfo(TypeLeafKind Leaf, const BuildInfo *Args, - ArrayRef LeafData) { - W.printNumber("NumArgs", Args->NumArgs); - - ListScope Arguments(W, "Arguments"); - for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) { - const TypeIndex *Type; - if (!consumeObject(LeafData, Type)) - return; - printTypeIndex("ArgType", *Type); - } -} - -void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) { - W.printEnum("AccessSpecifier", uint8_t(Attrs.getAccess()), - 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()), - makeArrayRef(MethodOptionNames)); - } -} - -void CVTypeDumper::visitUnknownMember(TypeLeafKind Leaf) { - W.printHex("UnknownMember", unsigned(Leaf)); -} - -void CVTypeDumper::visitNestedType(TypeLeafKind Leaf, const NestedType *Nested, - ArrayRef &FieldData) { - DictScope S(W, "NestedType"); - printTypeIndex("Type", Nested->Type); - StringRef Name = getBytesAsCString(FieldData); - FieldData = FieldData.drop_front(Name.size() + 1); - W.printString("Name", Name); -} - -void CVTypeDumper::visitOneMethod(TypeLeafKind Leaf, const OneMethod *Method, - ArrayRef &FieldData) { - DictScope S(W, "OneMethod"); - printMemberAttributes(Method->Attrs); - printTypeIndex("Type", Method->Type); - // 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); -} - -void CVTypeDumper::visitOverloadedMethod(TypeLeafKind Leaf, - const OverloadedMethod *Method, - ArrayRef &FieldData) { - 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); -} - -void CVTypeDumper::visitDataMember(TypeLeafKind Leaf, const DataMember *Field, - ArrayRef &FieldData) { - DictScope S(W, "DataMember"); - printMemberAttributes(Field->Attrs); - printTypeIndex("Type", Field->Type); - uint64_t FieldOffset; - error(decodeUIntLeaf(FieldData, FieldOffset)); - W.printHex("FieldOffset", FieldOffset); - StringRef Name = getBytesAsCString(FieldData); - FieldData = FieldData.drop_front(Name.size() + 1); - W.printString("Name", Name); -} - -void CVTypeDumper::visitStaticDataMember(TypeLeafKind Leaf, - const StaticDataMember *Field, - ArrayRef &FieldData) { - 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); -} - -void CVTypeDumper::visitVirtualFunctionPointer( - TypeLeafKind Leaf, const VirtualFunctionPointer *VFTable, - ArrayRef &FieldData) { - DictScope S(W, "VirtualFunctionPointer"); - printTypeIndex("Type", VFTable->Type); -} - -void CVTypeDumper::visitEnumerator(TypeLeafKind Leaf, const Enumerator *Enum, - ArrayRef &FieldData) { - DictScope S(W, "Enumerator"); - printMemberAttributes(Enum->Attrs); - APSInt EnumValue; - error(decodeNumerictLeaf(FieldData, EnumValue)); - W.printNumber("EnumValue", EnumValue); - StringRef Name = getBytesAsCString(FieldData); - FieldData = FieldData.drop_front(Name.size() + 1); - W.printString("Name", Name); -} - -void CVTypeDumper::visitBaseClass(TypeLeafKind Leaf, const BaseClass *Base, - ArrayRef &FieldData) { - DictScope S(W, "BaseClass"); - printMemberAttributes(Base->Attrs); - printTypeIndex("BaseType", Base->BaseType); - uint64_t BaseOffset; - error(decodeUIntLeaf(FieldData, BaseOffset)); - W.printHex("BaseOffset", BaseOffset); -} - -void CVTypeDumper::visitVirtualBaseClass(TypeLeafKind Leaf, - const VirtualBaseClass *Base, - ArrayRef &FieldData) { - DictScope S(W, "VirtualBaseClass"); - printMemberAttributes(Base->Attrs); - printTypeIndex("BaseType", Base->BaseType); - printTypeIndex("VBPtrType", Base->VBPtrType); - uint64_t VBPtrOffset, VBTableIndex; - error(decodeUIntLeaf(FieldData, VBPtrOffset)); - error(decodeUIntLeaf(FieldData, VBTableIndex)); - W.printHex("VBPtrOffset", VBPtrOffset); - W.printHex("VBTableIndex", VBTableIndex); -} - void COFFDumper::printSections() { ListScope SectionsD(W, "Sections"); int SectionNumber = 0;