//===-- TypeDumpVisitor.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/TypeDumpVisitor.h" #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/Formatters.h" #include "llvm/DebugInfo/CodeView/TypeCollection.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ScopedPrinter.h" using namespace llvm; using namespace llvm::codeview; static const EnumEntry LeafTypeNames[] = { #define CV_TYPE(enum, val) {#enum, enum}, #include "llvm/DebugInfo/CodeView/CodeViewTypes.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), }; static const EnumEntry LabelTypeEnum[] = { ENUM_ENTRY(LabelType, Near), ENUM_ENTRY(LabelType, Far), }; #undef ENUM_ENTRY static StringRef getLeafTypeName(TypeLeafKind LT) { switch (LT) { #define TYPE_RECORD(ename, value, name) \ case ename: \ return #name; #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" default: break; } return "UnknownLeaf"; } void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const { codeview::printTypeIndex(*W, FieldName, TI, TpiTypes); } void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const { codeview::printTypeIndex(*W, FieldName, TI, getSourceTypes()); } Error TypeDumpVisitor::visitTypeBegin(CVType &Record) { return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size())); } Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) { W->startLine() << getLeafTypeName(Record.Type); W->getOStream() << " (" << HexNumber(Index.getIndex()) << ")"; W->getOStream() << " {\n"; W->indent(); W->printEnum("TypeLeafKind", unsigned(Record.Type), makeArrayRef(LeafTypeNames)); return Error::success(); } Error TypeDumpVisitor::visitTypeEnd(CVType &Record) { if (PrintRecordBytes) W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content())); W->unindent(); W->startLine() << "}\n"; return Error::success(); } Error TypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) { W->startLine() << getLeafTypeName(Record.Kind); W->getOStream() << " {\n"; W->indent(); W->printEnum("TypeLeafKind", unsigned(Record.Kind), makeArrayRef(LeafTypeNames)); return Error::success(); } Error TypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) { if (PrintRecordBytes) W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data)); W->unindent(); W->startLine() << "}\n"; return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FieldListRecord &FieldList) { if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this)) return EC; return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) { printItemIndex("Id", String.getId()); W->printString("StringData", String.getString()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { auto Indices = Args.getIndices(); uint32_t Size = Indices.size(); W->printNumber("NumArgs", Size); ListScope Arguments(*W, "Arguments"); for (uint32_t I = 0; I < Size; ++I) { printTypeIndex("ArgType", Indices[I]); } return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringListRecord &Strs) { auto Indices = Strs.getIndices(); uint32_t Size = Indices.size(); W->printNumber("NumStrings", Size); ListScope Arguments(*W, "Strings"); for (uint32_t I = 0; I < Size; ++I) { printItemIndex("String", Indices[I]); } return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) { uint16_t Props = static_cast(Class.getOptions()); W->printNumber("MemberCount", Class.getMemberCount()); W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); 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()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) { uint16_t Props = static_cast(Union.getOptions()); W->printNumber("MemberCount", Union.getMemberCount()); W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); 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()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { uint16_t Props = static_cast(Enum.getOptions()); W->printNumber("NumEnumerators", Enum.getMemberCount()); W->printFlags("Properties", uint16_t(Enum.getOptions()), makeArrayRef(ClassOptionNames)); printTypeIndex("UnderlyingType", Enum.getUnderlyingType()); printTypeIndex("FieldListType", Enum.getFieldList()); W->printString("Name", Enum.getName()); if (Props & uint16_t(ClassOptions::HasUniqueName)) W->printString("LinkageName", Enum.getUniqueName()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { printTypeIndex("ElementType", AT.getElementType()); printTypeIndex("IndexType", AT.getIndexType()); W->printNumber("SizeOf", AT.getSize()); W->printString("Name", AT.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &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); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { printTypeIndex("ClassType", Id.getClassType()); printTypeIndex("FunctionType", Id.getFunctionType()); W->printString("Name", Id.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { printTypeIndex("ReturnType", Proc.getReturnType()); W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()), makeArrayRef(CallingConventions)); W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()), makeArrayRef(FunctionOptionEnum)); W->printNumber("NumParameters", Proc.getParameterCount()); printTypeIndex("ArgListType", Proc.getArgumentList()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, 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(MF.getOptions()), makeArrayRef(FunctionOptionEnum)); W->printNumber("NumParameters", MF.getParameterCount()); printTypeIndex("ArgListType", MF.getArgumentList()); W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MethodOverloadListRecord &MethodList) { for (auto &M : MethodList.getMethods()) { ListScope S(*W, "Method"); printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions()); printTypeIndex("Type", M.getType()); if (M.isIntroducingVirtual()) W->printHex("VFTableOffset", M.getVFTableOffset()); } return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { printItemIndex("ParentScope", Func.getParentScope()); printTypeIndex("FunctionType", Func.getFunctionType()); W->printString("Name", Func.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { W->printString("Guid", formatv("{0}", TS.getGuid()).str()); W->printNumber("Age", TS.getAge()); W->printString("Name", TS.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { printTypeIndex("PointeeType", Ptr.getReferentType()); W->printEnum("PtrType", unsigned(Ptr.getPointerKind()), makeArrayRef(PtrKindNames)); 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()); W->printNumber("IsRestrict", Ptr.isRestrict()); W->printNumber("IsThisPtr&", Ptr.isLValueReferenceThisPtr()); W->printNumber("IsThisPtr&&", Ptr.isRValueReferenceThisPtr()); W->printNumber("SizeOf", Ptr.getSize()); if (Ptr.isPointerToMember()) { const MemberPointerInfo &MI = Ptr.getMemberInfo(); printTypeIndex("ClassType", MI.getContainingType()); W->printEnum("Representation", uint16_t(MI.getRepresentation()), makeArrayRef(PtrMemberRepNames)); } return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { uint16_t Mods = static_cast(Mod.getModifiers()); printTypeIndex("ModifiedType", Mod.getModifiedType()); W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames)); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) { printTypeIndex("Type", BitField.getType()); W->printNumber("BitSize", BitField.getBitSize()); W->printNumber("BitOffset", BitField.getBitOffset()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, VFTableShapeRecord &Shape) { W->printNumber("VFEntryCount", Shape.getEntryCount()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UdtSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printItemIndex("SourceFile", Line.getSourceFile()); W->printNumber("LineNumber", Line.getLineNumber()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UdtModSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printItemIndex("SourceFile", Line.getSourceFile()); W->printNumber("LineNumber", Line.getLineNumber()); W->printNumber("Module", Line.getModule()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) { W->printNumber("NumArgs", static_cast(Args.getArgs().size())); ListScope Arguments(*W, "Arguments"); for (auto Arg : Args.getArgs()) { printItemIndex("ArgType", Arg); } return Error::success(); } void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) { return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(), Attrs.getFlags()); } void TypeDumpVisitor::printMemberAttributes(MemberAccess Access, MethodKind Kind, MethodOptions Options) { W->printEnum("AccessSpecifier", uint8_t(Access), makeArrayRef(MemberAccessNames)); // Data members will be vanilla. Don't try to print a method kind for them. if (Kind != MethodKind::Vanilla) W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames)); if (Options != MethodOptions::None) { W->printFlags("MethodOptions", unsigned(Options), makeArrayRef(MethodOptionNames)); } } Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) { W->printHex("UnknownMember", unsigned(Record.Kind)); return Error::success(); } Error TypeDumpVisitor::visitUnknownType(CVType &Record) { W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames)); W->printNumber("Length", uint32_t(Record.content().size())); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, NestedTypeRecord &Nested) { printTypeIndex("Type", Nested.getNestedType()); W->printString("Name", Nested.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, OneMethodRecord &Method) { MethodKind K = Method.getMethodKind(); printMemberAttributes(Method.getAccess(), K, Method.getOptions()); printTypeIndex("Type", Method.getType()); // If virtual, then read the vftable offset. if (Method.isIntroducingVirtual()) W->printHex("VFTableOffset", Method.getVFTableOffset()); W->printString("Name", Method.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, OverloadedMethodRecord &Method) { W->printHex("MethodCount", Method.getNumOverloads()); printTypeIndex("MethodListIndex", Method.getMethodList()); W->printString("Name", Method.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, DataMemberRecord &Field) { printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("Type", Field.getType()); W->printHex("FieldOffset", Field.getFieldOffset()); W->printString("Name", Field.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, StaticDataMemberRecord &Field) { printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("Type", Field.getType()); W->printString("Name", Field.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, VFPtrRecord &VFTable) { printTypeIndex("Type", VFTable.getType()); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, EnumeratorRecord &Enum) { printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, MethodOptions::None); W->printNumber("EnumValue", Enum.getValue()); W->printString("Name", Enum.getName()); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, BaseClassRecord &Base) { printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("BaseType", Base.getBaseType()); W->printHex("BaseOffset", Base.getBaseOffset()); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, VirtualBaseClassRecord &Base) { 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()); return Error::success(); } Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, ListContinuationRecord &Cont) { printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &LR) { W->printEnum("Mode", uint16_t(LR.Mode), makeArrayRef(LabelTypeEnum)); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PrecompRecord &Precomp) { W->printHex("StartIndex", Precomp.getStartTypeIndex()); W->printHex("Count", Precomp.getTypesCount()); W->printHex("Signature", Precomp.getSignature()); W->printString("PrecompFile", Precomp.getPrecompFilePath()); return Error::success(); } Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, EndPrecompRecord &EndPrecomp) { W->printHex("Signature", EndPrecomp.getSignature()); return Error::success(); }