summaryrefslogtreecommitdiffstats
path: root/llvm/tools
diff options
context:
space:
mode:
authorAlexandre Ganea <alexandre.ganea@ubisoft.com>2018-04-09 20:17:56 +0000
committerAlexandre Ganea <alexandre.ganea@ubisoft.com>2018-04-09 20:17:56 +0000
commitd9e96741c464f35722bbbb4d11bb7fa7c6f4fb21 (patch)
tree450fa7f2b11c3954d3beb58f6d587468428b5f8b /llvm/tools
parent69a2e18b4aeafad0e30091fb5f9c191e6d1c2df4 (diff)
downloadbcm5719-llvm-d9e96741c464f35722bbbb4d11bb7fa7c6f4fb21.tar.gz
bcm5719-llvm-d9e96741c464f35722bbbb4d11bb7fa7c6f4fb21.zip
[Debuginfo][COFF] Minimal serialization support for precompiled types records
This change adds support for the LF_PRECOMP and LF_ENDPRECOMP records required to read/write Microsoft precompiled types .objs. See https://en.wikipedia.org/wiki/Precompiled_header#Microsoft_Visual_C_and_C++ This also adds handling for the .debug$P section, which is actually a .debug$T section in disguise, found only in precompiled .objs. Differential Revision: https://reviews.llvm.org/D45283 llvm-svn: 329613
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/llvm-pdbutil/InputFile.cpp3
-rw-r--r--llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp1097
-rw-r--r--llvm/tools/obj2yaml/coff2yaml.cpp6
-rw-r--r--llvm/tools/yaml2obj/yaml2coff.cpp5
4 files changed, 567 insertions, 544 deletions
diff --git a/llvm/tools/llvm-pdbutil/InputFile.cpp b/llvm/tools/llvm-pdbutil/InputFile.cpp
index 3695cbfc4f9..7b5af7e9692 100644
--- a/llvm/tools/llvm-pdbutil/InputFile.cpp
+++ b/llvm/tools/llvm-pdbutil/InputFile.cpp
@@ -95,7 +95,8 @@ static inline bool isDebugSSection(object::SectionRef Section,
static bool isDebugTSection(SectionRef Section, CVTypeArray &Types) {
BinaryStreamReader Reader;
- if (!isCodeViewDebugSubsection(Section, ".debug$T", Reader))
+ if (!isCodeViewDebugSubsection(Section, ".debug$T", Reader) &&
+ !isCodeViewDebugSubsection(Section, ".debug$P", Reader))
return false;
cantFail(Reader.readArray(Types, Reader.bytesRemaining()));
return true;
diff --git a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
index fae89920e0b..3425c58b642 100644
--- a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
+++ b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -1,541 +1,556 @@
-//===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MinimalTypeDumper.h"
-
-#include "FormatUtil.h"
-#include "LinePrinter.h"
-
-#include "llvm/DebugInfo/CodeView/CVRecord.h"
-#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/Formatters.h"
-#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/MathExtras.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-using namespace llvm::pdb;
-
-static std::string formatClassOptions(uint32_t IndentLevel,
- ClassOptions Options) {
- std::vector<std::string> Opts;
- PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,
- "has ctor / dtor");
- PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,
- "contains nested class");
- PUSH_FLAG(ClassOptions, HasConversionOperator, Options,
- "conversion operator");
- PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
- PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");
- PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");
- PUSH_FLAG(ClassOptions, Nested, Options, "is nested");
- PUSH_FLAG(ClassOptions, HasOverloadedOperator, Options,
- "overloaded operator");
- PUSH_FLAG(ClassOptions, HasOverloadedAssignmentOperator, Options,
- "overloaded operator=");
- PUSH_FLAG(ClassOptions, Packed, Options, "packed");
- PUSH_FLAG(ClassOptions, Scoped, Options, "scoped");
- PUSH_FLAG(ClassOptions, Sealed, Options, "sealed");
-
- return typesetItemList(Opts, 4, IndentLevel, " | ");
-}
-
-static std::string pointerOptions(PointerOptions Options) {
- std::vector<std::string> Opts;
- PUSH_FLAG(PointerOptions, Flat32, Options, "flat32");
- PUSH_FLAG(PointerOptions, Volatile, Options, "volatile");
- PUSH_FLAG(PointerOptions, Const, Options, "const");
- PUSH_FLAG(PointerOptions, Unaligned, Options, "unaligned");
- PUSH_FLAG(PointerOptions, Restrict, Options, "restrict");
- PUSH_FLAG(PointerOptions, WinRTSmartPointer, Options, "winrt");
- if (Opts.empty())
- return "None";
- return join(Opts, " | ");
-}
-
-static std::string modifierOptions(ModifierOptions Options) {
- std::vector<std::string> Opts;
- PUSH_FLAG(ModifierOptions, Const, Options, "const");
- PUSH_FLAG(ModifierOptions, Volatile, Options, "volatile");
- PUSH_FLAG(ModifierOptions, Unaligned, Options, "unaligned");
- if (Opts.empty())
- return "None";
- return join(Opts, " | ");
-}
-
-static std::string formatCallingConvention(CallingConvention Convention) {
- switch (Convention) {
- RETURN_CASE(CallingConvention, AlphaCall, "alphacall");
- RETURN_CASE(CallingConvention, AM33Call, "am33call");
- RETURN_CASE(CallingConvention, ArmCall, "armcall");
- RETURN_CASE(CallingConvention, ClrCall, "clrcall");
- RETURN_CASE(CallingConvention, FarC, "far cdecl");
- RETURN_CASE(CallingConvention, FarFast, "far fastcall");
- RETURN_CASE(CallingConvention, FarPascal, "far pascal");
- RETURN_CASE(CallingConvention, FarStdCall, "far stdcall");
- RETURN_CASE(CallingConvention, FarSysCall, "far syscall");
- RETURN_CASE(CallingConvention, Generic, "generic");
- RETURN_CASE(CallingConvention, Inline, "inline");
- RETURN_CASE(CallingConvention, M32RCall, "m32rcall");
- RETURN_CASE(CallingConvention, MipsCall, "mipscall");
- RETURN_CASE(CallingConvention, NearC, "cdecl");
- RETURN_CASE(CallingConvention, NearFast, "fastcall");
- RETURN_CASE(CallingConvention, NearPascal, "pascal");
- RETURN_CASE(CallingConvention, NearStdCall, "stdcall");
- RETURN_CASE(CallingConvention, NearSysCall, "near syscall");
- RETURN_CASE(CallingConvention, NearVector, "vectorcall");
- RETURN_CASE(CallingConvention, PpcCall, "ppccall");
- RETURN_CASE(CallingConvention, SHCall, "shcall");
- RETURN_CASE(CallingConvention, SH5Call, "sh5call");
- RETURN_CASE(CallingConvention, ThisCall, "thiscall");
- RETURN_CASE(CallingConvention, TriCall, "tricall");
- }
- return formatUnknownEnum(Convention);
-}
-
-static std::string formatPointerMode(PointerMode Mode) {
- switch (Mode) {
- RETURN_CASE(PointerMode, LValueReference, "ref");
- RETURN_CASE(PointerMode, Pointer, "pointer");
- RETURN_CASE(PointerMode, PointerToDataMember, "data member pointer");
- RETURN_CASE(PointerMode, PointerToMemberFunction, "member fn pointer");
- RETURN_CASE(PointerMode, RValueReference, "rvalue ref");
- }
- return formatUnknownEnum(Mode);
-}
-
-static std::string memberAccess(MemberAccess Access) {
- switch (Access) {
- RETURN_CASE(MemberAccess, None, "");
- RETURN_CASE(MemberAccess, Private, "private");
- RETURN_CASE(MemberAccess, Protected, "protected");
- RETURN_CASE(MemberAccess, Public, "public");
- }
- return formatUnknownEnum(Access);
-}
-
-static std::string methodKind(MethodKind Kind) {
- switch (Kind) {
- RETURN_CASE(MethodKind, Vanilla, "");
- RETURN_CASE(MethodKind, Virtual, "virtual");
- RETURN_CASE(MethodKind, Static, "static");
- RETURN_CASE(MethodKind, Friend, "friend");
- RETURN_CASE(MethodKind, IntroducingVirtual, "intro virtual");
- RETURN_CASE(MethodKind, PureVirtual, "pure virtual");
- RETURN_CASE(MethodKind, PureIntroducingVirtual, "pure intro virtual");
- }
- return formatUnknownEnum(Kind);
-}
-
-static std::string pointerKind(PointerKind Kind) {
- switch (Kind) {
- RETURN_CASE(PointerKind, Near16, "ptr16");
- RETURN_CASE(PointerKind, Far16, "far ptr16");
- RETURN_CASE(PointerKind, Huge16, "huge ptr16");
- RETURN_CASE(PointerKind, BasedOnSegment, "segment based");
- RETURN_CASE(PointerKind, BasedOnValue, "value based");
- RETURN_CASE(PointerKind, BasedOnSegmentValue, "segment value based");
- RETURN_CASE(PointerKind, BasedOnAddress, "address based");
- RETURN_CASE(PointerKind, BasedOnSegmentAddress, "segment address based");
- RETURN_CASE(PointerKind, BasedOnType, "type based");
- RETURN_CASE(PointerKind, BasedOnSelf, "self based");
- RETURN_CASE(PointerKind, Near32, "ptr32");
- RETURN_CASE(PointerKind, Far32, "far ptr32");
- RETURN_CASE(PointerKind, Near64, "ptr64");
- }
- return formatUnknownEnum(Kind);
-}
-
-static std::string memberAttributes(const MemberAttributes &Attrs) {
- std::vector<std::string> Opts;
- std::string Access = memberAccess(Attrs.getAccess());
- std::string Kind = methodKind(Attrs.getMethodKind());
- if (!Access.empty())
- Opts.push_back(Access);
- if (!Kind.empty())
- Opts.push_back(Kind);
- MethodOptions Flags = Attrs.getFlags();
- PUSH_FLAG(MethodOptions, Pseudo, Flags, "pseudo");
- PUSH_FLAG(MethodOptions, NoInherit, Flags, "noinherit");
- PUSH_FLAG(MethodOptions, NoConstruct, Flags, "noconstruct");
- PUSH_FLAG(MethodOptions, CompilerGenerated, Flags, "compiler-generated");
- PUSH_FLAG(MethodOptions, Sealed, Flags, "sealed");
- return join(Opts, " ");
-}
-
-static std::string formatPointerAttrs(const PointerRecord &Record) {
- PointerMode Mode = Record.getMode();
- PointerOptions Opts = Record.getOptions();
- PointerKind Kind = Record.getPointerKind();
- return formatv("mode = {0}, opts = {1}, kind = {2}", formatPointerMode(Mode),
- pointerOptions(Opts), pointerKind(Kind));
-}
-
-static std::string formatFunctionOptions(FunctionOptions Options) {
- std::vector<std::string> Opts;
-
- PUSH_FLAG(FunctionOptions, CxxReturnUdt, Options, "returns cxx udt");
- PUSH_FLAG(FunctionOptions, ConstructorWithVirtualBases, Options,
- "constructor with virtual bases");
- PUSH_FLAG(FunctionOptions, Constructor, Options, "constructor");
- if (Opts.empty())
- return "None";
- return join(Opts, " | ");
-}
-
-Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
- // formatLine puts the newline at the beginning, so we use formatLine here
- // to start a new line, and then individual visit methods use format to
- // append to the existing line.
- if (!Hashes) {
- P.formatLine("{0} | {1} [size = {2}]",
- fmt_align(Index, AlignStyle::Right, Width),
- formatTypeLeafKind(Record.Type), Record.length());
- } else {
- std::string H;
- if (Index.toArrayIndex() >= HashValues.size()) {
- H = "(not present)";
- } else {
- uint32_t Hash = HashValues[Index.toArrayIndex()];
- Expected<uint32_t> MaybeHash = hashTypeRecord(Record);
- if (!MaybeHash)
- return MaybeHash.takeError();
- uint32_t OurHash = *MaybeHash;
- OurHash %= NumHashBuckets;
- if (Hash == OurHash)
- H = "0x" + utohexstr(Hash);
- else
- H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash);
- }
- P.formatLine("{0} | {1} [size = {2}, hash = {3}]",
- fmt_align(Index, AlignStyle::Right, Width),
- formatTypeLeafKind(Record.Type), Record.length(), H);
- }
- P.Indent(Width + 3);
- return Error::success();
-}
-Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
- P.Unindent(Width + 3);
- if (RecordBytes) {
- AutoIndent Indent(P, 9);
- P.formatBinary("Bytes", Record.RecordData, 0);
- }
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
- P.formatLine("- {0}", formatTypeLeafKind(Record.Kind));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
- if (RecordBytes) {
- AutoIndent Indent(P, 2);
- P.formatBinary("Bytes", Record.Data, 0);
- }
- return Error::success();
-}
-
-StringRef MinimalTypeDumpVisitor::getTypeName(TypeIndex TI) const {
- if (TI.isNoneType())
- return "";
- return Types.getTypeName(TI);
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- FieldListRecord &FieldList) {
- if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
- return EC;
-
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- StringIdRecord &String) {
- P.format(" ID: {0}, String: {1}", String.getId(), String.getString());
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- ArgListRecord &Args) {
- auto Indices = Args.getIndices();
- if (Indices.empty())
- return Error::success();
-
- auto Max = std::max_element(Indices.begin(), Indices.end());
- uint32_t W = NumDigits(Max->getIndex()) + 2;
-
- for (auto I : Indices)
- P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
- getTypeName(I));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- StringListRecord &Strings) {
- auto Indices = Strings.getIndices();
- if (Indices.empty())
- return Error::success();
-
- auto Max = std::max_element(Indices.begin(), Indices.end());
- uint32_t W = NumDigits(Max->getIndex()) + 2;
-
- for (auto I : Indices)
- P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
- getTypeName(I));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- ClassRecord &Class) {
- P.format(" `{0}`", Class.Name);
- if (Class.hasUniqueName())
- P.formatLine("unique name: `{0}`", Class.UniqueName);
- P.formatLine("vtable: {0}, base list: {1}, field list: {2}",
- Class.VTableShape, Class.DerivationList, Class.FieldList);
- P.formatLine("options: {0}",
- formatClassOptions(P.getIndentLevel(), Class.Options));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- UnionRecord &Union) {
- P.format(" `{0}`", Union.Name);
- if (Union.hasUniqueName())
- P.formatLine("unique name: `{0}`", Union.UniqueName);
- P.formatLine("field list: {0}", Union.FieldList);
- P.formatLine("options: {0}",
- formatClassOptions(P.getIndentLevel(), Union.Options));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
- P.format(" `{0}`", Enum.Name);
- if (Enum.hasUniqueName())
- P.formatLine("unique name: `{0}`", Enum.UniqueName);
- P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,
- Enum.UnderlyingType);
- P.formatLine("options: {0}",
- formatClassOptions(P.getIndentLevel(), Enum.Options));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
- if (AT.Name.empty()) {
- P.formatLine("size: {0}, index type: {1}, element type: {2}", AT.Size,
- AT.IndexType, AT.ElementType);
- } else {
- P.formatLine("name: {0}, size: {1}, index type: {2}, element type: {3}",
- AT.Name, AT.Size, AT.IndexType, AT.ElementType);
- }
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- VFTableRecord &VFT) {
- P.formatLine("offset: {0}, complete class: {1}, overridden vftable: {2}",
- VFT.VFPtrOffset, VFT.CompleteClass, VFT.OverriddenVFTable);
- P.formatLine("method names: ");
- if (!VFT.MethodNames.empty()) {
- std::string Sep =
- formatv("\n{0}",
- fmt_repeat(' ', P.getIndentLevel() + strlen("method names: ")))
- .str();
- P.print(join(VFT.MethodNames, Sep));
- }
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- MemberFuncIdRecord &Id) {
- P.formatLine("name = {0}, type = {1}, class type = {2}", Id.Name,
- Id.FunctionType, Id.ClassType);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- ProcedureRecord &Proc) {
- P.formatLine("return type = {0}, # args = {1}, param list = {2}",
- Proc.ReturnType, Proc.ParameterCount, Proc.ArgumentList);
- P.formatLine("calling conv = {0}, options = {1}",
- formatCallingConvention(Proc.CallConv),
- formatFunctionOptions(Proc.Options));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- MemberFunctionRecord &MF) {
- P.formatLine("return type = {0}, # args = {1}, param list = {2}",
- MF.ReturnType, MF.ParameterCount, MF.ArgumentList);
- P.formatLine("class type = {0}, this type = {1}, this adjust = {2}",
- MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment);
- P.formatLine("calling conv = {0}, options = {1}",
- formatCallingConvention(MF.CallConv),
- formatFunctionOptions(MF.Options));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- FuncIdRecord &Func) {
- P.formatLine("name = {0}, type = {1}, parent scope = {2}", Func.Name,
- Func.FunctionType, Func.ParentScope);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- TypeServer2Record &TS) {
- P.formatLine("name = {0}, age = {1}, guid = {2}", TS.Name, TS.Age, TS.Guid);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- PointerRecord &Ptr) {
- P.formatLine("referent = {0}, {1}", Ptr.ReferentType,
- formatPointerAttrs(Ptr));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- ModifierRecord &Mod) {
- P.formatLine("referent = {0}, modifiers = {1}", Mod.ModifiedType,
- modifierOptions(Mod.Modifiers));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- VFTableShapeRecord &Shape) {
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- UdtModSourceLineRecord &U) {
- P.formatLine("udt = {0}, mod = {1}, file = {2}, line = {3}", U.UDT, U.Module,
- U.SourceFile.getIndex(), U.LineNumber);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- UdtSourceLineRecord &U) {
- P.formatLine("udt = {0}, file = {1}, line = {2}", U.UDT,
- U.SourceFile.getIndex(), U.LineNumber);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- BitFieldRecord &BF) {
- P.formatLine("type = {0}, bit offset = {1}, # bits = {2}", BF.Type,
- BF.BitOffset, BF.BitSize);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(
- CVType &CVR, MethodOverloadListRecord &Overloads) {
- for (auto &M : Overloads.Methods)
- P.formatLine("- Method [type = {0}, vftable offset = {1}, attrs = {2}]",
- M.Type, M.VFTableOffset, memberAttributes(M.Attrs));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
- BuildInfoRecord &BI) {
- auto Indices = BI.ArgIndices;
- if (Indices.empty())
- return Error::success();
-
- auto Max = std::max_element(Indices.begin(), Indices.end());
- uint32_t W = NumDigits(Max->getIndex()) + 2;
-
- for (auto I : Indices)
- P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
- getTypeName(I));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) {
- std::string Type = (R.Mode == LabelType::Far) ? "far" : "near";
- P.format(" type = {0}", Type);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- NestedTypeRecord &Nested) {
- P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- OneMethodRecord &Method) {
- P.format(" [name = `{0}`]", Method.Name);
- AutoIndent Indent(P);
- P.formatLine("type = {0}, vftable offset = {1}, attrs = {2}", Method.Type,
- Method.VFTableOffset, memberAttributes(Method.Attrs));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- OverloadedMethodRecord &Method) {
- P.format(" [name = `{0}`, # overloads = {1}, overload list = {2}]",
- Method.Name, Method.NumOverloads, Method.MethodList);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- DataMemberRecord &Field) {
- P.format(" [name = `{0}`, Type = {1}, offset = {2}, attrs = {3}]", Field.Name,
- Field.Type, Field.FieldOffset, memberAttributes(Field.Attrs));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- StaticDataMemberRecord &Field) {
- P.format(" [name = `{0}`, type = {1}, attrs = {2}]", Field.Name, Field.Type,
- memberAttributes(Field.Attrs));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- EnumeratorRecord &Enum) {
- P.format(" [{0} = {1}]", Enum.Name,
- Enum.Value.toString(10, Enum.Value.isSigned()));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- BaseClassRecord &Base) {
- AutoIndent Indent(P);
- P.formatLine("type = {0}, offset = {1}, attrs = {2}", Base.Type, Base.Offset,
- memberAttributes(Base.Attrs));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- VirtualBaseClassRecord &Base) {
- AutoIndent Indent(P);
- P.formatLine(
- "base = {0}, vbptr = {1}, vbptr offset = {2}, vtable index = {3}",
- Base.BaseType, Base.VBPtrType, Base.VBPtrOffset, Base.VTableIndex);
- P.formatLine("attrs = {0}", memberAttributes(Base.Attrs));
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- ListContinuationRecord &Cont) {
- P.format(" continuation = {0}", Cont.ContinuationIndex);
- return Error::success();
-}
-
-Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
- VFPtrRecord &VFP) {
- P.format(" type = {0}", VFP.Type);
- return Error::success();
-}
+//===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinimalTypeDumper.h"
+
+#include "FormatUtil.h"
+#include "LinePrinter.h"
+
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static std::string formatClassOptions(uint32_t IndentLevel,
+ ClassOptions Options) {
+ std::vector<std::string> Opts;
+ PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,
+ "has ctor / dtor");
+ PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,
+ "contains nested class");
+ PUSH_FLAG(ClassOptions, HasConversionOperator, Options,
+ "conversion operator");
+ PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
+ PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");
+ PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");
+ PUSH_FLAG(ClassOptions, Nested, Options, "is nested");
+ PUSH_FLAG(ClassOptions, HasOverloadedOperator, Options,
+ "overloaded operator");
+ PUSH_FLAG(ClassOptions, HasOverloadedAssignmentOperator, Options,
+ "overloaded operator=");
+ PUSH_FLAG(ClassOptions, Packed, Options, "packed");
+ PUSH_FLAG(ClassOptions, Scoped, Options, "scoped");
+ PUSH_FLAG(ClassOptions, Sealed, Options, "sealed");
+
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string pointerOptions(PointerOptions Options) {
+ std::vector<std::string> Opts;
+ PUSH_FLAG(PointerOptions, Flat32, Options, "flat32");
+ PUSH_FLAG(PointerOptions, Volatile, Options, "volatile");
+ PUSH_FLAG(PointerOptions, Const, Options, "const");
+ PUSH_FLAG(PointerOptions, Unaligned, Options, "unaligned");
+ PUSH_FLAG(PointerOptions, Restrict, Options, "restrict");
+ PUSH_FLAG(PointerOptions, WinRTSmartPointer, Options, "winrt");
+ if (Opts.empty())
+ return "None";
+ return join(Opts, " | ");
+}
+
+static std::string modifierOptions(ModifierOptions Options) {
+ std::vector<std::string> Opts;
+ PUSH_FLAG(ModifierOptions, Const, Options, "const");
+ PUSH_FLAG(ModifierOptions, Volatile, Options, "volatile");
+ PUSH_FLAG(ModifierOptions, Unaligned, Options, "unaligned");
+ if (Opts.empty())
+ return "None";
+ return join(Opts, " | ");
+}
+
+static std::string formatCallingConvention(CallingConvention Convention) {
+ switch (Convention) {
+ RETURN_CASE(CallingConvention, AlphaCall, "alphacall");
+ RETURN_CASE(CallingConvention, AM33Call, "am33call");
+ RETURN_CASE(CallingConvention, ArmCall, "armcall");
+ RETURN_CASE(CallingConvention, ClrCall, "clrcall");
+ RETURN_CASE(CallingConvention, FarC, "far cdecl");
+ RETURN_CASE(CallingConvention, FarFast, "far fastcall");
+ RETURN_CASE(CallingConvention, FarPascal, "far pascal");
+ RETURN_CASE(CallingConvention, FarStdCall, "far stdcall");
+ RETURN_CASE(CallingConvention, FarSysCall, "far syscall");
+ RETURN_CASE(CallingConvention, Generic, "generic");
+ RETURN_CASE(CallingConvention, Inline, "inline");
+ RETURN_CASE(CallingConvention, M32RCall, "m32rcall");
+ RETURN_CASE(CallingConvention, MipsCall, "mipscall");
+ RETURN_CASE(CallingConvention, NearC, "cdecl");
+ RETURN_CASE(CallingConvention, NearFast, "fastcall");
+ RETURN_CASE(CallingConvention, NearPascal, "pascal");
+ RETURN_CASE(CallingConvention, NearStdCall, "stdcall");
+ RETURN_CASE(CallingConvention, NearSysCall, "near syscall");
+ RETURN_CASE(CallingConvention, NearVector, "vectorcall");
+ RETURN_CASE(CallingConvention, PpcCall, "ppccall");
+ RETURN_CASE(CallingConvention, SHCall, "shcall");
+ RETURN_CASE(CallingConvention, SH5Call, "sh5call");
+ RETURN_CASE(CallingConvention, ThisCall, "thiscall");
+ RETURN_CASE(CallingConvention, TriCall, "tricall");
+ }
+ return formatUnknownEnum(Convention);
+}
+
+static std::string formatPointerMode(PointerMode Mode) {
+ switch (Mode) {
+ RETURN_CASE(PointerMode, LValueReference, "ref");
+ RETURN_CASE(PointerMode, Pointer, "pointer");
+ RETURN_CASE(PointerMode, PointerToDataMember, "data member pointer");
+ RETURN_CASE(PointerMode, PointerToMemberFunction, "member fn pointer");
+ RETURN_CASE(PointerMode, RValueReference, "rvalue ref");
+ }
+ return formatUnknownEnum(Mode);
+}
+
+static std::string memberAccess(MemberAccess Access) {
+ switch (Access) {
+ RETURN_CASE(MemberAccess, None, "");
+ RETURN_CASE(MemberAccess, Private, "private");
+ RETURN_CASE(MemberAccess, Protected, "protected");
+ RETURN_CASE(MemberAccess, Public, "public");
+ }
+ return formatUnknownEnum(Access);
+}
+
+static std::string methodKind(MethodKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(MethodKind, Vanilla, "");
+ RETURN_CASE(MethodKind, Virtual, "virtual");
+ RETURN_CASE(MethodKind, Static, "static");
+ RETURN_CASE(MethodKind, Friend, "friend");
+ RETURN_CASE(MethodKind, IntroducingVirtual, "intro virtual");
+ RETURN_CASE(MethodKind, PureVirtual, "pure virtual");
+ RETURN_CASE(MethodKind, PureIntroducingVirtual, "pure intro virtual");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+static std::string pointerKind(PointerKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(PointerKind, Near16, "ptr16");
+ RETURN_CASE(PointerKind, Far16, "far ptr16");
+ RETURN_CASE(PointerKind, Huge16, "huge ptr16");
+ RETURN_CASE(PointerKind, BasedOnSegment, "segment based");
+ RETURN_CASE(PointerKind, BasedOnValue, "value based");
+ RETURN_CASE(PointerKind, BasedOnSegmentValue, "segment value based");
+ RETURN_CASE(PointerKind, BasedOnAddress, "address based");
+ RETURN_CASE(PointerKind, BasedOnSegmentAddress, "segment address based");
+ RETURN_CASE(PointerKind, BasedOnType, "type based");
+ RETURN_CASE(PointerKind, BasedOnSelf, "self based");
+ RETURN_CASE(PointerKind, Near32, "ptr32");
+ RETURN_CASE(PointerKind, Far32, "far ptr32");
+ RETURN_CASE(PointerKind, Near64, "ptr64");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+static std::string memberAttributes(const MemberAttributes &Attrs) {
+ std::vector<std::string> Opts;
+ std::string Access = memberAccess(Attrs.getAccess());
+ std::string Kind = methodKind(Attrs.getMethodKind());
+ if (!Access.empty())
+ Opts.push_back(Access);
+ if (!Kind.empty())
+ Opts.push_back(Kind);
+ MethodOptions Flags = Attrs.getFlags();
+ PUSH_FLAG(MethodOptions, Pseudo, Flags, "pseudo");
+ PUSH_FLAG(MethodOptions, NoInherit, Flags, "noinherit");
+ PUSH_FLAG(MethodOptions, NoConstruct, Flags, "noconstruct");
+ PUSH_FLAG(MethodOptions, CompilerGenerated, Flags, "compiler-generated");
+ PUSH_FLAG(MethodOptions, Sealed, Flags, "sealed");
+ return join(Opts, " ");
+}
+
+static std::string formatPointerAttrs(const PointerRecord &Record) {
+ PointerMode Mode = Record.getMode();
+ PointerOptions Opts = Record.getOptions();
+ PointerKind Kind = Record.getPointerKind();
+ return formatv("mode = {0}, opts = {1}, kind = {2}", formatPointerMode(Mode),
+ pointerOptions(Opts), pointerKind(Kind));
+}
+
+static std::string formatFunctionOptions(FunctionOptions Options) {
+ std::vector<std::string> Opts;
+
+ PUSH_FLAG(FunctionOptions, CxxReturnUdt, Options, "returns cxx udt");
+ PUSH_FLAG(FunctionOptions, ConstructorWithVirtualBases, Options,
+ "constructor with virtual bases");
+ PUSH_FLAG(FunctionOptions, Constructor, Options, "constructor");
+ if (Opts.empty())
+ return "None";
+ return join(Opts, " | ");
+}
+
+Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
+ // formatLine puts the newline at the beginning, so we use formatLine here
+ // to start a new line, and then individual visit methods use format to
+ // append to the existing line.
+ if (!Hashes) {
+ P.formatLine("{0} | {1} [size = {2}]",
+ fmt_align(Index, AlignStyle::Right, Width),
+ formatTypeLeafKind(Record.Type), Record.length());
+ } else {
+ std::string H;
+ if (Index.toArrayIndex() >= HashValues.size()) {
+ H = "(not present)";
+ } else {
+ uint32_t Hash = HashValues[Index.toArrayIndex()];
+ Expected<uint32_t> MaybeHash = hashTypeRecord(Record);
+ if (!MaybeHash)
+ return MaybeHash.takeError();
+ uint32_t OurHash = *MaybeHash;
+ OurHash %= NumHashBuckets;
+ if (Hash == OurHash)
+ H = "0x" + utohexstr(Hash);
+ else
+ H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash);
+ }
+ P.formatLine("{0} | {1} [size = {2}, hash = {3}]",
+ fmt_align(Index, AlignStyle::Right, Width),
+ formatTypeLeafKind(Record.Type), Record.length(), H);
+ }
+ P.Indent(Width + 3);
+ return Error::success();
+}
+Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
+ P.Unindent(Width + 3);
+ if (RecordBytes) {
+ AutoIndent Indent(P, 9);
+ P.formatBinary("Bytes", Record.RecordData, 0);
+ }
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
+ P.formatLine("- {0}", formatTypeLeafKind(Record.Kind));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
+ if (RecordBytes) {
+ AutoIndent Indent(P, 2);
+ P.formatBinary("Bytes", Record.Data, 0);
+ }
+ return Error::success();
+}
+
+StringRef MinimalTypeDumpVisitor::getTypeName(TypeIndex TI) const {
+ if (TI.isNoneType())
+ return "";
+ return Types.getTypeName(TI);
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ FieldListRecord &FieldList) {
+ if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
+ return EC;
+
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ StringIdRecord &String) {
+ P.format(" ID: {0}, String: {1}", String.getId(), String.getString());
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ArgListRecord &Args) {
+ auto Indices = Args.getIndices();
+ if (Indices.empty())
+ return Error::success();
+
+ auto Max = std::max_element(Indices.begin(), Indices.end());
+ uint32_t W = NumDigits(Max->getIndex()) + 2;
+
+ for (auto I : Indices)
+ P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
+ getTypeName(I));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ StringListRecord &Strings) {
+ auto Indices = Strings.getIndices();
+ if (Indices.empty())
+ return Error::success();
+
+ auto Max = std::max_element(Indices.begin(), Indices.end());
+ uint32_t W = NumDigits(Max->getIndex()) + 2;
+
+ for (auto I : Indices)
+ P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
+ getTypeName(I));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ClassRecord &Class) {
+ P.format(" `{0}`", Class.Name);
+ if (Class.hasUniqueName())
+ P.formatLine("unique name: `{0}`", Class.UniqueName);
+ P.formatLine("vtable: {0}, base list: {1}, field list: {2}",
+ Class.VTableShape, Class.DerivationList, Class.FieldList);
+ P.formatLine("options: {0}",
+ formatClassOptions(P.getIndentLevel(), Class.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UnionRecord &Union) {
+ P.format(" `{0}`", Union.Name);
+ if (Union.hasUniqueName())
+ P.formatLine("unique name: `{0}`", Union.UniqueName);
+ P.formatLine("field list: {0}", Union.FieldList);
+ P.formatLine("options: {0}",
+ formatClassOptions(P.getIndentLevel(), Union.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
+ P.format(" `{0}`", Enum.Name);
+ if (Enum.hasUniqueName())
+ P.formatLine("unique name: `{0}`", Enum.UniqueName);
+ P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,
+ Enum.UnderlyingType);
+ P.formatLine("options: {0}",
+ formatClassOptions(P.getIndentLevel(), Enum.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
+ if (AT.Name.empty()) {
+ P.formatLine("size: {0}, index type: {1}, element type: {2}", AT.Size,
+ AT.IndexType, AT.ElementType);
+ } else {
+ P.formatLine("name: {0}, size: {1}, index type: {2}, element type: {3}",
+ AT.Name, AT.Size, AT.IndexType, AT.ElementType);
+ }
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ VFTableRecord &VFT) {
+ P.formatLine("offset: {0}, complete class: {1}, overridden vftable: {2}",
+ VFT.VFPtrOffset, VFT.CompleteClass, VFT.OverriddenVFTable);
+ P.formatLine("method names: ");
+ if (!VFT.MethodNames.empty()) {
+ std::string Sep =
+ formatv("\n{0}",
+ fmt_repeat(' ', P.getIndentLevel() + strlen("method names: ")))
+ .str();
+ P.print(join(VFT.MethodNames, Sep));
+ }
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ MemberFuncIdRecord &Id) {
+ P.formatLine("name = {0}, type = {1}, class type = {2}", Id.Name,
+ Id.FunctionType, Id.ClassType);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ProcedureRecord &Proc) {
+ P.formatLine("return type = {0}, # args = {1}, param list = {2}",
+ Proc.ReturnType, Proc.ParameterCount, Proc.ArgumentList);
+ P.formatLine("calling conv = {0}, options = {1}",
+ formatCallingConvention(Proc.CallConv),
+ formatFunctionOptions(Proc.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ MemberFunctionRecord &MF) {
+ P.formatLine("return type = {0}, # args = {1}, param list = {2}",
+ MF.ReturnType, MF.ParameterCount, MF.ArgumentList);
+ P.formatLine("class type = {0}, this type = {1}, this adjust = {2}",
+ MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment);
+ P.formatLine("calling conv = {0}, options = {1}",
+ formatCallingConvention(MF.CallConv),
+ formatFunctionOptions(MF.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ FuncIdRecord &Func) {
+ P.formatLine("name = {0}, type = {1}, parent scope = {2}", Func.Name,
+ Func.FunctionType, Func.ParentScope);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ TypeServer2Record &TS) {
+ P.formatLine("name = {0}, age = {1}, guid = {2}", TS.Name, TS.Age, TS.Guid);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ PointerRecord &Ptr) {
+ P.formatLine("referent = {0}, {1}", Ptr.ReferentType,
+ formatPointerAttrs(Ptr));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ModifierRecord &Mod) {
+ P.formatLine("referent = {0}, modifiers = {1}", Mod.ModifiedType,
+ modifierOptions(Mod.Modifiers));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Shape) {
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtModSourceLineRecord &U) {
+ P.formatLine("udt = {0}, mod = {1}, file = {2}, line = {3}", U.UDT, U.Module,
+ U.SourceFile.getIndex(), U.LineNumber);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &U) {
+ P.formatLine("udt = {0}, file = {1}, line = {2}", U.UDT,
+ U.SourceFile.getIndex(), U.LineNumber);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ BitFieldRecord &BF) {
+ P.formatLine("type = {0}, bit offset = {1}, # bits = {2}", BF.Type,
+ BF.BitOffset, BF.BitSize);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(
+ CVType &CVR, MethodOverloadListRecord &Overloads) {
+ for (auto &M : Overloads.Methods)
+ P.formatLine("- Method [type = {0}, vftable offset = {1}, attrs = {2}]",
+ M.Type, M.VFTableOffset, memberAttributes(M.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ BuildInfoRecord &BI) {
+ auto Indices = BI.ArgIndices;
+ if (Indices.empty())
+ return Error::success();
+
+ auto Max = std::max_element(Indices.begin(), Indices.end());
+ uint32_t W = NumDigits(Max->getIndex()) + 2;
+
+ for (auto I : Indices)
+ P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
+ getTypeName(I));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) {
+ std::string Type = (R.Mode == LabelType::Far) ? "far" : "near";
+ P.format(" type = {0}", Type);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ PrecompRecord &Precomp) {
+ P.format(" start index = {0:X+}, types count = {1:X+}, signature = {2:X+},"
+ " precomp path = {3}",
+ Precomp.StartTypeIndex, Precomp.TypesCount, Precomp.Signature,
+ Precomp.PrecompFilePath);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ EndPrecompRecord &EP) {
+ P.format(" signature = {0:X+}", EP.Signature);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Nested) {
+ P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OneMethodRecord &Method) {
+ P.format(" [name = `{0}`]", Method.Name);
+ AutoIndent Indent(P);
+ P.formatLine("type = {0}, vftable offset = {1}, attrs = {2}", Method.Type,
+ Method.VFTableOffset, memberAttributes(Method.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OverloadedMethodRecord &Method) {
+ P.format(" [name = `{0}`, # overloads = {1}, overload list = {2}]",
+ Method.Name, Method.NumOverloads, Method.MethodList);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ DataMemberRecord &Field) {
+ P.format(" [name = `{0}`, Type = {1}, offset = {2}, attrs = {3}]", Field.Name,
+ Field.Type, Field.FieldOffset, memberAttributes(Field.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ StaticDataMemberRecord &Field) {
+ P.format(" [name = `{0}`, type = {1}, attrs = {2}]", Field.Name, Field.Type,
+ memberAttributes(Field.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ EnumeratorRecord &Enum) {
+ P.format(" [{0} = {1}]", Enum.Name,
+ Enum.Value.toString(10, Enum.Value.isSigned()));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ BaseClassRecord &Base) {
+ AutoIndent Indent(P);
+ P.formatLine("type = {0}, offset = {1}, attrs = {2}", Base.Type, Base.Offset,
+ memberAttributes(Base.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VirtualBaseClassRecord &Base) {
+ AutoIndent Indent(P);
+ P.formatLine(
+ "base = {0}, vbptr = {1}, vbptr offset = {2}, vtable index = {3}",
+ Base.BaseType, Base.VBPtrType, Base.VBPtrOffset, Base.VTableIndex);
+ P.formatLine("attrs = {0}", memberAttributes(Base.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ ListContinuationRecord &Cont) {
+ P.format(" continuation = {0}", Cont.ContinuationIndex);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VFPtrRecord &VFP) {
+ P.format(" type = {0}", VFP.Type);
+ return Error::success();
+}
diff --git a/llvm/tools/obj2yaml/coff2yaml.cpp b/llvm/tools/obj2yaml/coff2yaml.cpp
index 6c4f8437cae..1c59c5c35ef 100644
--- a/llvm/tools/obj2yaml/coff2yaml.cpp
+++ b/llvm/tools/obj2yaml/coff2yaml.cpp
@@ -170,7 +170,11 @@ void COFFDumper::dumpSections(unsigned NumSections) {
if (NewYAMLSection.Name == ".debug$S")
NewYAMLSection.DebugS = CodeViewYAML::fromDebugS(sectionData, SC);
else if (NewYAMLSection.Name == ".debug$T")
- NewYAMLSection.DebugT = CodeViewYAML::fromDebugT(sectionData);
+ NewYAMLSection.DebugT = CodeViewYAML::fromDebugT(sectionData,
+ NewYAMLSection.Name);
+ else if (NewYAMLSection.Name == ".debug$P")
+ NewYAMLSection.DebugP = CodeViewYAML::fromDebugT(sectionData,
+ NewYAMLSection.Name);
else if (NewYAMLSection.Name == ".debug$H")
NewYAMLSection.DebugH = CodeViewYAML::fromDebugH(sectionData);
diff --git a/llvm/tools/yaml2obj/yaml2coff.cpp b/llvm/tools/yaml2obj/yaml2coff.cpp
index 648317e97bb..88af85dcb0d 100644
--- a/llvm/tools/yaml2obj/yaml2coff.cpp
+++ b/llvm/tools/yaml2obj/yaml2coff.cpp
@@ -233,7 +233,10 @@ static bool layoutCOFF(COFFParser &CP) {
}
} else if (S.Name == ".debug$T") {
if (S.SectionData.binary_size() == 0)
- S.SectionData = CodeViewYAML::toDebugT(S.DebugT, CP.Allocator);
+ S.SectionData = CodeViewYAML::toDebugT(S.DebugT, CP.Allocator, S.Name);
+ } else if (S.Name == ".debug$P") {
+ if (S.SectionData.binary_size() == 0)
+ S.SectionData = CodeViewYAML::toDebugT(S.DebugP, CP.Allocator, S.Name);
} else if (S.Name == ".debug$H") {
if (S.DebugH.hasValue() && S.SectionData.binary_size() == 0)
S.SectionData = CodeViewYAML::toDebugH(*S.DebugH, CP.Allocator);
OpenPOWER on IntegriCloud