From 3de8077a9400e585188b55d5052669a498b42a47 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Mon, 20 Aug 2018 19:15:35 +0000 Subject: [PATCH] [MS Demangler] Demangle member pointer template parameters. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@340199 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Demangle/MicrosoftDemangle.cpp | 193 ++++++++++++++++++++++-------- test/Demangle/ms-templates-memptrs-2.test | 31 +++++ test/Demangle/ms-templates-memptrs.test | 95 +++++++++++++++ 3 files changed, 270 insertions(+), 49 deletions(-) create mode 100644 test/Demangle/ms-templates-memptrs-2.test create mode 100644 test/Demangle/ms-templates-memptrs.test diff --git a/lib/Demangle/MicrosoftDemangle.cpp b/lib/Demangle/MicrosoftDemangle.cpp index 6f382098b27..58678e9f908 100644 --- a/lib/Demangle/MicrosoftDemangle.cpp +++ b/lib/Demangle/MicrosoftDemangle.cpp @@ -20,6 +20,7 @@ #include "StringView.h" #include "Utility.h" +#include #include #include #include @@ -415,8 +416,13 @@ struct TemplateParams { bool IntegerLiteralIsNegative = false; bool IsEmptyParameterPack = false; bool PointerToSymbol = false; + bool NullptrLiteral = false; + bool DataMemberPointer = false; bool ReferenceToSymbol = false; + int ThunkOffsetCount = 0; + std::array ThunkOffsets; + // If IsIntegerLiteral is true, this is a non-type template parameter // whose value is contained in this field. uint64_t IntegralValue = 0; @@ -794,11 +800,30 @@ static void outputParameterList(OutputStream &OS, OS << '-'; OS << Head->IntegralValue; } else if (Head->PointerToSymbol || Head->ReferenceToSymbol) { - if (Head->PointerToSymbol) - OS << "&"; - Type::outputPre(OS, *Head->ParamType); - outputName(OS, Head->ParamName, Head->ParamType); - Type::outputPost(OS, *Head->ParamType); + if (Head->NullptrLiteral) + OS << "nullptr"; + else { + if (Head->ThunkOffsetCount > 0) + OS << "{"; + else if (Head->PointerToSymbol) + OS << "&"; + if (Head->ParamType) + Type::outputPre(OS, *Head->ParamType); + outputName(OS, Head->ParamName, Head->ParamType); + if (Head->ParamType) + Type::outputPost(OS, *Head->ParamType); + if (Head->ThunkOffsetCount > 0) { + for (int I = 0; I < Head->ThunkOffsetCount; ++I) { + OS << ", " << Head->ThunkOffsets[I]; + } + OS << "}"; + } + } + } else if (Head->DataMemberPointer) { + OS << "{" << Head->ThunkOffsets[0]; + for (int I = 1; I < Head->ThunkOffsetCount; ++I) + OS << ", " << Head->ThunkOffsets[I]; + OS << "}"; } else if (Head->ParamType) { // simple type. Type::outputPre(OS, *Head->ParamType); @@ -840,12 +865,33 @@ static void outputNameComponent(OutputStream &OS, const Name &N) { outputParameterList(OS, *N.TParams); } +static const OperatorInfo *lastComponentAsOperator(const Name *TheName) { + if (!TheName) + return nullptr; + while (TheName->Next) + TheName = TheName->Next; + if (TheName->IsOperator) + return static_cast(TheName); + return nullptr; +} + static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) { if (!TheName) return; outputSpaceIfNecessary(OS); + const OperatorInfo *Operator = lastComponentAsOperator(TheName); + const VirtualMemberPtrThunk *Thunk = nullptr; + if (Operator) { + if (Operator->Info->Operator == OperatorTy::Vcall) { + Thunk = static_cast(Operator); + OS << "[thunk]: "; + outputCallingConvention(OS, Thunk->CC); + OS << " "; + } + } + const Name *Previous = nullptr; // Print out namespaces or outer class BackReferences. for (; TheName->Next; TheName = TheName->Next) { @@ -860,10 +906,9 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) { return; } - const OperatorInfo &Operator = static_cast(*TheName); // Print out ctor or dtor. - switch (Operator.Info->Operator) { + switch (Operator->Info->Operator) { case OperatorTy::Dtor: OS << "~"; LLVM_FALLTHROUGH; @@ -884,30 +929,36 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) { } break; case OperatorTy::LiteralOperator: - OS << Operator.Info->Name; + OS << Operator->Info->Name; outputNameComponent(OS, *TheName); break; case OperatorTy::RttiBaseClassDescriptor: { const RttiBaseClassDescriptor &BCD = - static_cast(Operator); - OS << "`" << Operator.Info->Name << " at ("; + static_cast(*Operator); + OS << "`" << Operator->Info->Name << " at ("; OS << BCD.NVOffset << ", " << BCD.VBPtrOffset << ", " << BCD.VBTableOffset << ", " << BCD.Flags; OS << ")'"; break; } + case OperatorTy::Vcall: { + OS << "`vcall'{"; + OS << Thunk->OffsetInVTable << ", {flat}}"; + break; + } + case OperatorTy::LocalStaticGuard: { const LocalStaticGuardVariable &LSG = - static_cast(Operator); - OS << Operator.Info->Name; + static_cast(*Operator); + OS << Operator->Info->Name; if (LSG.ScopeIndex > 0) OS << "{" << LSG.ScopeIndex << "}"; break; } default: - OS << Operator.Info->Name; - if (Operator.IsTemplateInstantiation) - outputParameterList(OS, *Operator.TParams); + OS << Operator->Info->Name; + if (Operator->IsTemplateInstantiation) + outputParameterList(OS, *Operator->TParams); break; } } @@ -915,12 +966,10 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) { static void outputSpecialOperator(OutputStream &OS, const Name *OuterName) { assert(OuterName); // The last component should be an operator. - const Name *LastComponent = OuterName; - while (LastComponent->Next) - LastComponent = LastComponent->Next; + const OperatorInfo *Operator = lastComponentAsOperator(OuterName); - assert(LastComponent->IsOperator); - const OperatorInfo &Oper = static_cast(*LastComponent); + assert(Operator->IsOperator); + const OperatorInfo &Oper = static_cast(*Operator); switch (Oper.Info->Operator) { case OperatorTy::StringLiteral: { const StringLiteral &SL = static_cast(Oper); @@ -1398,9 +1447,14 @@ Symbol *Demangler::parseOperator(StringView &MangledName) { std::tie(OTy, S->SymbolName) = demangleOperatorName(MangledName, true); switch (OTy) { case OperatorTy::StringLiteral: - case OperatorTy::Vcall: S->Category = SymbolCategory::SpecialOperator; break; + case OperatorTy::Vcall: + S->Category = SymbolCategory::UnnamedFunction; + break; + case OperatorTy::LocalStaticGuard: + S->Category = SymbolCategory::UnnamedVariable; + break; case OperatorTy::Vftable: // Foo@@6B@ case OperatorTy::LocalVftable: // Foo@@6B@ case OperatorTy::RttiCompleteObjLocator: // Foo@@6B@ @@ -1428,10 +1482,6 @@ Symbol *Demangler::parseOperator(StringView &MangledName) { if (!MangledName.empty()) Error = true; break; - case OperatorTy::LocalStaticGuard: { - S->Category = SymbolCategory::UnnamedVariable; - break; - } default: if (!Error) std::tie(S->Category, S->SymbolType) = @@ -2878,57 +2928,102 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) { // Template parameter lists don't participate in back-referencing. *Current = Arena.alloc(); + TemplateParams &TP = **Current; + // Empty parameter pack. if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") || MangledName.consumeFront("$$$V")) { - (*Current)->IsEmptyParameterPack = true; + TP.IsEmptyParameterPack = true; break; } if (MangledName.consumeFront("$$Y")) { // Template alias - (*Current)->IsTemplateTemplate = true; - (*Current)->IsAliasTemplate = true; - (*Current)->ParamName = demangleFullyQualifiedTypeName(MangledName); + TP.IsTemplateTemplate = true; + TP.IsAliasTemplate = true; + TP.ParamName = demangleFullyQualifiedTypeName(MangledName); } else if (MangledName.consumeFront("$$B")) { // Array - (*Current)->ParamType = - demangleType(MangledName, QualifierMangleMode::Drop); + TP.ParamType = demangleType(MangledName, QualifierMangleMode::Drop); } else if (MangledName.consumeFront("$$C")) { // Type has qualifiers. - (*Current)->ParamType = - demangleType(MangledName, QualifierMangleMode::Mangle); - } else if (MangledName.startsWith("$1?")) { - MangledName.consumeFront("$1"); - // Pointer to symbol - Symbol *S = parse(MangledName); - (*Current)->ParamName = S->SymbolName; - (*Current)->ParamType = S->SymbolType; - (*Current)->PointerToSymbol = true; + TP.ParamType = demangleType(MangledName, QualifierMangleMode::Mangle); + } else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") || + MangledName.startsWith("$I") || MangledName.startsWith("$J")) { + MangledName = MangledName.dropFront(); + // 1 - single inheritance + // H - multiple inheritance + // I - virtual inheritance + // J - unspecified inheritance + char InheritanceSpecifier = MangledName.popFront(); + // Pointer to member + Symbol *S = MangledName.startsWith('?') ? parse(MangledName) : nullptr; + switch (InheritanceSpecifier) { + case 'J': + TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName); + LLVM_FALLTHROUGH; + case 'I': + TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName); + LLVM_FALLTHROUGH; + case 'H': + TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName); + LLVM_FALLTHROUGH; + case '1': + break; + default: + Error = true; + break; + } + TP.PointerToSymbol = true; + if (S) { + TP.ParamName = S->SymbolName; + TP.ParamType = S->SymbolType; + } else + TP.NullptrLiteral = true; } else if (MangledName.startsWith("$E?")) { MangledName.consumeFront("$E"); // Reference to symbol Symbol *S = parse(MangledName); - (*Current)->ParamName = S->SymbolName; - (*Current)->ParamType = S->SymbolType; - (*Current)->ReferenceToSymbol = true; + TP.ParamName = S->SymbolName; + TP.ParamType = S->SymbolType; + TP.ReferenceToSymbol = true; + } else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) { + // Data member pointer. + MangledName = MangledName.dropFront(); + char InheritanceSpecifier = MangledName.popFront(); + + switch (InheritanceSpecifier) { + case 'G': + TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName); + LLVM_FALLTHROUGH; + case 'F': + TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName); + TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName); + LLVM_FALLTHROUGH; + case '0': + break; + default: + Error = true; + break; + } + TP.DataMemberPointer = true; + } else if (MangledName.consumeFront("$0")) { // Integral non-type template parameter bool IsNegative = false; uint64_t Value = 0; std::tie(Value, IsNegative) = demangleNumber(MangledName); - (*Current)->IsIntegerLiteral = true; - (*Current)->IntegerLiteralIsNegative = IsNegative; - (*Current)->IntegralValue = Value; + TP.IsIntegerLiteral = true; + TP.IntegerLiteralIsNegative = IsNegative; + TP.IntegralValue = Value; } else { - (*Current)->ParamType = - demangleType(MangledName, QualifierMangleMode::Drop); + TP.ParamType = demangleType(MangledName, QualifierMangleMode::Drop); } if (Error) return nullptr; - Current = &(*Current)->Next; + Current = &TP.Next; } if (Error) diff --git a/test/Demangle/ms-templates-memptrs-2.test b/test/Demangle/ms-templates-memptrs-2.test new file mode 100644 index 00000000000..d06ea0399f2 --- /dev/null +++ b/test/Demangle/ms-templates-memptrs-2.test @@ -0,0 +1,31 @@ +; RUN: llvm-undname < %s | FileCheck %s + +; CHECK-NOT: Invalid mangled name + + +?m@@3U?$J@UM@@$0A@@@A +; CHECK: struct J m + +?m2@@3U?$K@UM@@$0?0@@A +; CHECK: struct K m2 + +?n@@3U?$J@UN@@$HA@@@A +; CHECK: struct J n + +?n2@@3U?$K@UN@@$0?0@@A +; CHECK: struct K n2 + +?o@@3U?$J@UO@@$IA@A@@@A +; CHECK: struct J o + +?o2@@3U?$K@UO@@$FA@?0@@A +; CHECK: struct K o2 + +?p@@3U?$J@UP@@$JA@A@?0@@A +; CHECK: struct J p + +?p2@@3U?$K@UP@@$GA@A@?0@@A +; CHECK: struct K p2 + +??0?$ClassTemplate@$J??_9MostGeneral@@$BA@AEA@M@3@@QAE@XZ +; CHECK: __thiscall ClassTemplate<{[thunk]: __thiscall MostGeneral::`vcall'{0, {flat}}, 0, 12, 4}>::ClassTemplate<{[thunk]: __thiscall MostGeneral::`vcall'{0, {flat}}, 0, 12, 4}>(void) \ No newline at end of file diff --git a/test/Demangle/ms-templates-memptrs.test b/test/Demangle/ms-templates-memptrs.test new file mode 100644 index 00000000000..3647a898871 --- /dev/null +++ b/test/Demangle/ms-templates-memptrs.test @@ -0,0 +1,95 @@ +; RUN: llvm-undname < %s | FileCheck %s + +; CHECK-NOT: Invalid mangled name + +; There's a back-referencing problem here +??$CallMethod@UC@NegativeNVOffset@@$I??_912@$BA@AEPPPPPPPM@A@@@YAXAAUC@NegativeNVOffset@@@Z +; FIXME: void __cdecl CallMethod(struct NegativeNVOffset::C &) + +??$CallMethod@UM@@$0A@@@YAXAAUM@@@Z +; CHECK: void __cdecl CallMethod(struct M &) + +??$CallMethod@UM@@$H??_91@$BA@AEA@@@YAXAAUM@@@Z +; FIXME: void __cdecl CallMethod(struct M &) + +??$CallMethod@UM@@$H?f@1@QAEXXZA@@@YAXAAUM@@@Z +; FIXME: void __cdecl CallMethod(struct M &) + +??$CallMethod@UO@@$H??_91@$BA@AE3@@YAXAAUO@@@Z +; FIXME: void __cdecl CallMethod(struct O &) + +??$CallMethod@US@@$0A@@@YAXAAUS@@@Z +; CHECK: void __cdecl CallMethod(struct S &) + +??$CallMethod@US@@$1??_91@$BA@AE@@YAXAAUS@@@Z +; CHECK: void __cdecl CallMethod(struct S &) + +??$CallMethod@US@@$1?f@1@QAEXXZ@@YAXAAUS@@@Z +; CHECK: void __cdecl CallMethod(struct S &) + +??$CallMethod@UU@@$0A@@@YAXAAUU@@@Z +; CHECK: void __cdecl CallMethod(struct U &) + +??$CallMethod@UU@@$J??_91@$BA@AEA@A@A@@@YAXAAUU@@@Z +; CHECK: void __cdecl CallMethod(struct U &) + +??$CallMethod@UU@@$J?f@1@QAEXXZA@A@A@@@YAXAAUU@@@Z +; CHECK: void __cdecl CallMethod(struct U &) + +??$CallMethod@UV@@$0A@@@YAXAAUV@@@Z +; CHECK: void __cdecl CallMethod(struct V &) + +??$CallMethod@UV@@$I??_91@$BA@AEA@A@@@YAXAAUV@@@Z +; CHECK: void __cdecl CallMethod(struct V &) + +??$CallMethod@UV@@$I?f@1@QAEXXZA@A@@@YAXAAUV@@@Z +; CHECK: void __cdecl CallMethod(struct V &) + +??$ReadField@UA@@$0?0@@YAHAAUA@@@Z +; CHECK: int __cdecl ReadField(struct A &) + +??$ReadField@UA@@$0A@@@YAHAAUA@@@Z +; CHECK: int __cdecl ReadField(struct A &) + +??$ReadField@UI@@$03@@YAHAAUI@@@Z +; CHECK: int __cdecl ReadField(struct I &) + +??$ReadField@UI@@$0A@@@YAHAAUI@@@Z +; CHECK: int __cdecl ReadField(struct I &) + +??$ReadField@UM@@$0A@@@YAHAAUM@@@Z +; CHECK: int __cdecl ReadField(struct M &) + +??$ReadField@UM@@$0BA@@@YAHAAUM@@@Z +; CHECK: int __cdecl ReadField(struct M &) + +??$ReadField@UM@@$0M@@@YAHAAUM@@@Z +; CHECK: int __cdecl ReadField(struct M &) + +??$ReadField@US@@$03@@YAHAAUS@@@Z +; CHECK: int __cdecl ReadField(struct S &) + +??$ReadField@US@@$07@@YAHAAUS@@@Z +; CHECK: int __cdecl ReadField(struct S &) + +??$ReadField@US@@$0A@@@YAHAAUS@@@Z +; CHECK: int __cdecl ReadField(struct S &) + +??$ReadField@UU@@$0A@@@YAHAAUU@@@Z +; CHECK: int __cdecl ReadField(struct U &) + +??$ReadField@UU@@$G3A@A@@@YAHAAUU@@@Z +; CHECK: int __cdecl ReadField(struct U &) + +??$ReadField@UU@@$G7A@A@@@YAHAAUU@@@Z +; CHECK: int __cdecl ReadField(struct U &) + +??$ReadField@UV@@$0A@@@YAHAAUV@@@Z +; CHECK: int __cdecl ReadField(struct V &) + +??$ReadField@UV@@$F7A@@@YAHAAUV@@@Z +; CHECK: int __cdecl ReadField(struct V &) + +??$ReadField@UV@@$FM@A@@@YAHAAUV@@@Z +; CHECK: int __cdecl ReadField(struct V &) + -- 2.11.0