Skip to content

Commit 66555a7

Browse files
author
Zachary Turner
committed
[MS Demangler] Demangle member pointer template parameters.
llvm-svn: 340199
1 parent 4876977 commit 66555a7

File tree

3 files changed

+270
-49
lines changed

3 files changed

+270
-49
lines changed

llvm/lib/Demangle/MicrosoftDemangle.cpp

Lines changed: 144 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "StringView.h"
2121
#include "Utility.h"
2222

23+
#include <array>
2324
#include <cctype>
2425
#include <cstdio>
2526
#include <tuple>
@@ -415,8 +416,13 @@ struct TemplateParams {
415416
bool IntegerLiteralIsNegative = false;
416417
bool IsEmptyParameterPack = false;
417418
bool PointerToSymbol = false;
419+
bool NullptrLiteral = false;
420+
bool DataMemberPointer = false;
418421
bool ReferenceToSymbol = false;
419422

423+
int ThunkOffsetCount = 0;
424+
std::array<int64_t, 3> ThunkOffsets;
425+
420426
// If IsIntegerLiteral is true, this is a non-type template parameter
421427
// whose value is contained in this field.
422428
uint64_t IntegralValue = 0;
@@ -794,11 +800,30 @@ static void outputParameterList(OutputStream &OS,
794800
OS << '-';
795801
OS << Head->IntegralValue;
796802
} else if (Head->PointerToSymbol || Head->ReferenceToSymbol) {
797-
if (Head->PointerToSymbol)
798-
OS << "&";
799-
Type::outputPre(OS, *Head->ParamType);
800-
outputName(OS, Head->ParamName, Head->ParamType);
801-
Type::outputPost(OS, *Head->ParamType);
803+
if (Head->NullptrLiteral)
804+
OS << "nullptr";
805+
else {
806+
if (Head->ThunkOffsetCount > 0)
807+
OS << "{";
808+
else if (Head->PointerToSymbol)
809+
OS << "&";
810+
if (Head->ParamType)
811+
Type::outputPre(OS, *Head->ParamType);
812+
outputName(OS, Head->ParamName, Head->ParamType);
813+
if (Head->ParamType)
814+
Type::outputPost(OS, *Head->ParamType);
815+
if (Head->ThunkOffsetCount > 0) {
816+
for (int I = 0; I < Head->ThunkOffsetCount; ++I) {
817+
OS << ", " << Head->ThunkOffsets[I];
818+
}
819+
OS << "}";
820+
}
821+
}
822+
} else if (Head->DataMemberPointer) {
823+
OS << "{" << Head->ThunkOffsets[0];
824+
for (int I = 1; I < Head->ThunkOffsetCount; ++I)
825+
OS << ", " << Head->ThunkOffsets[I];
826+
OS << "}";
802827
} else if (Head->ParamType) {
803828
// simple type.
804829
Type::outputPre(OS, *Head->ParamType);
@@ -840,12 +865,33 @@ static void outputNameComponent(OutputStream &OS, const Name &N) {
840865
outputParameterList(OS, *N.TParams);
841866
}
842867

868+
static const OperatorInfo *lastComponentAsOperator(const Name *TheName) {
869+
if (!TheName)
870+
return nullptr;
871+
while (TheName->Next)
872+
TheName = TheName->Next;
873+
if (TheName->IsOperator)
874+
return static_cast<const OperatorInfo *>(TheName);
875+
return nullptr;
876+
}
877+
843878
static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) {
844879
if (!TheName)
845880
return;
846881

847882
outputSpaceIfNecessary(OS);
848883

884+
const OperatorInfo *Operator = lastComponentAsOperator(TheName);
885+
const VirtualMemberPtrThunk *Thunk = nullptr;
886+
if (Operator) {
887+
if (Operator->Info->Operator == OperatorTy::Vcall) {
888+
Thunk = static_cast<const VirtualMemberPtrThunk *>(Operator);
889+
OS << "[thunk]: ";
890+
outputCallingConvention(OS, Thunk->CC);
891+
OS << " ";
892+
}
893+
}
894+
849895
const Name *Previous = nullptr;
850896
// Print out namespaces or outer class BackReferences.
851897
for (; TheName->Next; TheName = TheName->Next) {
@@ -860,10 +906,9 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) {
860906
return;
861907
}
862908

863-
const OperatorInfo &Operator = static_cast<const OperatorInfo &>(*TheName);
864909

865910
// Print out ctor or dtor.
866-
switch (Operator.Info->Operator) {
911+
switch (Operator->Info->Operator) {
867912
case OperatorTy::Dtor:
868913
OS << "~";
869914
LLVM_FALLTHROUGH;
@@ -884,43 +929,47 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) {
884929
}
885930
break;
886931
case OperatorTy::LiteralOperator:
887-
OS << Operator.Info->Name;
932+
OS << Operator->Info->Name;
888933
outputNameComponent(OS, *TheName);
889934
break;
890935
case OperatorTy::RttiBaseClassDescriptor: {
891936
const RttiBaseClassDescriptor &BCD =
892-
static_cast<const RttiBaseClassDescriptor &>(Operator);
893-
OS << "`" << Operator.Info->Name << " at (";
937+
static_cast<const RttiBaseClassDescriptor &>(*Operator);
938+
OS << "`" << Operator->Info->Name << " at (";
894939
OS << BCD.NVOffset << ", " << BCD.VBPtrOffset << ", " << BCD.VBTableOffset
895940
<< ", " << BCD.Flags;
896941
OS << ")'";
897942
break;
898943
}
944+
case OperatorTy::Vcall: {
945+
OS << "`vcall'{";
946+
OS << Thunk->OffsetInVTable << ", {flat}}";
947+
break;
948+
}
949+
899950
case OperatorTy::LocalStaticGuard: {
900951
const LocalStaticGuardVariable &LSG =
901-
static_cast<const LocalStaticGuardVariable &>(Operator);
902-
OS << Operator.Info->Name;
952+
static_cast<const LocalStaticGuardVariable &>(*Operator);
953+
OS << Operator->Info->Name;
903954
if (LSG.ScopeIndex > 0)
904955
OS << "{" << LSG.ScopeIndex << "}";
905956
break;
906957
}
907958
default:
908-
OS << Operator.Info->Name;
909-
if (Operator.IsTemplateInstantiation)
910-
outputParameterList(OS, *Operator.TParams);
959+
OS << Operator->Info->Name;
960+
if (Operator->IsTemplateInstantiation)
961+
outputParameterList(OS, *Operator->TParams);
911962
break;
912963
}
913964
}
914965

915966
static void outputSpecialOperator(OutputStream &OS, const Name *OuterName) {
916967
assert(OuterName);
917968
// The last component should be an operator.
918-
const Name *LastComponent = OuterName;
919-
while (LastComponent->Next)
920-
LastComponent = LastComponent->Next;
969+
const OperatorInfo *Operator = lastComponentAsOperator(OuterName);
921970

922-
assert(LastComponent->IsOperator);
923-
const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*LastComponent);
971+
assert(Operator->IsOperator);
972+
const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*Operator);
924973
switch (Oper.Info->Operator) {
925974
case OperatorTy::StringLiteral: {
926975
const StringLiteral &SL = static_cast<const StringLiteral &>(Oper);
@@ -1398,9 +1447,14 @@ Symbol *Demangler::parseOperator(StringView &MangledName) {
13981447
std::tie(OTy, S->SymbolName) = demangleOperatorName(MangledName, true);
13991448
switch (OTy) {
14001449
case OperatorTy::StringLiteral:
1401-
case OperatorTy::Vcall:
14021450
S->Category = SymbolCategory::SpecialOperator;
14031451
break;
1452+
case OperatorTy::Vcall:
1453+
S->Category = SymbolCategory::UnnamedFunction;
1454+
break;
1455+
case OperatorTy::LocalStaticGuard:
1456+
S->Category = SymbolCategory::UnnamedVariable;
1457+
break;
14041458
case OperatorTy::Vftable: // Foo@@6B@
14051459
case OperatorTy::LocalVftable: // Foo@@6B@
14061460
case OperatorTy::RttiCompleteObjLocator: // Foo@@6B@
@@ -1428,10 +1482,6 @@ Symbol *Demangler::parseOperator(StringView &MangledName) {
14281482
if (!MangledName.empty())
14291483
Error = true;
14301484
break;
1431-
case OperatorTy::LocalStaticGuard: {
1432-
S->Category = SymbolCategory::UnnamedVariable;
1433-
break;
1434-
}
14351485
default:
14361486
if (!Error)
14371487
std::tie(S->Category, S->SymbolType) =
@@ -2878,57 +2928,102 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
28782928
// Template parameter lists don't participate in back-referencing.
28792929
*Current = Arena.alloc<TemplateParams>();
28802930

2931+
TemplateParams &TP = **Current;
2932+
28812933
// Empty parameter pack.
28822934
if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") ||
28832935
MangledName.consumeFront("$$$V")) {
2884-
(*Current)->IsEmptyParameterPack = true;
2936+
TP.IsEmptyParameterPack = true;
28852937
break;
28862938
}
28872939

28882940
if (MangledName.consumeFront("$$Y")) {
28892941
// Template alias
2890-
(*Current)->IsTemplateTemplate = true;
2891-
(*Current)->IsAliasTemplate = true;
2892-
(*Current)->ParamName = demangleFullyQualifiedTypeName(MangledName);
2942+
TP.IsTemplateTemplate = true;
2943+
TP.IsAliasTemplate = true;
2944+
TP.ParamName = demangleFullyQualifiedTypeName(MangledName);
28932945
} else if (MangledName.consumeFront("$$B")) {
28942946
// Array
2895-
(*Current)->ParamType =
2896-
demangleType(MangledName, QualifierMangleMode::Drop);
2947+
TP.ParamType = demangleType(MangledName, QualifierMangleMode::Drop);
28972948
} else if (MangledName.consumeFront("$$C")) {
28982949
// Type has qualifiers.
2899-
(*Current)->ParamType =
2900-
demangleType(MangledName, QualifierMangleMode::Mangle);
2901-
} else if (MangledName.startsWith("$1?")) {
2902-
MangledName.consumeFront("$1");
2903-
// Pointer to symbol
2904-
Symbol *S = parse(MangledName);
2905-
(*Current)->ParamName = S->SymbolName;
2906-
(*Current)->ParamType = S->SymbolType;
2907-
(*Current)->PointerToSymbol = true;
2950+
TP.ParamType = demangleType(MangledName, QualifierMangleMode::Mangle);
2951+
} else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") ||
2952+
MangledName.startsWith("$I") || MangledName.startsWith("$J")) {
2953+
MangledName = MangledName.dropFront();
2954+
// 1 - single inheritance <name>
2955+
// H - multiple inheritance <name> <number>
2956+
// I - virtual inheritance <name> <number> <number> <number>
2957+
// J - unspecified inheritance <name> <number> <number> <number>
2958+
char InheritanceSpecifier = MangledName.popFront();
2959+
// Pointer to member
2960+
Symbol *S = MangledName.startsWith('?') ? parse(MangledName) : nullptr;
2961+
switch (InheritanceSpecifier) {
2962+
case 'J':
2963+
TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
2964+
LLVM_FALLTHROUGH;
2965+
case 'I':
2966+
TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
2967+
LLVM_FALLTHROUGH;
2968+
case 'H':
2969+
TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
2970+
LLVM_FALLTHROUGH;
2971+
case '1':
2972+
break;
2973+
default:
2974+
Error = true;
2975+
break;
2976+
}
2977+
TP.PointerToSymbol = true;
2978+
if (S) {
2979+
TP.ParamName = S->SymbolName;
2980+
TP.ParamType = S->SymbolType;
2981+
} else
2982+
TP.NullptrLiteral = true;
29082983
} else if (MangledName.startsWith("$E?")) {
29092984
MangledName.consumeFront("$E");
29102985
// Reference to symbol
29112986
Symbol *S = parse(MangledName);
2912-
(*Current)->ParamName = S->SymbolName;
2913-
(*Current)->ParamType = S->SymbolType;
2914-
(*Current)->ReferenceToSymbol = true;
2987+
TP.ParamName = S->SymbolName;
2988+
TP.ParamType = S->SymbolType;
2989+
TP.ReferenceToSymbol = true;
2990+
} else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) {
2991+
// Data member pointer.
2992+
MangledName = MangledName.dropFront();
2993+
char InheritanceSpecifier = MangledName.popFront();
2994+
2995+
switch (InheritanceSpecifier) {
2996+
case 'G':
2997+
TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
2998+
LLVM_FALLTHROUGH;
2999+
case 'F':
3000+
TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
3001+
TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
3002+
LLVM_FALLTHROUGH;
3003+
case '0':
3004+
break;
3005+
default:
3006+
Error = true;
3007+
break;
3008+
}
3009+
TP.DataMemberPointer = true;
3010+
29153011
} else if (MangledName.consumeFront("$0")) {
29163012
// Integral non-type template parameter
29173013
bool IsNegative = false;
29183014
uint64_t Value = 0;
29193015
std::tie(Value, IsNegative) = demangleNumber(MangledName);
29203016

2921-
(*Current)->IsIntegerLiteral = true;
2922-
(*Current)->IntegerLiteralIsNegative = IsNegative;
2923-
(*Current)->IntegralValue = Value;
3017+
TP.IsIntegerLiteral = true;
3018+
TP.IntegerLiteralIsNegative = IsNegative;
3019+
TP.IntegralValue = Value;
29243020
} else {
2925-
(*Current)->ParamType =
2926-
demangleType(MangledName, QualifierMangleMode::Drop);
3021+
TP.ParamType = demangleType(MangledName, QualifierMangleMode::Drop);
29273022
}
29283023
if (Error)
29293024
return nullptr;
29303025

2931-
Current = &(*Current)->Next;
3026+
Current = &TP.Next;
29323027
}
29333028

29343029
if (Error)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; RUN: llvm-undname < %s | FileCheck %s
2+
3+
; CHECK-NOT: Invalid mangled name
4+
5+
6+
?m@@3U?$J@UM@@$0A@@@A
7+
; CHECK: struct J<struct M, 0> m
8+
9+
?m2@@3U?$K@UM@@$0?0@@A
10+
; CHECK: struct K<struct M, -1> m2
11+
12+
?n@@3U?$J@UN@@$HA@@@A
13+
; CHECK: struct J<struct N, nullptr> n
14+
15+
?n2@@3U?$K@UN@@$0?0@@A
16+
; CHECK: struct K<struct N, -1> n2
17+
18+
?o@@3U?$J@UO@@$IA@A@@@A
19+
; CHECK: struct J<struct O, nullptr> o
20+
21+
?o2@@3U?$K@UO@@$FA@?0@@A
22+
; CHECK: struct K<struct O, {0, -1}> o2
23+
24+
?p@@3U?$J@UP@@$JA@A@?0@@A
25+
; CHECK: struct J<struct P, nullptr> p
26+
27+
?p2@@3U?$K@UP@@$GA@A@?0@@A
28+
; CHECK: struct K<struct P, {0, 0, -1}> p2
29+
30+
??0?$ClassTemplate@$J??_9MostGeneral@@$BA@AEA@M@3@@QAE@XZ
31+
; CHECK: __thiscall ClassTemplate<{[thunk]: __thiscall MostGeneral::`vcall'{0, {flat}}, 0, 12, 4}>::ClassTemplate<{[thunk]: __thiscall MostGeneral::`vcall'{0, {flat}}, 0, 12, 4}>(void)

0 commit comments

Comments
 (0)