Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -16,6 +16,8 @@ #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/MSF/ByteStream.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" @@ -80,9 +82,10 @@ if (Data.empty()) return; - msf::ByteStream Stream(Data); - CVTypeDumper TypeDumper(&W, false); - if (auto EC = TypeDumper.dump(Data)) + TypeDatabase TDB; + TypeDumpVisitor TDV(TDB, &W, false); + CVTypeDumper TypeDumper(TDB); + if (auto EC = TypeDumper.dump(Data, TDV)) fatal(EC, "CVTypeDumper::dump failed"); } @@ -97,8 +100,8 @@ if (auto EC = Reader.readArray(Symbols, Reader.getLength())) fatal(EC, "StreamReader.readArray failed"); - CVTypeDumper TypeDumper(&W, false); - CVSymbolDumper SymbolDumper(W, TypeDumper, nullptr, false); + TypeDatabase TDB; + CVSymbolDumper SymbolDumper(W, TDB, nullptr, false); if (auto EC = SymbolDumper.dump(Symbols)) fatal(EC, "CVSymbolDumper::dump failed"); } Index: llvm/include/llvm/DebugInfo/CodeView/CVTypeDumper.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CVTypeDumper.h +++ llvm/include/llvm/DebugInfo/CodeView/CVTypeDumper.h @@ -16,69 +16,38 @@ #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/ScopedPrinter.h" namespace llvm { -class ScopedPrinter; namespace codeview { /// Dumper for CodeView type streams found in COFF object files and PDB files. -class CVTypeDumper : public TypeVisitorCallbacks { +class CVTypeDumper { public: - CVTypeDumper(ScopedPrinter *W, bool PrintRecordBytes) - : W(W), PrintRecordBytes(PrintRecordBytes) {} - - void printTypeIndex(StringRef FieldName, TypeIndex TI); + explicit CVTypeDumper(TypeDatabase &TypeDB) : TypeDB(TypeDB) {} /// Dumps one type record. Returns false if there was a type parsing error, /// and true otherwise. This should be called in order, since the dumper /// maintains state about previous records which are necessary for cross /// type references. - Error dump(const CVRecord &Record); + Error dump(const CVType &Record, TypeVisitorCallbacks &Dumper); /// Dumps the type records in Types. Returns false if there was a type stream /// parse error, and true otherwise. - Error dump(const CVTypeArray &Types); + Error dump(const CVTypeArray &Types, TypeVisitorCallbacks &Dumper); /// Dumps the type records in Data. Returns false if there was a type stream /// parse error, and true otherwise. Use this method instead of the /// CVTypeArray overload when type records are laid out contiguously in /// memory. - Error dump(ArrayRef Data); - - void setPrinter(ScopedPrinter *P); - ScopedPrinter *getPrinter() { return W; } - - /// Action to take on unknown types. By default, they are ignored. - Error visitUnknownType(CVType &Record) override; - Error visitUnknownMember(CVMemberRecord &Record) override; - - /// Paired begin/end actions for all types. Receives all record data, - /// including the fixed-length record prefix. - Error visitTypeBegin(CVType &Record) override; - Error visitTypeEnd(CVType &Record) override; - Error visitMemberBegin(CVMemberRecord &Record) override; - Error visitMemberEnd(CVMemberRecord &Record) override; + Error dump(ArrayRef Data, TypeVisitorCallbacks &Dumper); -#define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override; -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "TypeRecords.def" + static void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, + TypeIndex TI, TypeDatabase &DB); private: - void printMemberAttributes(MemberAttributes Attrs); - void printMemberAttributes(MemberAccess Access, MethodKind Kind, - MethodOptions Options); - - ScopedPrinter *W; - - bool IsInFieldList = false; - bool PrintRecordBytes = false; - - TypeDatabase TypeDB; + TypeDatabase &TypeDB; }; } // end namespace codeview Index: llvm/include/llvm/DebugInfo/CodeView/SymbolDumper.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolDumper.h +++ llvm/include/llvm/DebugInfo/CodeView/SymbolDumper.h @@ -20,15 +20,15 @@ class ScopedPrinter; namespace codeview { -class CVTypeDumper; +class TypeDatabase; /// Dumper for CodeView symbol streams found in COFF object files and PDB files. class CVSymbolDumper { public: - CVSymbolDumper(ScopedPrinter &W, CVTypeDumper &CVTD, + CVSymbolDumper(ScopedPrinter &W, TypeDatabase &TypeDB, std::unique_ptr ObjDelegate, bool PrintRecordBytes) - : W(W), CVTD(CVTD), ObjDelegate(std::move(ObjDelegate)), + : W(W), TypeDB(TypeDB), ObjDelegate(std::move(ObjDelegate)), PrintRecordBytes(PrintRecordBytes) {} /// Dumps one type record. Returns false if there was a type parsing error, @@ -43,7 +43,7 @@ private: ScopedPrinter &W; - CVTypeDumper &CVTD; + TypeDatabase &TypeDB; std::unique_ptr ObjDelegate; bool PrintRecordBytes; Index: llvm/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h @@ -0,0 +1,67 @@ +//===-- TypeDumpVisitor.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_TYPEDUMPVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPVISITOR_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" + +namespace llvm { +class ScopedPrinter; + +namespace codeview { + +/// Dumper for CodeView type streams found in COFF object files and PDB files. +class TypeDumpVisitor : public TypeVisitorCallbacks { +public: + TypeDumpVisitor(TypeDatabase &TypeDB, ScopedPrinter *W, bool PrintRecordBytes) + : W(W), PrintRecordBytes(PrintRecordBytes), TypeDB(TypeDB) {} + + void printTypeIndex(StringRef FieldName, TypeIndex TI) const; + + /// Action to take on unknown types. By default, they are ignored. + Error visitUnknownType(CVType &Record) override; + Error visitUnknownMember(CVMemberRecord &Record) override; + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + Error visitTypeBegin(CVType &Record) override; + Error visitTypeEnd(CVType &Record) override; + Error visitMemberBegin(CVMemberRecord &Record) override; + Error visitMemberEnd(CVMemberRecord &Record) override; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override; +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "TypeRecords.def" + +private: + void printMemberAttributes(MemberAttributes Attrs); + void printMemberAttributes(MemberAccess Access, MethodKind Kind, + MethodOptions Options); + + ScopedPrinter *W; + + bool PrintRecordBytes = false; + + TypeDatabase &TypeDB; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -19,6 +19,7 @@ #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -468,7 +469,8 @@ CommentPrefix += ' '; } - CVTypeDumper CVTD(nullptr, /*PrintRecordBytes=*/false); + TypeDatabase TypeDB; + CVTypeDumper CVTD(TypeDB); TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef Record) { if (OS.isVerboseAsm()) { // Emit a block comment describing the type record for readability. @@ -476,8 +478,8 @@ raw_svector_ostream CommentOS(CommentBlock); ScopedPrinter SP(CommentOS); SP.setPrefix(CommentPrefix); - CVTD.setPrinter(&SP); - Error E = CVTD.dump(Record); + TypeDumpVisitor TDV(TypeDB, &SP, false); + Error E = CVTD.dump(Record, TDV); if (E) { logAllUnhandledErrors(std::move(E), errs(), "error: "); llvm_unreachable("produced malformed type record"); Index: llvm/lib/DebugInfo/CodeView/CMakeLists.txt =================================================================== --- llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -13,6 +13,7 @@ SymbolDumper.cpp TypeDatabase.cpp TypeDatabaseVisitor.cpp + TypeDumpVisitor.cpp TypeRecord.cpp TypeRecordMapping.cpp TypeSerializer.cpp Index: llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp +++ llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp @@ -8,536 +8,24 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/CVTypeDumper.h" -#include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/ByteStream.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/TypeRecords.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 - -static StringRef getLeafTypeName(TypeLeafKind LT) { - switch (LT) { -#define TYPE_RECORD(ename, value, name) \ - case ename: \ - return #name; -#include "llvm/DebugInfo/CodeView/TypeRecords.def" - default: - break; - } - return "UnknownLeaf"; -} - -Error CVTypeDumper::visitTypeBegin(CVType &Record) { - W->startLine() << getLeafTypeName(Record.Type); - W->getOStream() << " (" << HexNumber(TypeDB.getNextTypeIndex().getIndex()) - << ")"; - W->getOStream() << " {\n"; - W->indent(); - W->printEnum("TypeLeafKind", unsigned(Record.Type), - makeArrayRef(LeafTypeNames)); - return Error::success(); -} - -Error CVTypeDumper::visitTypeEnd(CVType &Record) { - if (PrintRecordBytes) - W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content())); - - W->unindent(); - W->startLine() << "}\n"; - return Error::success(); -} - -Error CVTypeDumper::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 CVTypeDumper::visitMemberEnd(CVMemberRecord &Record) { - if (PrintRecordBytes) - W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data)); - - W->unindent(); - W->startLine() << "}\n"; - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVType &CVR, FieldListRecord &FieldList) { - CVTypeVisitor Visitor(*this); - if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data)) - return EC; - - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVType &CVR, StringIdRecord &String) { - printTypeIndex("Id", String.getId()); - W->printString("StringData", String.getString()); - return Error::success(); -} - -Error CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { - printTypeIndex("ClassType", Id.getClassType()); - printTypeIndex("FunctionType", Id.getFunctionType()); - W->printString("Name", Id.getName()); - return Error::success(); -} - -Error CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { - printTypeIndex("ParentScope", Func.getParentScope()); - printTypeIndex("FunctionType", Func.getFunctionType()); - W->printString("Name", Func.getName()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { - W->printBinary("Signature", TS.getGuid()); - W->printNumber("Age", TS.getAge()); - W->printString("Name", TS.getName()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVType &CVR, 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.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("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 CVTypeDumper::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 CVTypeDumper::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) { - printTypeIndex("Type", BitField.getType()); - W->printNumber("BitSize", BitField.getBitSize()); - W->printNumber("BitOffset", BitField.getBitOffset()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVType &CVR, VFTableShapeRecord &Shape) { - W->printNumber("VFEntryCount", Shape.getEntryCount()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVType &CVR, UdtSourceLineRecord &Line) { - printTypeIndex("UDT", Line.getUDT()); - printTypeIndex("SourceFile", Line.getSourceFile()); - W->printNumber("LineNumber", Line.getLineNumber()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVType &CVR, - UdtModSourceLineRecord &Line) { - printTypeIndex("UDT", Line.getUDT()); - printTypeIndex("SourceFile", Line.getSourceFile()); - W->printNumber("LineNumber", Line.getLineNumber()); - W->printNumber("Module", Line.getModule()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) { - W->printNumber("NumArgs", static_cast(Args.getArgs().size())); - - ListScope Arguments(*W, "Arguments"); - for (auto Arg : Args.getArgs()) { - printTypeIndex("ArgType", Arg); - } - return Error::success(); -} - -void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) { - return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(), - Attrs.getFlags()); -} - -void CVTypeDumper::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 CVTypeDumper::visitUnknownMember(CVMemberRecord &Record) { - W->printHex("UnknownMember", unsigned(Record.Kind)); - return Error::success(); -} - -Error CVTypeDumper::visitUnknownType(CVType &Record) { - W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames)); - W->printNumber("Length", uint32_t(Record.content().size())); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - NestedTypeRecord &Nested) { - printTypeIndex("Type", Nested.getNestedType()); - W->printString("Name", Nested.getName()); - return Error::success(); -} - -Error CVTypeDumper::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 CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - OverloadedMethodRecord &Method) { - W->printHex("MethodCount", Method.getNumOverloads()); - printTypeIndex("MethodListIndex", Method.getMethodList()); - W->printString("Name", Method.getName()); - return Error::success(); -} - -Error CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - VFPtrRecord &VFTable) { - printTypeIndex("Type", VFTable.getType()); - return Error::success(); -} - -Error CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::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 CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - ListContinuationRecord &Cont) { - printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); - return Error::success(); -} - -void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { - StringRef TypeName; - if (!TI.isNoneType()) - TypeName = TypeDB.getTypeName(TI); - if (!TypeName.empty()) - W->printHex(FieldName, TypeName, TI.getIndex()); - else - W->printHex(FieldName, TI.getIndex()); -} - -Error CVTypeDumper::dump(const CVType &Record) { - assert(W && "printer should not be null"); +Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) { TypeDatabaseVisitor DBV(TypeDB); TypeDeserializer Deserializer; TypeVisitorCallbackPipeline Pipeline; Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(DBV); - Pipeline.addCallbackToPipeline(*this); + Pipeline.addCallbackToPipeline(Dumper); CVTypeVisitor Visitor(Pipeline); @@ -547,14 +35,14 @@ return Error::success(); } -Error CVTypeDumper::dump(const CVTypeArray &Types) { - assert(W && "printer should not be null"); +Error CVTypeDumper::dump(const CVTypeArray &Types, + TypeVisitorCallbacks &Dumper) { TypeDatabaseVisitor DBV(TypeDB); TypeDeserializer Deserializer; TypeVisitorCallbackPipeline Pipeline; Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(DBV); - Pipeline.addCallbackToPipeline(*this); + Pipeline.addCallbackToPipeline(Dumper); CVTypeVisitor Visitor(Pipeline); @@ -563,17 +51,23 @@ return Error::success(); } -Error CVTypeDumper::dump(ArrayRef Data) { +Error CVTypeDumper::dump(ArrayRef Data, TypeVisitorCallbacks &Dumper) { msf::ByteStream Stream(Data); CVTypeArray Types; msf::StreamReader Reader(Stream); if (auto EC = Reader.readArray(Types, Reader.getLength())) return EC; - return dump(Types); + return dump(Types, Dumper); } -void CVTypeDumper::setPrinter(ScopedPrinter *P) { - static ScopedPrinter NullP(llvm::nulls()); - W = P ? P : &NullP; +void CVTypeDumper::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, + TypeIndex TI, TypeDatabase &DB) { + StringRef TypeName; + if (!TI.isNoneType()) + TypeName = DB.getTypeName(TI); + if (!TypeName.empty()) + Printer.printHex(FieldName, TypeName, TI.getIndex()); + else + Printer.printHex(FieldName, TI.getIndex()); } Index: llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -32,9 +32,9 @@ /// the visitor out of SymbolDumper.h. class CVSymbolDumperImpl : public SymbolVisitorCallbacks { public: - CVSymbolDumperImpl(CVTypeDumper &CVTD, SymbolDumpDelegate *ObjDelegate, + CVSymbolDumperImpl(TypeDatabase &TypeDB, SymbolDumpDelegate *ObjDelegate, ScopedPrinter &W, bool PrintRecordBytes) - : CVTD(CVTD), ObjDelegate(ObjDelegate), W(W), + : TypeDB(TypeDB), ObjDelegate(ObjDelegate), W(W), PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} /// CVSymbolVisitor overrides. @@ -51,8 +51,9 @@ void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, uint32_t RelocationOffset); void printLocalVariableAddrGap(ArrayRef Gaps); + void printTypeIndex(StringRef FieldName, TypeIndex TI); - CVTypeDumper &CVTD; + TypeDatabase &TypeDB; SymbolDumpDelegate *ObjDelegate; ScopedPrinter &W; @@ -80,6 +81,10 @@ } } +void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) { + CVTypeDumper::printTypeIndex(W, FieldName, TI, TypeDB); +} + Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) { return Error::success(); } @@ -163,7 +168,7 @@ DictScope S(W, "BPRelativeSym"); W.printNumber("Offset", BPRel.Offset); - CVTD.printTypeIndex("Type", BPRel.Type); + printTypeIndex("Type", BPRel.Type); W.printString("VarName", BPRel.Name); return Error::success(); } @@ -187,7 +192,7 @@ CallSiteInfo.CodeOffset, &LinkageName); } W.printHex("Segment", CallSiteInfo.Segment); - CVTD.printTypeIndex("Type", CallSiteInfo.Type); + printTypeIndex("Type", CallSiteInfo.Type); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); return Error::success(); @@ -278,7 +283,7 @@ ConstantSym &Constant) { DictScope S(W, "Constant"); - CVTD.printTypeIndex("Type", Constant.Type); + printTypeIndex("Type", Constant.Type); W.printNumber("Value", Constant.Value); W.printString("Name", Constant.Name); return Error::success(); @@ -293,7 +298,7 @@ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), Data.DataOffset, &LinkageName); } - CVTD.printTypeIndex("Type", Data.Type); + printTypeIndex("Type", Data.Type); W.printString("DisplayName", Data.Name); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); @@ -445,7 +450,7 @@ } W.printHex("Segment", HeapAllocSite.Segment); W.printHex("CallInstructionSize", HeapAllocSite.CallInstructionSize); - CVTD.printTypeIndex("Type", HeapAllocSite.Type); + printTypeIndex("Type", HeapAllocSite.Type); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); return Error::success(); @@ -457,7 +462,7 @@ W.printHex("PtrParent", InlineSite.Parent); W.printHex("PtrEnd", InlineSite.End); - CVTD.printTypeIndex("Inlinee", InlineSite.Inlinee); + printTypeIndex("Inlinee", InlineSite.Inlinee); ListScope BinaryAnnotations(W, "BinaryAnnotations"); for (auto &Annotation : InlineSite.annotations()) { @@ -555,7 +560,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { DictScope S(W, "Local"); - CVTD.printTypeIndex("Type", Local.Type); + printTypeIndex("Type", Local.Type); W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames()); W.printString("VarName", Local.Name); return Error::success(); @@ -586,7 +591,7 @@ W.printHex("CodeSize", Proc.CodeSize); W.printHex("DbgStart", Proc.DbgStart); W.printHex("DbgEnd", Proc.DbgEnd); - CVTD.printTypeIndex("FunctionType", Proc.FunctionType); + printTypeIndex("FunctionType", Proc.FunctionType); if (ObjDelegate) { ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(), Proc.CodeOffset, &LinkageName); @@ -616,7 +621,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers"); for (auto FuncID : Caller.Indices) - CVTD.printTypeIndex("FuncID", FuncID); + printTypeIndex("FuncID", FuncID); return Error::success(); } @@ -625,7 +630,7 @@ DictScope S(W, "RegRelativeSym"); W.printHex("Offset", RegRel.Offset); - CVTD.printTypeIndex("Type", RegRel.Type); + printTypeIndex("Type", RegRel.Type); W.printHex("Register", RegRel.Register); W.printString("VarName", RegRel.Name); return Error::success(); @@ -640,7 +645,7 @@ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), Data.DataOffset, &LinkageName); } - CVTD.printTypeIndex("Type", Data.Type); + printTypeIndex("Type", Data.Type); W.printString("DisplayName", Data.Name); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); @@ -649,7 +654,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) { DictScope S(W, "UDT"); - CVTD.printTypeIndex("Type", UDT.Type); + printTypeIndex("Type", UDT.Type); W.printString("UDTName", UDT.Name); return Error::success(); } @@ -664,7 +669,7 @@ Error CVSymbolDumper::dump(CVRecord &Record) { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(ObjDelegate.get()); - CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes); + CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); @@ -675,7 +680,7 @@ Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(ObjDelegate.get()); - CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes); + CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); Index: llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -0,0 +1,532 @@ +//===-- 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/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/MSF/ByteStream.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/TypeRecords.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 + +static StringRef getLeafTypeName(TypeLeafKind LT) { + switch (LT) { +#define TYPE_RECORD(ename, value, name) \ + case ename: \ + return #name; +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + default: + break; + } + return "UnknownLeaf"; +} + +void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const { + CVTypeDumper::printTypeIndex(*W, FieldName, TI, TypeDB); +} + +Error TypeDumpVisitor::visitTypeBegin(CVType &Record) { + W->startLine() << getLeafTypeName(Record.Type); + W->getOStream() << " (" << HexNumber(TypeDB.getNextTypeIndex().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) { + CVTypeVisitor Visitor(*this); + if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data)) + return EC; + + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) { + printTypeIndex("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, 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) { + printTypeIndex("ParentScope", Func.getParentScope()); + printTypeIndex("FunctionType", Func.getFunctionType()); + W->printString("Name", Func.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { + W->printBinary("Signature", TS.getGuid()); + 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->printHex("PointerAttributes", uint32_t(Ptr.getOptions())); + 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("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()); + printTypeIndex("SourceFile", Line.getSourceFile()); + W->printNumber("LineNumber", Line.getLineNumber()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &Line) { + printTypeIndex("UDT", Line.getUDT()); + printTypeIndex("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()) { + printTypeIndex("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(); +} Index: llvm/tools/llvm-pdbdump/LLVMOutputStyle.h =================================================================== --- llvm/tools/llvm-pdbdump/LLVMOutputStyle.h +++ llvm/tools/llvm-pdbdump/LLVMOutputStyle.h @@ -12,7 +12,7 @@ #include "OutputStyle.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/Support/ScopedPrinter.h" namespace llvm { @@ -49,7 +49,7 @@ PDBFile &File; ScopedPrinter P; - codeview::CVTypeDumper Dumper; + codeview::TypeDatabase TypeDB; std::vector StreamPurposes; }; } Index: llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -10,9 +10,15 @@ #include "LLVMOutputStyle.h" #include "llvm-pdbdump.h" +#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" #include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" @@ -83,8 +89,7 @@ OS << Off.Off << ", " << Off.Isect; } -LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) - : File(File), P(outs()), Dumper(&P, false) {} +LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) : File(File), P(outs()) {} Error LLVMOutputStyle::dump() { if (auto EC = dumpFileHeaders()) @@ -519,6 +524,7 @@ if (!Tpi) return Tpi.takeError(); + CVTypeDumper Dumper(TypeDB); if (DumpRecords || DumpRecordBytes) { DictScope D(P, Label); @@ -532,7 +538,8 @@ DictScope DD(P, ""); if (DumpRecords) { - if (auto EC = Dumper.dump(Type)) + TypeDumpVisitor TDV(TypeDB, &P, false); + if (auto EC = Dumper.dump(Type, TDV)) return EC; } @@ -545,19 +552,23 @@ "TPI stream contained corrupt record"); } else if (opts::raw::DumpModuleSyms) { // Even if the user doesn't want to dump type records, we still need to - // iterate them in order to build the list of types so that we can print - // them when dumping module symbols. So when they want to dump symbols - // but not types, use a null output stream. - ScopedPrinter *OldP = Dumper.getPrinter(); - Dumper.setPrinter(nullptr); + // iterate them in order to build the type database. So when they want to + // dump symbols but not types, don't stick a dumper on the end, just build + // the type database. + TypeDatabaseVisitor DBV(TypeDB); + TypeDeserializer Deserializer; + TypeVisitorCallbackPipeline Pipeline; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(DBV); + + CVTypeVisitor Visitor(Pipeline); bool HadError = false; - for (auto &Type : Tpi->types(&HadError)) { - if (auto EC = Dumper.dump(Type)) + for (auto Type : Tpi->types(&HadError)) { + if (auto EC = Visitor.visitTypeRecord(Type)) return EC; } - Dumper.setPrinter(OldP); dumpTpiHash(P, *Tpi); if (HadError) return make_error(raw_error_code::corrupt_file, @@ -640,7 +651,7 @@ if (ShouldDumpSymbols) { ListScope SS(P, "Symbols"); - codeview::CVSymbolDumper SD(P, Dumper, nullptr, false); + codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false); bool HadError = false; for (auto S : ModS.symbols(&HadError)) { DictScope LL(P, ""); @@ -865,7 +876,7 @@ P.printList("Section Offsets", Publics->getSectionOffsets(), printSectionOffset); ListScope L(P, "Symbols"); - codeview::CVSymbolDumper SD(P, Dumper, nullptr, false); + codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false); bool HadError = false; for (auto S : Publics->getSymbols(&HadError)) { DictScope DD(P, ""); Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/tools/llvm-readobj/COFFDumper.cpp @@ -30,6 +30,7 @@ #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" @@ -64,8 +65,7 @@ public: friend class COFFObjectDumpDelegate; COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer) - : ObjDumper(Writer), Obj(Obj), - CVTD(&Writer, opts::CodeViewSubsectionBytes) {} + : ObjDumper(Writer), Writer(Writer), Obj(Obj) {} void printFileHeaders() override; void printSections() override; @@ -99,7 +99,7 @@ void printFileNameForOffset(StringRef Label, uint32_t FileOffset); void printTypeIndex(StringRef FieldName, TypeIndex TI) { // Forward to CVTypeDumper for simplicity. - CVTD.printTypeIndex(FieldName, TI); + CVTypeDumper::printTypeIndex(Writer, FieldName, TI, TypeDB); } void printCodeViewSymbolsSubsection(StringRef Subsection, @@ -142,7 +142,8 @@ StringRef CVFileChecksumTable; StringRef CVStringTable; - CVTypeDumper CVTD; + ScopedPrinter &Writer; + TypeDatabase TypeDB; }; class COFFObjectDumpDelegate : public SymbolDumpDelegate { @@ -962,7 +963,8 @@ auto CODD = llvm::make_unique(*this, Section, Obj, SectionContents); - CVSymbolDumper CVSD(W, CVTD, std::move(CODD), opts::CodeViewSubsectionBytes); + CVSymbolDumper CVSD(W, TypeDB, std::move(CODD), + opts::CodeViewSubsectionBytes); ByteStream Stream(BinaryData); CVSymbolArray Symbols; StreamReader Reader(Stream); @@ -1106,7 +1108,9 @@ if (Magic != COFF::DEBUG_SECTION_MAGIC) return error(object_error::parse_failed); - if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()})) { + CVTypeDumper CVTD(TypeDB); + TypeDumpVisitor TDV(TypeDB, &W, opts::CodeViewSubsectionBytes); + if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()}, TDV)) { W.flush(); error(llvm::errorToErrorCode(std::move(EC))); } @@ -1552,8 +1556,12 @@ CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef Record) { Buf.append(Record.begin(), Record.end()); }); - CVTypeDumper CVTD(&Writer, opts::CodeViewSubsectionBytes); - if (auto EC = CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()})) { + + TypeDatabase TypeDB; + CVTypeDumper CVTD(TypeDB); + TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes); + if (auto EC = + CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()}, TDV)) { Writer.flush(); error(llvm::errorToErrorCode(std::move(EC))); }