diff options
author | Zachary Turner <zturner@google.com> | 2016-08-18 16:49:29 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2016-08-18 16:49:29 +0000 |
commit | ac5763eca45d20466eb180928ec5afe231c11d4e (patch) | |
tree | d8e836c16af8b15a167ec7bab10e42bd4e615aa3 /llvm/tools | |
parent | c6bf547564088ad0ba0b2f281ffa813974f66bda (diff) | |
download | bcm5719-llvm-ac5763eca45d20466eb180928ec5afe231c11d4e.tar.gz bcm5719-llvm-ac5763eca45d20466eb180928ec5afe231c11d4e.zip |
Resubmit "Write the TPI stream from a PDB to Yaml."
The original patch was breaking some buildbots due to an
incorrect ordering of function definitions which caused some
compilers to recognize a definition but others to not.
llvm-svn: 279089
Diffstat (limited to 'llvm/tools')
-rw-r--r-- | llvm/tools/llvm-pdbdump/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/CodeViewYaml.cpp | 506 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/CodeViewYaml.h | 71 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/PdbYaml.cpp | 48 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/PdbYaml.h | 25 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp | 28 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/YAMLOutputStyle.h | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp | 7 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/llvm-pdbdump.h | 1 |
9 files changed, 678 insertions, 10 deletions
diff --git a/llvm/tools/llvm-pdbdump/CMakeLists.txt b/llvm/tools/llvm-pdbdump/CMakeLists.txt index 56324e83a63..701fcda4194 100644 --- a/llvm/tools/llvm-pdbdump/CMakeLists.txt +++ b/llvm/tools/llvm-pdbdump/CMakeLists.txt @@ -10,6 +10,7 @@ add_llvm_tool(llvm-pdbdump llvm-pdbdump.cpp BuiltinDumper.cpp ClassDefinitionDumper.cpp + CodeViewYaml.cpp CompilandDumper.cpp EnumDumper.cpp ExternalSymbolDumper.cpp diff --git a/llvm/tools/llvm-pdbdump/CodeViewYaml.cpp b/llvm/tools/llvm-pdbdump/CodeViewYaml.cpp new file mode 100644 index 00000000000..690e46fb041 --- /dev/null +++ b/llvm/tools/llvm-pdbdump/CodeViewYaml.cpp @@ -0,0 +1,506 @@ +//===- PdbYAML.cpp -------------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CodeViewYaml.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/EnumTables.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::codeview::yaml; + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(TypeIndex) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint64_t) +LLVM_YAML_IS_SEQUENCE_VECTOR(OneMethodRecord) +LLVM_YAML_IS_SEQUENCE_VECTOR(VFTableSlotKind) +LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef) +LLVM_YAML_IS_SEQUENCE_VECTOR(CVType) + +namespace llvm { +namespace yaml { +template <> struct ScalarEnumerationTraits<PointerToMemberRepresentation> { + static void enumeration(IO &IO, PointerToMemberRepresentation &Value) { + IO.enumCase(Value, "Unknown", PointerToMemberRepresentation::Unknown); + IO.enumCase(Value, "SingleInheritanceData", + PointerToMemberRepresentation::SingleInheritanceData); + IO.enumCase(Value, "MultipleInheritanceData", + PointerToMemberRepresentation::MultipleInheritanceData); + IO.enumCase(Value, "VirtualInheritanceData", + PointerToMemberRepresentation::VirtualInheritanceData); + IO.enumCase(Value, "GeneralData", + PointerToMemberRepresentation::GeneralData); + IO.enumCase(Value, "SingleInheritanceFunction", + PointerToMemberRepresentation::SingleInheritanceFunction); + IO.enumCase(Value, "MultipleInheritanceFunction", + PointerToMemberRepresentation::MultipleInheritanceFunction); + IO.enumCase(Value, "VirtualInheritanceFunction", + PointerToMemberRepresentation::VirtualInheritanceFunction); + IO.enumCase(Value, "GeneralFunction", + PointerToMemberRepresentation::GeneralFunction); + } +}; + +template <> struct ScalarEnumerationTraits<VFTableSlotKind> { + static void enumeration(IO &IO, VFTableSlotKind &Kind) { + IO.enumCase(Kind, "Near16", VFTableSlotKind::Near16); + IO.enumCase(Kind, "Far16", VFTableSlotKind::Far16); + IO.enumCase(Kind, "This", VFTableSlotKind::This); + IO.enumCase(Kind, "Outer", VFTableSlotKind::Outer); + IO.enumCase(Kind, "Meta", VFTableSlotKind::Meta); + IO.enumCase(Kind, "Near", VFTableSlotKind::Near); + IO.enumCase(Kind, "Far", VFTableSlotKind::Far); + } +}; + +template <> struct ScalarEnumerationTraits<CallingConvention> { + static void enumeration(IO &IO, CallingConvention &Value) { + IO.enumCase(Value, "NearC", CallingConvention::NearC); + IO.enumCase(Value, "FarC", CallingConvention::FarC); + IO.enumCase(Value, "NearPascal", CallingConvention::NearPascal); + IO.enumCase(Value, "FarPascal", CallingConvention::FarPascal); + IO.enumCase(Value, "NearFast", CallingConvention::NearFast); + IO.enumCase(Value, "FarFast", CallingConvention::FarFast); + IO.enumCase(Value, "NearStdCall", CallingConvention::NearStdCall); + IO.enumCase(Value, "FarStdCall", CallingConvention::FarStdCall); + IO.enumCase(Value, "NearSysCall", CallingConvention::NearSysCall); + IO.enumCase(Value, "FarSysCall", CallingConvention::FarSysCall); + IO.enumCase(Value, "ThisCall", CallingConvention::ThisCall); + IO.enumCase(Value, "MipsCall", CallingConvention::MipsCall); + IO.enumCase(Value, "Generic", CallingConvention::Generic); + IO.enumCase(Value, "AlphaCall", CallingConvention::AlphaCall); + IO.enumCase(Value, "PpcCall", CallingConvention::PpcCall); + IO.enumCase(Value, "SHCall", CallingConvention::SHCall); + IO.enumCase(Value, "ArmCall", CallingConvention::ArmCall); + IO.enumCase(Value, "AM33Call", CallingConvention::AM33Call); + IO.enumCase(Value, "TriCall", CallingConvention::TriCall); + IO.enumCase(Value, "SH5Call", CallingConvention::SH5Call); + IO.enumCase(Value, "M32RCall", CallingConvention::M32RCall); + IO.enumCase(Value, "ClrCall", CallingConvention::ClrCall); + IO.enumCase(Value, "Inline", CallingConvention::Inline); + IO.enumCase(Value, "NearVector", CallingConvention::NearVector); + } +}; + +template <> struct ScalarEnumerationTraits<PointerKind> { + static void enumeration(IO &IO, PointerKind &Kind) { + IO.enumCase(Kind, "Near16", PointerKind::Near16); + IO.enumCase(Kind, "Far16", PointerKind::Far16); + IO.enumCase(Kind, "Huge16", PointerKind::Huge16); + IO.enumCase(Kind, "BasedOnSegment", PointerKind::BasedOnSegment); + IO.enumCase(Kind, "BasedOnValue", PointerKind::BasedOnValue); + IO.enumCase(Kind, "BasedOnSegmentValue", PointerKind::BasedOnSegmentValue); + IO.enumCase(Kind, "BasedOnAddress", PointerKind::BasedOnAddress); + IO.enumCase(Kind, "BasedOnSegmentAddress", + PointerKind::BasedOnSegmentAddress); + IO.enumCase(Kind, "BasedOnType", PointerKind::BasedOnType); + IO.enumCase(Kind, "BasedOnSelf", PointerKind::BasedOnSelf); + IO.enumCase(Kind, "Near32", PointerKind::Near32); + IO.enumCase(Kind, "Far32", PointerKind::Far32); + IO.enumCase(Kind, "Near64", PointerKind::Near64); + } +}; + +template <> struct ScalarEnumerationTraits<PointerMode> { + static void enumeration(IO &IO, PointerMode &Mode) { + IO.enumCase(Mode, "Pointer", PointerMode::Pointer); + IO.enumCase(Mode, "LValueReference", PointerMode::LValueReference); + IO.enumCase(Mode, "PointerToDataMember", PointerMode::PointerToDataMember); + IO.enumCase(Mode, "PointerToMemberFunction", + PointerMode::PointerToMemberFunction); + IO.enumCase(Mode, "RValueReference", PointerMode::RValueReference); + } +}; + +template <> struct ScalarEnumerationTraits<HfaKind> { + static void enumeration(IO &IO, HfaKind &Value) { + IO.enumCase(Value, "None", HfaKind::None); + IO.enumCase(Value, "Float", HfaKind::Float); + IO.enumCase(Value, "Double", HfaKind::Double); + IO.enumCase(Value, "Other", HfaKind::Other); + } +}; + +template <> struct ScalarEnumerationTraits<MemberAccess> { + static void enumeration(IO &IO, MemberAccess &Access) { + IO.enumCase(Access, "None", MemberAccess::None); + IO.enumCase(Access, "Private", MemberAccess::Private); + IO.enumCase(Access, "Protected", MemberAccess::Protected); + IO.enumCase(Access, "Public", MemberAccess::Public); + } +}; + +template <> struct ScalarEnumerationTraits<MethodKind> { + static void enumeration(IO &IO, MethodKind &Kind) { + IO.enumCase(Kind, "Vanilla", MethodKind::Vanilla); + IO.enumCase(Kind, "Virtual", MethodKind::Virtual); + IO.enumCase(Kind, "Static", MethodKind::Static); + IO.enumCase(Kind, "Friend", MethodKind::Friend); + IO.enumCase(Kind, "IntroducingVirtual", MethodKind::IntroducingVirtual); + IO.enumCase(Kind, "PureVirtual", MethodKind::PureVirtual); + IO.enumCase(Kind, "PureIntroducingVirtual", + MethodKind::PureIntroducingVirtual); + } +}; + +template <> struct ScalarEnumerationTraits<WindowsRTClassKind> { + static void enumeration(IO &IO, WindowsRTClassKind &Value) { + IO.enumCase(Value, "None", WindowsRTClassKind::None); + IO.enumCase(Value, "Ref", WindowsRTClassKind::RefClass); + IO.enumCase(Value, "Value", WindowsRTClassKind::ValueClass); + IO.enumCase(Value, "Interface", WindowsRTClassKind::Interface); + } +}; + +template <> struct ScalarBitSetTraits<PointerOptions> { + static void bitset(IO &IO, PointerOptions &Options) { + IO.bitSetCase(Options, "None", PointerOptions::None); + IO.bitSetCase(Options, "Flat32", PointerOptions::Flat32); + IO.bitSetCase(Options, "Volatile", PointerOptions::Volatile); + IO.bitSetCase(Options, "Const", PointerOptions::Const); + IO.bitSetCase(Options, "Unaligned", PointerOptions::Unaligned); + IO.bitSetCase(Options, "Restrict", PointerOptions::Restrict); + IO.bitSetCase(Options, "WinRTSmartPointer", + PointerOptions::WinRTSmartPointer); + } +}; + +template <> struct ScalarBitSetTraits<ModifierOptions> { + static void bitset(IO &IO, ModifierOptions &Options) { + IO.bitSetCase(Options, "None", ModifierOptions::None); + IO.bitSetCase(Options, "Const", ModifierOptions::Const); + IO.bitSetCase(Options, "Volatile", ModifierOptions::Volatile); + IO.bitSetCase(Options, "Unaligned", ModifierOptions::Unaligned); + } +}; + +template <> struct ScalarBitSetTraits<FunctionOptions> { + static void bitset(IO &IO, FunctionOptions &Options) { + IO.bitSetCase(Options, "None", FunctionOptions::None); + IO.bitSetCase(Options, "CxxReturnUdt", FunctionOptions::CxxReturnUdt); + IO.bitSetCase(Options, "Constructor", FunctionOptions::Constructor); + IO.bitSetCase(Options, "ConstructorWithVirtualBases", + FunctionOptions::ConstructorWithVirtualBases); + } +}; + +template <> struct ScalarBitSetTraits<ClassOptions> { + static void bitset(IO &IO, ClassOptions &Options) { + IO.bitSetCase(Options, "None", ClassOptions::None); + IO.bitSetCase(Options, "HasConstructorOrDestructor", + ClassOptions::HasConstructorOrDestructor); + IO.bitSetCase(Options, "HasOverloadedOperator", + ClassOptions::HasOverloadedOperator); + IO.bitSetCase(Options, "Nested", ClassOptions::Nested); + IO.bitSetCase(Options, "ContainsNestedClass", + ClassOptions::ContainsNestedClass); + IO.bitSetCase(Options, "HasOverloadedAssignmentOperator", + ClassOptions::HasOverloadedAssignmentOperator); + IO.bitSetCase(Options, "HasConversionOperator", + ClassOptions::HasConversionOperator); + IO.bitSetCase(Options, "ForwardReference", ClassOptions::ForwardReference); + IO.bitSetCase(Options, "Scoped", ClassOptions::Scoped); + IO.bitSetCase(Options, "HasUniqueName", ClassOptions::HasUniqueName); + IO.bitSetCase(Options, "Sealed", ClassOptions::Sealed); + IO.bitSetCase(Options, "Intrinsic", ClassOptions::Intrinsic); + } +}; + +template <> struct ScalarBitSetTraits<MethodOptions> { + static void bitset(IO &IO, MethodOptions &Options) { + IO.bitSetCase(Options, "None", MethodOptions::None); + IO.bitSetCase(Options, "Pseudo", MethodOptions::Pseudo); + IO.bitSetCase(Options, "NoInherit", MethodOptions::NoInherit); + IO.bitSetCase(Options, "NoConstruct", MethodOptions::NoConstruct); + IO.bitSetCase(Options, "CompilerGenerated", + MethodOptions::CompilerGenerated); + IO.bitSetCase(Options, "Sealed", MethodOptions::Sealed); + } +}; + +template <> struct ScalarTraits<APSInt> { + static void output(const APSInt &S, void *, llvm::raw_ostream &OS) { + S.print(OS, true); + } + static StringRef input(StringRef Scalar, void *Ctx, APSInt &S) { + S = APSInt(Scalar); + return ""; + } + + static bool mustQuote(StringRef Scalar) { return false; } +}; + +void MappingTraits<CVType>::mapping(IO &IO, CVType &Record) { + if (IO.outputting()) { + codeview::yaml::YamlTypeDumperCallbacks Callbacks(IO); + codeview::TypeDeserializer Deserializer(Callbacks); + + codeview::CVTypeVisitor Visitor(Deserializer); + consumeError(Visitor.visitTypeRecord(Record)); + } +} + +void MappingTraits<FieldListRecord>::mapping(IO &IO, + FieldListRecord &FieldList) { + if (IO.outputting()) { + codeview::yaml::YamlTypeDumperCallbacks Callbacks(IO); + codeview::TypeDeserializer Deserializer(Callbacks); + codeview::CVTypeVisitor Visitor(Deserializer); + consumeError(Visitor.visitFieldListMemberStream(FieldList.Data)); + } +} + +void MappingTraits<StringIdRecord>::mapping(IO &IO, StringIdRecord &String) { + IO.mapRequired("Id", String.Id); + IO.mapRequired("String", String.String); +} + +void MappingTraits<ArgListRecord>::mapping(IO &IO, ArgListRecord &Args) { + IO.mapRequired("ArgIndices", Args.StringIndices); +} + +void MappingTraits<ClassRecord>::mapping(IO &IO, ClassRecord &Class) { + IO.mapRequired("MemberCount", Class.MemberCount); + IO.mapRequired("Options", Class.Options); + IO.mapRequired("FieldList", Class.FieldList); + IO.mapRequired("Name", Class.Name); + IO.mapRequired("UniqueName", Class.UniqueName); + IO.mapRequired("Hfa", Class.Hfa); + IO.mapRequired("WinRTKind", Class.WinRTKind); + IO.mapRequired("DerivationList", Class.DerivationList); + IO.mapRequired("VTableShape", Class.VTableShape); + IO.mapRequired("Size", Class.Size); +} + +void MappingTraits<UnionRecord>::mapping(IO &IO, UnionRecord &Union) { + IO.mapRequired("MemberCount", Union.MemberCount); + IO.mapRequired("Options", Union.Options); + IO.mapRequired("FieldList", Union.FieldList); + IO.mapRequired("Name", Union.Name); + IO.mapRequired("UniqueName", Union.UniqueName); + IO.mapRequired("Hfa", Union.Hfa); + IO.mapRequired("Size", Union.Size); +} + +void MappingTraits<EnumRecord>::mapping(IO &IO, EnumRecord &Enum) { + IO.mapRequired("NumEnumerators", Enum.MemberCount); + IO.mapRequired("Options", Enum.Options); + IO.mapRequired("FieldList", Enum.FieldList); + IO.mapRequired("Name", Enum.Name); + IO.mapRequired("UniqueName", Enum.UniqueName); + IO.mapRequired("UnderlyingType", Enum.UnderlyingType); +} + +void MappingTraits<ArrayRecord>::mapping(IO &IO, ArrayRecord &AT) { + IO.mapRequired("ElementType", AT.ElementType); + IO.mapRequired("IndexType", AT.IndexType); + IO.mapRequired("Size", AT.Size); + IO.mapRequired("Name", AT.Name); +} + +void MappingTraits<VFTableRecord>::mapping(IO &IO, VFTableRecord &VFT) { + IO.mapRequired("CompleteClass", VFT.CompleteClass); + IO.mapRequired("OverriddenVFTable", VFT.OverriddenVFTable); + IO.mapRequired("VFPtrOffset", VFT.VFPtrOffset); + IO.mapRequired("Name", VFT.Name); + IO.mapRequired("MethodNames", VFT.MethodNames); +} + +void MappingTraits<MemberFuncIdRecord>::mapping(IO &IO, + MemberFuncIdRecord &Id) { + IO.mapRequired("ClassType", Id.ClassType); + IO.mapRequired("FunctionType", Id.FunctionType); + IO.mapRequired("Name", Id.Name); +} + +void MappingTraits<ProcedureRecord>::mapping(IO &IO, ProcedureRecord &Proc) { + IO.mapRequired("ReturnType", Proc.ReturnType); + IO.mapRequired("CallConv", Proc.CallConv); + IO.mapRequired("Options", Proc.Options); + IO.mapRequired("ParameterCount", Proc.ParameterCount); + IO.mapRequired("ArgumentList", Proc.ArgumentList); +} + +void MappingTraits<MemberFunctionRecord>::mapping(IO &IO, + MemberFunctionRecord &MF) { + IO.mapRequired("ReturnType", MF.ReturnType); + IO.mapRequired("ClassType", MF.ClassType); + IO.mapRequired("ThisType", MF.ThisType); + IO.mapRequired("CallConv", MF.CallConv); + IO.mapRequired("Options", MF.Options); + IO.mapRequired("ParameterCount", MF.ParameterCount); + IO.mapRequired("ArgumentList", MF.ArgumentList); + IO.mapRequired("ThisPointerAdjustment", MF.ThisPointerAdjustment); +} + +void MappingTraits<MethodOverloadListRecord>::mapping( + IO &IO, MethodOverloadListRecord &MethodList) { + IO.mapRequired("Methods", MethodList.Methods); +} + +void MappingTraits<FuncIdRecord>::mapping(IO &IO, FuncIdRecord &Func) { + IO.mapRequired("ParentScope", Func.ParentScope); + IO.mapRequired("FunctionType", Func.FunctionType); + IO.mapRequired("Name", Func.Name); +} + +void MappingTraits<TypeServer2Record>::mapping(IO &IO, TypeServer2Record &TS) { + IO.mapRequired("Guid", TS.Guid); + IO.mapRequired("Age", TS.Age); + IO.mapRequired("Name", TS.Name); +} + +void MappingTraits<PointerRecord>::mapping(IO &IO, PointerRecord &Ptr) { + IO.mapRequired("ReferentType", Ptr.ReferentType); + IO.mapRequired("PtrKind", Ptr.PtrKind); + IO.mapRequired("Mode", Ptr.Mode); + IO.mapRequired("Options", Ptr.Options); + IO.mapRequired("Size", Ptr.Size); + IO.mapOptional("MemberInfo", Ptr.MemberInfo); +} + +void MappingTraits<MemberPointerInfo>::mapping(IO &IO, MemberPointerInfo &MPI) { + IO.mapRequired("ContainingType", MPI.ContainingType); + IO.mapRequired("Representation", MPI.Representation); +} + +void MappingTraits<ModifierRecord>::mapping(IO &IO, ModifierRecord &Mod) { + IO.mapRequired("ModifiedType", Mod.ModifiedType); + IO.mapRequired("Modifiers", Mod.Modifiers); +} + +void MappingTraits<BitFieldRecord>::mapping(IO &IO, BitFieldRecord &BitField) { + IO.mapRequired("Type", BitField.Type); + IO.mapRequired("BitSize", BitField.BitSize); + IO.mapRequired("BitOffset", BitField.BitOffset); +} + +void MappingTraits<VFTableShapeRecord>::mapping(IO &IO, + VFTableShapeRecord &Shape) { + IO.mapRequired("Slots", Shape.Slots); +} + +void MappingTraits<UdtSourceLineRecord>::mapping(IO &IO, + UdtSourceLineRecord &Line) { + IO.mapRequired("UDT", Line.UDT); + IO.mapRequired("SourceFile", Line.SourceFile); + IO.mapRequired("LineNumber", Line.LineNumber); +} + +void MappingTraits<UdtModSourceLineRecord>::mapping( + IO &IO, UdtModSourceLineRecord &Line) { + IO.mapRequired("UDT", Line.UDT); + IO.mapRequired("SourceFile", Line.SourceFile); + IO.mapRequired("LineNumber", Line.LineNumber); + IO.mapRequired("Module", Line.Module); +} + +void MappingTraits<BuildInfoRecord>::mapping(IO &IO, BuildInfoRecord &Args) { + IO.mapRequired("ArgIndices", Args.ArgIndices); +} + +void MappingTraits<NestedTypeRecord>::mapping(IO &IO, + NestedTypeRecord &Nested) { + IO.mapRequired("Type", Nested.Type); + IO.mapRequired("Name", Nested.Name); +} + +void MappingTraits<OneMethodRecord>::mapping(IO &IO, OneMethodRecord &Method) { + IO.mapRequired("Type", Method.Type); + IO.mapRequired("Kind", Method.Kind); + IO.mapRequired("Options", Method.Options); + IO.mapRequired("Access", Method.Access); + IO.mapRequired("VFTableOffset", Method.VFTableOffset); + IO.mapRequired("Name", Method.Name); +} + +void MappingTraits<OverloadedMethodRecord>::mapping( + IO &IO, OverloadedMethodRecord &Method) { + IO.mapRequired("NumOverloads", Method.NumOverloads); + IO.mapRequired("MethodList", Method.MethodList); + IO.mapRequired("Name", Method.Name); +} + +void MappingTraits<DataMemberRecord>::mapping(IO &IO, DataMemberRecord &Field) { + IO.mapRequired("Access", Field.Access); + IO.mapRequired("Type", Field.Type); + IO.mapRequired("FieldOffset", Field.FieldOffset); + IO.mapRequired("Name", Field.Name); +} + +void MappingTraits<StaticDataMemberRecord>::mapping( + IO &IO, StaticDataMemberRecord &Field) { + IO.mapRequired("Access", Field.Access); + IO.mapRequired("Type", Field.Type); + IO.mapRequired("Name", Field.Name); +} + +void MappingTraits<VFPtrRecord>::mapping(IO &IO, VFPtrRecord &VFTable) { + IO.mapRequired("Type", VFTable.Type); +} + +void MappingTraits<EnumeratorRecord>::mapping(IO &IO, EnumeratorRecord &Enum) { + IO.mapRequired("Access", Enum.Access); + IO.mapRequired("Value", Enum.Value); + IO.mapRequired("Name", Enum.Name); +} + +void MappingTraits<BaseClassRecord>::mapping(IO &IO, BaseClassRecord &Base) { + IO.mapRequired("Access", Base.Access); + IO.mapRequired("Type", Base.Type); + IO.mapRequired("Offset", Base.Offset); +} + +void MappingTraits<VirtualBaseClassRecord>::mapping( + IO &IO, VirtualBaseClassRecord &Base) { + IO.mapRequired("Access", Base.Access); + IO.mapRequired("BaseType", Base.BaseType); + IO.mapRequired("VBPtrType", Base.VBPtrType); + IO.mapRequired("VBPtrOffset", Base.VBPtrOffset); + IO.mapRequired("VTableIndex", Base.VTableIndex); +} + +void MappingTraits<ListContinuationRecord>::mapping( + IO &IO, ListContinuationRecord &Cont) { + IO.mapRequired("ContinuationIndex", Cont.ContinuationIndex); +} + +template <> struct ScalarTraits<codeview::TypeIndex> { + static void output(const codeview::TypeIndex &S, void *, + llvm::raw_ostream &OS) { + OS << S.getIndex(); + } + static StringRef input(StringRef Scalar, void *Ctx, codeview::TypeIndex &S) { + uint32_t I; + StringRef Result = ScalarTraits<uint32_t>::input(Scalar, Ctx, I); + if (!Result.empty()) + return Result; + S = TypeIndex(I); + return ""; + } + static bool mustQuote(StringRef Scalar) { return false; } +}; + +void ScalarEnumerationTraits<TypeLeafKind>::enumeration(IO &io, + TypeLeafKind &Value) { + auto TypeLeafNames = getTypeLeafNames(); + for (const auto &E : TypeLeafNames) + io.enumCase(Value, E.Name.str().c_str(), E.Value); +} +} +} + +Error llvm::codeview::yaml::YamlTypeDumperCallbacks::visitTypeBegin( + const CVRecord<TypeLeafKind> &CVR) { + TypeLeafKind K = CVR.Type; + YamlIO.mapRequired("Kind", K); + return Error::success(); +} diff --git a/llvm/tools/llvm-pdbdump/CodeViewYaml.h b/llvm/tools/llvm-pdbdump/CodeViewYaml.h new file mode 100644 index 00000000000..bacb55cef40 --- /dev/null +++ b/llvm/tools/llvm-pdbdump/CodeViewYaml.h @@ -0,0 +1,71 @@ +//===- PdbYAML.h ---------------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_CODEVIEWYAML_H +#define LLVM_TOOLS_LLVMPDBDUMP_CODEVIEWYAML_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/YAMLTraits.h" + +namespace llvm { +namespace codeview { +namespace yaml { +class YamlTypeDumperCallbacks : public TypeVisitorCallbacks { +public: + YamlTypeDumperCallbacks(llvm::yaml::IO &IO) : YamlIO(IO) {} + + virtual Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \ + Name##Record &Record) override { \ + YamlIO.mapRequired(#Name, Record); \ + return Error::success(); \ + } +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + +private: + llvm::yaml::IO &YamlIO; +}; +} +} +} + +namespace llvm { +namespace yaml { +template <> struct MappingTraits<codeview::MemberPointerInfo> { + static void mapping(IO &IO, codeview::MemberPointerInfo &Obj); +}; + +template <> struct MappingTraits<codeview::CVType> { + static void mapping(IO &IO, codeview::CVType &Obj); +}; + +template <> struct ScalarEnumerationTraits<codeview::TypeLeafKind> { + static void enumeration(IO &io, codeview::TypeLeafKind &Value); +}; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + template <> struct MappingTraits<codeview::Name##Record> { \ + static void mapping(IO &IO, codeview::Name##Record &Obj); \ + }; +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" +} +} + +#endif diff --git a/llvm/tools/llvm-pdbdump/PdbYaml.cpp b/llvm/tools/llvm-pdbdump/PdbYaml.cpp index 44609a8787b..187264acdbe 100644 --- a/llvm/tools/llvm-pdbdump/PdbYaml.cpp +++ b/llvm/tools/llvm-pdbdump/PdbYaml.cpp @@ -8,18 +8,29 @@ //===----------------------------------------------------------------------===// #include "PdbYaml.h" +#include "CodeViewYaml.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" using namespace llvm; -using namespace llvm::msf; -using namespace llvm::yaml; using namespace llvm::pdb; using namespace llvm::pdb::yaml; +using namespace llvm::yaml; + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiRecord) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) namespace llvm { namespace yaml { + template <> struct ScalarTraits<llvm::pdb::PDB_UniqueId> { static void output(const llvm::pdb::PDB_UniqueId &S, void *, llvm::raw_ostream &OS) { @@ -102,6 +113,16 @@ template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_ImplVer> { io.enumCase(Value, "VC140", llvm::pdb::PdbRaw_ImplVer::PdbImplVC140); } }; + +template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_TpiVer> { + static void enumeration(IO &io, llvm::pdb::PdbRaw_TpiVer &Value) { + io.enumCase(Value, "VC40", llvm::pdb::PdbRaw_TpiVer::PdbTpiV40); + io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_TpiVer::PdbTpiV41); + io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_TpiVer::PdbTpiV50); + io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_TpiVer::PdbTpiV70); + io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80); + } +}; } } @@ -111,6 +132,7 @@ void MappingTraits<PdbObject>::mapping(IO &IO, PdbObject &Obj) { IO.mapOptional("StreamMap", Obj.StreamMap); IO.mapOptional("PdbStream", Obj.PdbStream); IO.mapOptional("DbiStream", Obj.DbiStream); + IO.mapOptional("TpiStream", Obj.TpiStream); } void MappingTraits<MSFHeaders>::mapping(IO &IO, MSFHeaders &Obj) { @@ -157,6 +179,12 @@ void MappingTraits<PdbDbiStream>::mapping(IO &IO, PdbDbiStream &Obj) { IO.mapOptional("Modules", Obj.ModInfos); } +void MappingTraits<PdbTpiStream>::mapping(IO &IO, + pdb::yaml::PdbTpiStream &Obj) { + IO.mapRequired("Version", Obj.Version); + IO.mapRequired("Records", Obj.Records); +} + void MappingTraits<NamedStreamMapping>::mapping(IO &IO, NamedStreamMapping &Obj) { IO.mapRequired("Name", Obj.StreamName); @@ -168,3 +196,19 @@ void MappingTraits<PdbDbiModuleInfo>::mapping(IO &IO, PdbDbiModuleInfo &Obj) { IO.mapRequired("ObjFile", Obj.Obj); IO.mapOptional("SourceFiles", Obj.SourceFiles); } + +void MappingTraits<PdbTpiRecord>::mapping(IO &IO, + pdb::yaml::PdbTpiRecord &Obj) { + if (IO.outputting()) { + // If we're going from Pdb To Yaml, deserialize the Pdb record + codeview::yaml::YamlTypeDumperCallbacks Callbacks(IO); + codeview::TypeDeserializer Deserializer(Callbacks); + + codeview::CVTypeVisitor Visitor(Deserializer); + consumeError(Visitor.visitTypeRecord(Obj.Record)); + } else { + codeview::yaml::YamlTypeDumperCallbacks Callbacks(IO); + codeview::CVTypeVisitor Visitor(Callbacks); + consumeError(Visitor.visitTypeRecord(Obj.Record)); + } +} diff --git a/llvm/tools/llvm-pdbdump/PdbYaml.h b/llvm/tools/llvm-pdbdump/PdbYaml.h index 5dbc5686282..0da53034bf1 100644 --- a/llvm/tools/llvm-pdbdump/PdbYaml.h +++ b/llvm/tools/llvm-pdbdump/PdbYaml.h @@ -69,12 +69,23 @@ struct PdbDbiStream { std::vector<PdbDbiModuleInfo> ModInfos; }; +struct PdbTpiRecord { + std::vector<uint8_t> RecordData; + codeview::CVType Record; +}; + +struct PdbTpiStream { + PdbRaw_TpiVer Version; + std::vector<PdbTpiRecord> Records; +}; + struct PdbObject { Optional<MSFHeaders> Headers; Optional<std::vector<uint32_t>> StreamSizes; Optional<std::vector<StreamBlockList>> StreamMap; Optional<PdbInfoStream> PdbStream; Optional<PdbDbiStream> DbiStream; + Optional<PdbTpiStream> TpiStream; }; } } @@ -107,6 +118,10 @@ template <> struct MappingTraits<pdb::yaml::PdbDbiStream> { static void mapping(IO &IO, pdb::yaml::PdbDbiStream &Obj); }; +template <> struct MappingTraits<pdb::yaml::PdbTpiStream> { + static void mapping(IO &IO, pdb::yaml::PdbTpiStream &Obj); +}; + template <> struct MappingTraits<pdb::yaml::NamedStreamMapping> { static void mapping(IO &IO, pdb::yaml::NamedStreamMapping &Obj); }; @@ -114,13 +129,11 @@ template <> struct MappingTraits<pdb::yaml::NamedStreamMapping> { template <> struct MappingTraits<pdb::yaml::PdbDbiModuleInfo> { static void mapping(IO &IO, pdb::yaml::PdbDbiModuleInfo &Obj); }; + +template <> struct MappingTraits<pdb::yaml::PdbTpiRecord> { + static void mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj); +}; } } -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) - #endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H diff --git a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp index ff3d5d1cfd9..1277b01df9e 100644 --- a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -16,6 +16,7 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" using namespace llvm; using namespace llvm::pdb; @@ -45,6 +46,9 @@ Error YAMLOutputStyle::dump() { if (auto EC = dumpDbiStream()) return EC; + if (auto EC = dumpTpiStream()) + return EC; + flush(); return Error::success(); } @@ -150,6 +154,30 @@ Error YAMLOutputStyle::dumpDbiStream() { return Error::success(); } +Error YAMLOutputStyle::dumpTpiStream() { + if (!opts::pdb2yaml::TpiStream) + return Error::success(); + + auto TpiS = File.getPDBTpiStream(); + if (!TpiS) + return TpiS.takeError(); + + auto &TS = TpiS.get(); + Obj.TpiStream.emplace(); + Obj.TpiStream->Version = TS.getTpiVersion(); + for (auto &Record : TS.types(nullptr)) { + yaml::PdbTpiRecord R; + // It's not necessary to set R.RecordData here. That only exists as a + // way to have the `PdbTpiRecord` structure own the memory that `R.Record` + // references. In the case of reading an existing PDB though, that memory + // is owned by the backing stream. + R.Record = Record; + Obj.TpiStream->Records.push_back(R); + } + + return Error::success(); +} + void YAMLOutputStyle::flush() { Out << Obj; outs().flush(); diff --git a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h index d36dfec5f25..3204bdd9218 100644 --- a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h +++ b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h @@ -31,6 +31,7 @@ private: Error dumpStreamDirectory(); Error dumpPDBStream(); Error dumpDbiStream(); + Error dumpTpiStream(); void flush(); diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp index 27512f50084..902c5fcbd47 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -281,6 +281,10 @@ cl::opt<bool> DbiModuleSourceFileInfo( "Dump DBI Module Source File Information (implies -dbi-module-info"), cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt<bool> TpiStream("tpi-stream", + cl::desc("Dump the TPI Stream (Stream 3)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + cl::list<std::string> InputFilename(cl::Positional, cl::desc("<input PDB file>"), cl::Required, cl::sub(PdbToYamlSubcommand)); @@ -537,8 +541,7 @@ int main(int argc_, const char *argv_[]) { cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); - // These options are shared by two subcommands. - if ((opts::PdbToYamlSubcommand || opts::RawSubcommand) && opts::raw::RawAll) { + if (opts::RawSubcommand && opts::raw::RawAll) { opts::raw::DumpHeaders = true; opts::raw::DumpModules = true; opts::raw::DumpModuleFiles = true; diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h index c3c4a4e5980..c4f021416e6 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h @@ -65,6 +65,7 @@ extern llvm::cl::opt<bool> PdbStream; extern llvm::cl::opt<bool> DbiStream; extern llvm::cl::opt<bool> DbiModuleInfo; extern llvm::cl::opt<bool> DbiModuleSourceFileInfo; +extern llvm::cl::opt<bool> TpiStream; extern llvm::cl::list<std::string> InputFilename; } } |