diff options
-rw-r--r-- | llvm/lib/Demangle/MicrosoftDemangle.cpp | 193 | ||||
-rw-r--r-- | llvm/test/Demangle/ms-templates-memptrs-2.test | 31 | ||||
-rw-r--r-- | llvm/test/Demangle/ms-templates-memptrs.test | 95 |
3 files changed, 270 insertions, 49 deletions
diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp index 6f382098b27..58678e9f908 100644 --- a/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -20,6 +20,7 @@ #include "StringView.h" #include "Utility.h" +#include <array> #include <cctype> #include <cstdio> #include <tuple> @@ -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<int64_t, 3> 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<const OperatorInfo *>(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<const VirtualMemberPtrThunk *>(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<const OperatorInfo &>(*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<const RttiBaseClassDescriptor &>(Operator); - OS << "`" << Operator.Info->Name << " at ("; + static_cast<const RttiBaseClassDescriptor &>(*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<const LocalStaticGuardVariable &>(Operator); - OS << Operator.Info->Name; + static_cast<const LocalStaticGuardVariable &>(*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<const OperatorInfo &>(*LastComponent); + assert(Operator->IsOperator); + const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*Operator); switch (Oper.Info->Operator) { case OperatorTy::StringLiteral: { const StringLiteral &SL = static_cast<const StringLiteral &>(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>(); + 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 <name> + // H - multiple inheritance <name> <number> + // I - virtual inheritance <name> <number> <number> <number> + // J - unspecified inheritance <name> <number> <number> <number> + 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/llvm/test/Demangle/ms-templates-memptrs-2.test b/llvm/test/Demangle/ms-templates-memptrs-2.test new file mode 100644 index 00000000000..d06ea0399f2 --- /dev/null +++ b/llvm/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<struct M, 0> m + +?m2@@3U?$K@UM@@$0?0@@A +; CHECK: struct K<struct M, -1> m2 + +?n@@3U?$J@UN@@$HA@@@A +; CHECK: struct J<struct N, nullptr> n + +?n2@@3U?$K@UN@@$0?0@@A +; CHECK: struct K<struct N, -1> n2 + +?o@@3U?$J@UO@@$IA@A@@@A +; CHECK: struct J<struct O, nullptr> o + +?o2@@3U?$K@UO@@$FA@?0@@A +; CHECK: struct K<struct O, {0, -1}> o2 + +?p@@3U?$J@UP@@$JA@A@?0@@A +; CHECK: struct J<struct P, nullptr> p + +?p2@@3U?$K@UP@@$GA@A@?0@@A +; CHECK: struct K<struct P, {0, 0, -1}> 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/llvm/test/Demangle/ms-templates-memptrs.test b/llvm/test/Demangle/ms-templates-memptrs.test new file mode 100644 index 00000000000..3647a898871 --- /dev/null +++ b/llvm/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, {[thunk]: __thiscall NegativeNVOffset::C::`vcall'{0, {flat}}, 4294967292, 0}>(struct NegativeNVOffset::C &) + +??$CallMethod@UM@@$0A@@@YAXAAUM@@@Z +; CHECK: void __cdecl CallMethod<struct M, 0>(struct M &) + +??$CallMethod@UM@@$H??_91@$BA@AEA@@@YAXAAUM@@@Z +; FIXME: void __cdecl CallMethod<struct M, {[thunk]: __thiscall M::`vcall'{0, {flat}}', 0}>(struct M &) + +??$CallMethod@UM@@$H?f@1@QAEXXZA@@@YAXAAUM@@@Z +; FIXME: void __cdecl CallMethod<struct M, {void __thiscall M::f(void), 0}>(struct M &) + +??$CallMethod@UO@@$H??_91@$BA@AE3@@YAXAAUO@@@Z +; FIXME: void __cdecl CallMethod<struct O, {[thunk]: __thiscall O::`vcall'{0, {flat}}, 4}>(struct O &) + +??$CallMethod@US@@$0A@@@YAXAAUS@@@Z +; CHECK: void __cdecl CallMethod<struct S, 0>(struct S &) + +??$CallMethod@US@@$1??_91@$BA@AE@@YAXAAUS@@@Z +; CHECK: void __cdecl CallMethod<struct S, &[thunk]: __thiscall S::`vcall'{0, {flat}}>(struct S &) + +??$CallMethod@US@@$1?f@1@QAEXXZ@@YAXAAUS@@@Z +; CHECK: void __cdecl CallMethod<struct S, &void __thiscall S::f(void)>(struct S &) + +??$CallMethod@UU@@$0A@@@YAXAAUU@@@Z +; CHECK: void __cdecl CallMethod<struct U, 0>(struct U &) + +??$CallMethod@UU@@$J??_91@$BA@AEA@A@A@@@YAXAAUU@@@Z +; CHECK: void __cdecl CallMethod<struct U, {[thunk]: __thiscall U::`vcall'{0, {flat}}, 0, 0, 0}>(struct U &) + +??$CallMethod@UU@@$J?f@1@QAEXXZA@A@A@@@YAXAAUU@@@Z +; CHECK: void __cdecl CallMethod<struct U, {void __thiscall U::f(void), 0, 0, 0}>(struct U &) + +??$CallMethod@UV@@$0A@@@YAXAAUV@@@Z +; CHECK: void __cdecl CallMethod<struct V, 0>(struct V &) + +??$CallMethod@UV@@$I??_91@$BA@AEA@A@@@YAXAAUV@@@Z +; CHECK: void __cdecl CallMethod<struct V, {[thunk]: __thiscall V::`vcall'{0, {flat}}, 0, 0}>(struct V &) + +??$CallMethod@UV@@$I?f@1@QAEXXZA@A@@@YAXAAUV@@@Z +; CHECK: void __cdecl CallMethod<struct V, {void __thiscall V::f(void), 0, 0}>(struct V &) + +??$ReadField@UA@@$0?0@@YAHAAUA@@@Z +; CHECK: int __cdecl ReadField<struct A, -1>(struct A &) + +??$ReadField@UA@@$0A@@@YAHAAUA@@@Z +; CHECK: int __cdecl ReadField<struct A, 0>(struct A &) + +??$ReadField@UI@@$03@@YAHAAUI@@@Z +; CHECK: int __cdecl ReadField<struct I, 4>(struct I &) + +??$ReadField@UI@@$0A@@@YAHAAUI@@@Z +; CHECK: int __cdecl ReadField<struct I, 0>(struct I &) + +??$ReadField@UM@@$0A@@@YAHAAUM@@@Z +; CHECK: int __cdecl ReadField<struct M, 0>(struct M &) + +??$ReadField@UM@@$0BA@@@YAHAAUM@@@Z +; CHECK: int __cdecl ReadField<struct M, 16>(struct M &) + +??$ReadField@UM@@$0M@@@YAHAAUM@@@Z +; CHECK: int __cdecl ReadField<struct M, 12>(struct M &) + +??$ReadField@US@@$03@@YAHAAUS@@@Z +; CHECK: int __cdecl ReadField<struct S, 4>(struct S &) + +??$ReadField@US@@$07@@YAHAAUS@@@Z +; CHECK: int __cdecl ReadField<struct S, 8>(struct S &) + +??$ReadField@US@@$0A@@@YAHAAUS@@@Z +; CHECK: int __cdecl ReadField<struct S, 0>(struct S &) + +??$ReadField@UU@@$0A@@@YAHAAUU@@@Z +; CHECK: int __cdecl ReadField<struct U, 0>(struct U &) + +??$ReadField@UU@@$G3A@A@@@YAHAAUU@@@Z +; CHECK: int __cdecl ReadField<struct U, {4, 0, 0}>(struct U &) + +??$ReadField@UU@@$G7A@A@@@YAHAAUU@@@Z +; CHECK: int __cdecl ReadField<struct U, {8, 0, 0}>(struct U &) + +??$ReadField@UV@@$0A@@@YAHAAUV@@@Z +; CHECK: int __cdecl ReadField<struct V, 0>(struct V &) + +??$ReadField@UV@@$F7A@@@YAHAAUV@@@Z +; CHECK: int __cdecl ReadField<struct V, {8, 0}>(struct V &) + +??$ReadField@UV@@$FM@A@@@YAHAAUV@@@Z +; CHECK: int __cdecl ReadField<struct V, {12, 0}>(struct V &) + |