[MS Demangler] Demangle all remaining types of operators.

This demangles all remaining special operators including thunks,
RTTI Descriptors, and local static guard variables.

llvm-svn: 340083
This commit is contained in:
Zachary Turner 2018-08-17 21:18:05 +00:00
parent 3820f582eb
commit 469f076356
2 changed files with 416 additions and 138 deletions

View File

@ -282,6 +282,8 @@ struct OperatorMapEntry {
OperatorTy Operator;
};
// The entries here must be in the same order as the enumeration so that it can
// be indexed by enum value.
OperatorMapEntry OperatorMap[] = {
{"0", " <ctor>", OperatorTy::Ctor},
{"1", " <dtor>", OperatorTy::Dtor},
@ -347,8 +349,7 @@ OperatorMapEntry OperatorMap[] = {
{"_P", "`udt returning'", OperatorTy::UdtReturning},
{"_Q", "`unknown'", OperatorTy::Unknown},
{"_R0", "`RTTI Type Descriptor'", OperatorTy::RttiTypeDescriptor},
{"_R1", "`RTTI Base Class Descriptor'",
OperatorTy::RttiBaseClassDescriptor},
{"_R1", "RTTI Base Class Descriptor", OperatorTy::RttiBaseClassDescriptor},
{"_R2", "`RTTI Base Class Array'", OperatorTy::RttiBaseClassArray},
{"_R3", "`RTTI Class Hierarchy Descriptor'",
OperatorTy::RttiClassHierarchyDescriptor},
@ -364,6 +365,7 @@ OperatorMapEntry OperatorMap[] = {
// Function classes
enum FuncClass : uint16_t {
None = 0,
Public = 1 << 0,
Protected = 1 << 1,
Private = 1 << 2,
@ -373,6 +375,9 @@ enum FuncClass : uint16_t {
Far = 1 << 6,
ExternC = 1 << 7,
NoPrototype = 1 << 8,
VirtualThisAdjust = 1 << 9,
VirtualThisAdjustEx = 1 << 10,
StaticThisAdjust = 1 << 11
};
enum NameBackrefBehavior : uint8_t {
@ -381,7 +386,14 @@ enum NameBackrefBehavior : uint8_t {
NBB_Simple = 1 << 1, // save simple names.
};
enum class SymbolCategory { Unknown, Function, Variable };
enum class SymbolCategory {
Unknown,
NamedFunction,
NamedVariable,
UnnamedFunction,
UnnamedVariable,
SpecialOperator
};
namespace {
@ -474,14 +486,46 @@ struct Name {
};
struct OperatorInfo : public Name {
explicit OperatorInfo(const OperatorMapEntry &Info) : Info(&Info) {
this->IsOperator = true;
}
explicit OperatorInfo(OperatorTy OpType)
: OperatorInfo(OperatorMap[(int)OpType]) {}
const OperatorMapEntry *Info = nullptr;
};
struct StringLiteral : public OperatorInfo {
StringLiteral() : OperatorInfo(OperatorTy::StringLiteral) {}
PrimTy CharType;
bool IsTruncated = false;
};
struct RttiBaseClassDescriptor : public OperatorInfo {
RttiBaseClassDescriptor()
: OperatorInfo(OperatorTy::RttiBaseClassDescriptor) {}
uint32_t NVOffset = 0;
int32_t VBPtrOffset = 0;
uint32_t VBTableOffset = 0;
uint32_t Flags = 0;
};
struct LocalStaticGuardVariable : public OperatorInfo {
LocalStaticGuardVariable() : OperatorInfo(OperatorTy::LocalStaticGuard) {}
uint32_t ScopeIndex = 0;
bool IsVisible = false;
};
struct VirtualMemberPtrThunk : public OperatorInfo {
VirtualMemberPtrThunk() : OperatorInfo(OperatorTy::Vcall) {}
uint64_t OffsetInVTable = 0;
CallingConv CC = CallingConv::Cdecl;
};
struct PointerType : public Type {
Type *clone(ArenaAllocator &Arena) const override;
void outputPre(OutputStream &OS, NameResolver &Resolver) override;
@ -507,6 +551,13 @@ struct MemberPointerType : public Type {
};
struct FunctionType : public Type {
struct ThisAdjustor {
uint32_t StaticOffset = 0;
int32_t VBPtrOffset = 0;
int32_t VBOffsetOffset = 0;
int32_t VtordispOffset = 0;
};
Type *clone(ArenaAllocator &Arena) const override;
void outputPre(OutputStream &OS, NameResolver &Resolver) override;
void outputPost(OutputStream &OS, NameResolver &Resolver) override;
@ -514,6 +565,7 @@ struct FunctionType : public Type {
// True if this FunctionType instance is the Pointee of a PointerType or
// MemberPointerType.
bool IsFunctionPointer = false;
bool IsThunk = false;
Type *ReturnType = nullptr;
// If this is a reference, the type of reference.
@ -522,6 +574,9 @@ struct FunctionType : public Type {
CallingConv CallConvention;
FuncClass FunctionClass;
// Valid if IsThunk is true.
ThisAdjustor *ThisAdjust = nullptr;
FunctionParams Params;
};
@ -767,6 +822,23 @@ static void outputParameterList(OutputStream &OS, const TemplateParams &Params,
OS << ">";
}
static void outputQualifiers(OutputStream &OS, Qualifiers Q) {
if (Q & Q_Const) {
outputSpaceIfNecessary(OS);
OS << "const";
}
if (Q & Q_Volatile) {
outputSpaceIfNecessary(OS);
OS << "volatile";
}
if (Q & Q_Restrict) {
outputSpaceIfNecessary(OS);
OS << "__restrict";
}
}
static void outputNameComponent(OutputStream &OS, bool IsBackReference,
const TemplateParams *TParams, StringView Str,
NameResolver &Resolver) {
@ -827,15 +899,27 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty,
OS << "<conversion>";
}
break;
case OperatorTy::StringLiteral: {
const StringLiteral &SL = static_cast<const StringLiteral &>(Operator);
outputStringLiteral(OS, SL);
break;
}
case OperatorTy::LiteralOperator:
OS << Operator.Info->Name;
outputNameComponent(OS, *TheName, Resolver);
break;
case OperatorTy::RttiBaseClassDescriptor: {
const RttiBaseClassDescriptor &BCD =
static_cast<const RttiBaseClassDescriptor &>(Operator);
OS << "`" << Operator.Info->Name << " at (";
OS << BCD.NVOffset << ", " << BCD.VBPtrOffset << ", " << BCD.VBTableOffset
<< ", " << BCD.Flags;
OS << ")'";
break;
}
case OperatorTy::LocalStaticGuard: {
const LocalStaticGuardVariable &LSG =
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)
@ -844,6 +928,45 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty,
}
}
static void outputSpecialOperator(OutputStream &OS, const Name *OuterName,
NameResolver &Resolver) {
assert(OuterName);
// The last component should be an operator.
const Name *LastComponent = OuterName;
while (LastComponent->Next)
LastComponent = LastComponent->Next;
assert(LastComponent->IsOperator);
const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*LastComponent);
switch (Oper.Info->Operator) {
case OperatorTy::StringLiteral: {
const StringLiteral &SL = static_cast<const StringLiteral &>(Oper);
outputStringLiteral(OS, SL);
break;
}
case OperatorTy::Vcall: {
// [thunk]: __cdecl Base::`vcall'{8, {flat}}' }'
const VirtualMemberPtrThunk &Thunk =
static_cast<const VirtualMemberPtrThunk &>(Oper);
OS << "[thunk]: ";
outputCallingConvention(OS, Thunk.CC);
OS << " ";
// Print out namespaces or outer class BackReferences.
const Name *N = OuterName;
for (; N->Next; N = N->Next) {
outputNameComponent(OS, *N, Resolver);
OS << "::";
}
OS << "`vcall'{";
OS << Thunk.OffsetInVTable << ", {flat}}";
break;
}
default:
// There are no other special operator categories.
LLVM_BUILTIN_UNREACHABLE;
}
}
namespace {
bool Name::isStringLiteralOperatorInfo() const {
@ -877,20 +1000,7 @@ void Type::outputPre(OutputStream &OS, Type &Ty, NameResolver &Resolver) {
}
Ty.outputPre(OS, Resolver);
if (Ty.Quals & Q_Const) {
outputSpaceIfNecessary(OS);
OS << "const";
}
if (Ty.Quals & Q_Volatile) {
outputSpaceIfNecessary(OS);
OS << "volatile";
}
if (Ty.Quals & Q_Restrict) {
outputSpaceIfNecessary(OS);
OS << "__restrict";
}
outputQualifiers(OS, Ty.Quals);
}
// Write the "second half" of a given type.
@ -1054,6 +1164,9 @@ Type *FunctionType::clone(ArenaAllocator &Arena) const {
}
void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) {
if ((FunctionClass & StaticThisAdjust) || (FunctionClass & VirtualThisAdjust))
OS << "[thunk]: ";
if (!(FunctionClass & Global)) {
if (FunctionClass & Static)
OS << "static ";
@ -1081,6 +1194,11 @@ void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) {
if (FunctionClass & NoPrototype)
return;
if (FunctionClass & VirtualThisAdjust) {
OS << "`vtordisp{" << ThisAdjust->VtordispOffset << ", "
<< ThisAdjust->StaticOffset << "}'";
}
OS << "(";
outputParameterList(OS, Params, Resolver);
OS << ")";
@ -1152,6 +1270,7 @@ void ArrayType::outputPost(OutputStream &OS, NameResolver &Resolver) {
struct Symbol {
SymbolCategory Category;
Qualifiers SymbolQuals = Q_None;
Name *SymbolName = nullptr;
Type *SymbolType = nullptr;
};
@ -1183,6 +1302,8 @@ public:
// You are supposed to call parse() first and then check if error is true. If
// it is false, call output() to write the formatted name to the given stream.
Symbol *parse(StringView &MangledName);
Symbol *parseOperator(StringView &MangledName);
void output(const Symbol *S, OutputStream &OS);
StringView resolve(StringView N) override;
@ -1193,9 +1314,12 @@ public:
void dumpBackReferences();
private:
Type *demangleVariableEncoding(StringView &MangledName);
std::pair<SymbolCategory, Type *>
demangleSymbolCategoryAndType(StringView &MangledName);
Type *demangleVariableEncoding(StringView &MangledName, StorageClass SC);
Type *demangleFunctionEncoding(StringView &MangledName);
Type *demangleVtableEncoding(StringView &MangledName);
uint64_t demangleThunkThisAdjust(StringView &MangledName);
Qualifiers demanglePointerExtQualifiers(StringView &MangledName);
@ -1214,6 +1338,8 @@ private:
FunctionParams demangleFunctionParameterList(StringView &MangledName);
std::pair<uint64_t, bool> demangleNumber(StringView &MangledName);
uint64_t demangleUnsigned(StringView &MangledName);
int64_t demangleSigned(StringView &MangledName);
void memorizeString(StringView s);
@ -1233,7 +1359,8 @@ private:
Name *demangleBackRefName(StringView &MangledName);
Name *demangleTemplateInstantiationName(StringView &MangledName,
NameBackrefBehavior NBB);
OperatorInfo *demangleOperatorName(StringView &MangledName);
std::pair<OperatorTy, Name *> demangleOperatorName(StringView &MangledName,
bool FullyQualified);
Name *demangleSimpleName(StringView &MangledName, bool Memorize);
Name *demangleAnonymousNamespaceName(StringView &MangledName);
Name *demangleLocallyScopedNamePiece(StringView &MangledName);
@ -1278,12 +1405,86 @@ StringView Demangler::copyString(StringView Borrowed) {
return {Stable, Borrowed.size()};
}
// Parser entry point.
Symbol *Demangler::parse(StringView &MangledName) {
Symbol *Demangler::parseOperator(StringView &MangledName) {
Symbol *S = Arena.alloc<Symbol>();
bool IsMember = false;
OperatorTy OTy;
std::tie(OTy, S->SymbolName) = demangleOperatorName(MangledName, true);
switch (OTy) {
case OperatorTy::StringLiteral:
case OperatorTy::Vcall:
S->Category = SymbolCategory::SpecialOperator;
break;
case OperatorTy::Vftable: // Foo@@6B@
case OperatorTy::LocalVftable: // Foo@@6B@
case OperatorTy::RttiCompleteObjLocator: // Foo@@6B@
case OperatorTy::Vbtable: // Foo@@7B@
S->Category = SymbolCategory::UnnamedVariable;
switch (MangledName.popFront()) {
case '6':
case '7':
std::tie(S->SymbolQuals, IsMember) = demangleQualifiers(MangledName);
if (!MangledName.consumeFront('@'))
Error = true;
break;
default:
Error = true;
break;
}
break;
case OperatorTy::RttiTypeDescriptor: // <type>@@8
S->Category = SymbolCategory::UnnamedVariable;
S->SymbolType = demangleType(MangledName, QualifierMangleMode::Result);
if (Error)
break;
if (!MangledName.consumeFront("@8"))
Error = true;
if (!MangledName.empty())
Error = true;
break;
case OperatorTy::LocalStaticGuard: {
S->Category = SymbolCategory::UnnamedVariable;
break;
}
default:
if (!Error)
std::tie(S->Category, S->SymbolType) =
demangleSymbolCategoryAndType(MangledName);
break;
}
return (Error) ? nullptr : S;
}
std::pair<SymbolCategory, Type *>
Demangler::demangleSymbolCategoryAndType(StringView &MangledName) {
// Read a variable.
switch (MangledName.front()) {
case '0':
case '1':
case '2':
case '3':
case '4':
return std::make_pair(
SymbolCategory::NamedVariable,
demangleVariableEncoding(MangledName,
demangleVariableStorageClass(MangledName)));
case '8':
MangledName.consumeFront('8');
return std::pair<SymbolCategory, Type *>(SymbolCategory::UnnamedVariable,
nullptr);
}
return std::make_pair(SymbolCategory::NamedFunction,
demangleFunctionEncoding(MangledName));
}
// Parser entry point.
Symbol *Demangler::parse(StringView &MangledName) {
// We can't demangle MD5 names, just output them as-is.
if (MangledName.startsWith("??@")) {
// Also, MSVC-style mangled symbols must start with '?'.
if (MangledName.startsWith("??@") || !MangledName.startsWith('?')) {
Symbol *S = Arena.alloc<Symbol>();
S->Category = SymbolCategory::Unknown;
S->SymbolName = Arena.alloc<Name>();
S->SymbolName->Str = MangledName;
@ -1292,43 +1493,22 @@ Symbol *Demangler::parse(StringView &MangledName) {
return S;
}
// MSVC-style mangled symbols must start with '?'.
if (!MangledName.consumeFront("?")) {
S->Category = SymbolCategory::Unknown;
S->SymbolName = Arena.alloc<Name>();
S->SymbolName->Str = MangledName;
S->SymbolType = nullptr;
return S;
}
MangledName.consumeFront('?');
// What follows is a main symbol name. This may include
// namespaces or class BackReferences.
// ?$ is a template instantiation, but all other names that start with ? are
// operators / special names.
if (MangledName.startsWith('?') && !MangledName.startsWith("?$"))
return parseOperator(MangledName);
Symbol *S = Arena.alloc<Symbol>();
// What follows is a main symbol name. This may include namespaces or class
// back references.
S->SymbolName = demangleFullyQualifiedSymbolName(MangledName);
if (Error)
return nullptr;
if (S->SymbolName->isStringLiteralOperatorInfo())
return S;
// Read a variable.
switch (MangledName.front()) {
case '0':
case '1':
case '2':
case '3':
case '4':
S->Category = SymbolCategory::Variable;
S->SymbolType = demangleVariableEncoding(MangledName);
break;
case '6':
case '7':
S->Category = SymbolCategory::Variable;
S->SymbolType = demangleVtableEncoding(MangledName);
break;
default:
S->Category = SymbolCategory::Function;
S->SymbolType = demangleFunctionEncoding(MangledName);
}
std::tie(S->Category, S->SymbolType) =
demangleSymbolCategoryAndType(MangledName);
if (Error)
return nullptr;
@ -1336,23 +1516,6 @@ Symbol *Demangler::parse(StringView &MangledName) {
return S;
}
Type *Demangler::demangleVtableEncoding(StringView &MangledName) {
Type *Ty = Arena.alloc<Type>();
switch (MangledName.popFront()) {
case '6':
Ty->Prim = PrimTy::Vftable;
break;
case '7':
Ty->Prim = PrimTy::Vbtable;
break;
}
bool IsMember = false;
std::tie(Ty->Quals, IsMember) = demangleQualifiers(MangledName);
Ty->Storage = StorageClass::None;
MangledName.consumeFront('@');
return Ty;
}
// <type-encoding> ::= <storage-class> <variable-type>
// <storage-class> ::= 0 # private static member
// ::= 1 # protected static member
@ -1360,9 +1523,8 @@ Type *Demangler::demangleVtableEncoding(StringView &MangledName) {
// ::= 3 # global
// ::= 4 # static local
Type *Demangler::demangleVariableEncoding(StringView &MangledName) {
StorageClass SC = demangleVariableStorageClass(MangledName);
Type *Demangler::demangleVariableEncoding(StringView &MangledName,
StorageClass SC) {
Type *Ty = demangleType(MangledName, QualifierMangleMode::Drop);
Ty->Storage = SC;
@ -1438,6 +1600,25 @@ std::pair<uint64_t, bool> Demangler::demangleNumber(StringView &MangledName) {
return {0ULL, false};
}
uint64_t Demangler::demangleUnsigned(StringView &MangledName) {
bool IsNegative = false;
uint64_t Number = 0;
std::tie(Number, IsNegative) = demangleNumber(MangledName);
if (IsNegative)
Error = true;
return Number;
}
int64_t Demangler::demangleSigned(StringView &MangledName) {
bool IsNegative = false;
uint64_t Number = 0;
std::tie(Number, IsNegative) = demangleNumber(MangledName);
if (Number > INT64_MAX)
Error = true;
int64_t I = static_cast<int64_t>(Number);
return IsNegative ? -I : I;
}
// First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9.
// Memorize it.
void Demangler::memorizeString(StringView S) {
@ -1492,7 +1673,8 @@ Name *Demangler::demangleTemplateInstantiationName(StringView &MangledName,
return Node;
}
OperatorInfo *Demangler::demangleOperatorName(StringView &MangledName) {
std::pair<OperatorTy, Name *>
Demangler::demangleOperatorName(StringView &MangledName, bool FullyQualified) {
assert(MangledName.startsWith('?'));
MangledName.consumeFront('?');
@ -1505,28 +1687,77 @@ OperatorInfo *Demangler::demangleOperatorName(StringView &MangledName) {
}
if (!Entry) {
Error = true;
return nullptr;
return std::make_pair(OperatorTy::Unknown, nullptr);
}
OperatorInfo *Oper = nullptr;
Name *N = nullptr;
switch (Entry->Operator) {
case OperatorTy::Vftable: // Foo@@6B@
case OperatorTy::LocalVftable: // Foo@@6B@
case OperatorTy::RttiCompleteObjLocator: // Foo@@6B@
case OperatorTy::Vbtable: { // Foo@@7B@
OperatorInfo *Oper = Arena.alloc<OperatorInfo>(*Entry);
N = (FullyQualified) ? demangleNameScopeChain(MangledName, Oper) : Oper;
break;
}
case OperatorTy::StringLiteral:
Oper = demangleStringLiteral(MangledName);
N = demangleStringLiteral(MangledName);
break;
case OperatorTy::LiteralOperator:
Oper = Arena.alloc<OperatorInfo>();
Oper->Str = demangleSimpleString(MangledName, false);
N = Arena.alloc<OperatorInfo>(*Entry);
N->Str = demangleSimpleString(MangledName, false);
if (!MangledName.consumeFront('@'))
Error = true;
break;
case OperatorTy::RttiBaseClassDescriptor: {
RttiBaseClassDescriptor *Temp = Arena.alloc<RttiBaseClassDescriptor>();
Temp->NVOffset = demangleUnsigned(MangledName);
Temp->VBPtrOffset = demangleSigned(MangledName);
Temp->VBTableOffset = demangleUnsigned(MangledName);
Temp->Flags = demangleUnsigned(MangledName);
N = (FullyQualified) ? demangleNameScopeChain(MangledName, Temp) : Temp;
break;
}
case OperatorTy::Vcall: {
VirtualMemberPtrThunk *Temp = Arena.alloc<VirtualMemberPtrThunk>();
N = demangleNameScopeChain(MangledName, Temp);
if (Error)
break;
if (!MangledName.consumeFront("$B"))
Error = true;
Temp->OffsetInVTable = demangleUnsigned(MangledName);
if (!MangledName.consumeFront('A'))
Error = true;
Temp->CC = demangleCallingConvention(MangledName);
break;
}
case OperatorTy::RttiTypeDescriptor:
// This one is just followed by a type, not a name scope.
N = Arena.alloc<OperatorInfo>(*Entry);
break;
case OperatorTy::LocalStaticGuard: {
LocalStaticGuardVariable *Temp = Arena.alloc<LocalStaticGuardVariable>();
N = (FullyQualified) ? demangleNameScopeChain(MangledName, Temp) : Temp;
if (MangledName.consumeFront("4IA"))
Temp->IsVisible = false;
else if (MangledName.consumeFront("5"))
Temp->IsVisible = true;
else
Error = true;
if (!MangledName.empty())
Temp->ScopeIndex = demangleUnsigned(MangledName);
break;
}
default:
N = Arena.alloc<OperatorInfo>(*Entry);
N = (FullyQualified) ? demangleNameScopeChain(MangledName, N) : N;
break;
default:
Oper = Arena.alloc<OperatorInfo>();
}
Oper->Info = Entry;
Oper->IsOperator = true;
if (Error)
return nullptr;
return std::make_pair(OperatorTy::Unknown, nullptr);
return Oper;
return std::make_pair(Entry->Operator, N);
}
Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) {
@ -1956,11 +2187,6 @@ Name *Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) {
if (Error)
return nullptr;
// This is a special case that isn't followed by a scope.
assert(SymbolName);
if (SymbolName->isStringLiteralOperatorInfo())
return SymbolName;
Name *QualName = demangleNameScopeChain(MangledName, SymbolName);
if (Error)
return nullptr;
@ -1990,7 +2216,7 @@ Name *Demangler::demangleUnqualifiedSymbolName(StringView &MangledName,
if (MangledName.startsWith("?$"))
return demangleTemplateInstantiationName(MangledName, NBB);
if (MangledName.startsWith('?'))
return demangleOperatorName(MangledName);
return demangleOperatorName(MangledName, false).second;
return demangleSimpleName(MangledName, (NBB & NBB_Simple) != 0);
}
@ -2035,53 +2261,77 @@ FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {
SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
RestoreOnError.shouldRestore(false);
FuncClass TempFlags = FuncClass(0);
if (MangledName.consumeFront("$$J0"))
TempFlags = ExternC;
switch (MangledName.popFront()) {
case '9':
return FuncClass(TempFlags | ExternC | NoPrototype);
return FuncClass(ExternC | NoPrototype);
case 'A':
return Private;
case 'B':
return FuncClass(TempFlags | Private | Far);
return FuncClass(Private | Far);
case 'C':
return FuncClass(TempFlags | Private | Static);
return FuncClass(Private | Static);
case 'D':
return FuncClass(TempFlags | Private | Static);
return FuncClass(Private | Static);
case 'E':
return FuncClass(TempFlags | Private | Virtual);
return FuncClass(Private | Virtual);
case 'F':
return FuncClass(TempFlags | Private | Virtual);
return FuncClass(Private | Virtual);
case 'I':
return FuncClass(TempFlags | Protected);
return FuncClass(Protected);
case 'J':
return FuncClass(TempFlags | Protected | Far);
return FuncClass(Protected | Far);
case 'K':
return FuncClass(TempFlags | Protected | Static);
return FuncClass(Protected | Static);
case 'L':
return FuncClass(TempFlags | Protected | Static | Far);
return FuncClass(Protected | Static | Far);
case 'M':
return FuncClass(TempFlags | Protected | Virtual);
return FuncClass(Protected | Virtual);
case 'N':
return FuncClass(TempFlags | Protected | Virtual | Far);
return FuncClass(Protected | Virtual | Far);
case 'O':
return FuncClass(Protected | Virtual | StaticThisAdjust);
case 'P':
return FuncClass(Protected | Virtual | StaticThisAdjust | Far);
case 'Q':
return FuncClass(TempFlags | Public);
return FuncClass(Public);
case 'R':
return FuncClass(TempFlags | Public | Far);
return FuncClass(Public | Far);
case 'S':
return FuncClass(TempFlags | Public | Static);
return FuncClass(Public | Static);
case 'T':
return FuncClass(TempFlags | Public | Static | Far);
return FuncClass(Public | Static | Far);
case 'U':
return FuncClass(TempFlags | Public | Virtual);
return FuncClass(Public | Virtual);
case 'V':
return FuncClass(TempFlags | Public | Virtual | Far);
return FuncClass(Public | Virtual | Far);
case 'W':
return FuncClass(Public | Virtual | StaticThisAdjust);
case 'X':
return FuncClass(Public | Virtual | StaticThisAdjust | Far);
case 'Y':
return FuncClass(TempFlags | Global);
return FuncClass(Global);
case 'Z':
return FuncClass(TempFlags | Global | Far);
return FuncClass(Global | Far);
case '$': {
FuncClass VFlag = VirtualThisAdjust;
if (MangledName.consumeFront('R'))
VFlag = FuncClass(VFlag | VirtualThisAdjustEx);
switch (MangledName.popFront()) {
case '0':
return FuncClass(Private | Virtual | VFlag);
case '1':
return FuncClass(Private | Virtual | VFlag | Far);
case '2':
return FuncClass(Protected | Virtual | VFlag);
case '3':
return FuncClass(Protected | Virtual | VFlag | Far);
case '4':
return FuncClass(Public | Virtual | VFlag);
case '5':
return FuncClass(Public | Virtual | VFlag | Far);
}
}
}
Error = true;
@ -2291,7 +2541,27 @@ FunctionType *Demangler::demangleFunctionType(StringView &MangledName,
}
Type *Demangler::demangleFunctionEncoding(StringView &MangledName) {
FuncClass ExtraFlags = FuncClass::None;
if (MangledName.consumeFront("$$J0"))
ExtraFlags = FuncClass::ExternC;
FuncClass FC = demangleFunctionClass(MangledName);
FC = FuncClass(ExtraFlags | FC);
FunctionType::ThisAdjustor *Adjustor = nullptr;
if (FC & FuncClass::StaticThisAdjust) {
Adjustor = Arena.alloc<FunctionType::ThisAdjustor>();
Adjustor->StaticOffset = demangleSigned(MangledName);
} else if (FC & FuncClass::VirtualThisAdjust) {
Adjustor = Arena.alloc<FunctionType::ThisAdjustor>();
if (FC & FuncClass::VirtualThisAdjustEx) {
Adjustor->VBPtrOffset = demangleSigned(MangledName);
Adjustor->VBOffsetOffset = demangleSigned(MangledName);
}
Adjustor->VtordispOffset = demangleSigned(MangledName);
Adjustor->StaticOffset = demangleSigned(MangledName);
}
FunctionType *FTy = nullptr;
if (FC & NoPrototype) {
// This is an extern "C" function whose full signature hasn't been mangled.
@ -2302,6 +2572,7 @@ Type *Demangler::demangleFunctionEncoding(StringView &MangledName) {
bool HasThisQuals = !(FC & (Global | Static));
FTy = demangleFunctionType(MangledName, HasThisQuals, false);
}
FTy->ThisAdjust = Adjustor;
FTy->FunctionClass = FC;
return FTy;
@ -2694,6 +2965,11 @@ void Demangler::output(const Symbol *S, OutputStream &OS) {
return;
}
if (S->Category == SymbolCategory::SpecialOperator) {
outputSpecialOperator(OS, S->SymbolName, *this);
return;
}
// Converts an AST to a string.
//
// Converting an AST representing a C++ type to a string is tricky due
@ -2715,8 +2991,10 @@ void Demangler::output(const Symbol *S, OutputStream &OS) {
Type::outputPre(OS, *S->SymbolType, *this);
outputName(OS, S->SymbolName, S->SymbolType, *this);
Type::outputPost(OS, *S->SymbolType, *this);
} else
} else {
outputQualifiers(OS, S->SymbolQuals);
outputName(OS, S->SymbolName, nullptr, *this);
}
}
void Demangler::dumpBackReferences() {

View File

@ -143,11 +143,11 @@
??_8Middle2@@7B@
; CHECK: const Middle2::`vbtable'
; ??_9Base@@$B7AA
; FIXME: [thunk]: __cdecl Base::`vcall'{8, {flat}}' }'
??_9Base@@$B7AA
; CHECK: [thunk]: __cdecl Base::`vcall'{8, {flat}}
; ??_B?1??getS@@YAAAUS@@XZ@51
; FIXME: `struct S & __cdecl getS(void)'::`2'::`local static guard'{2}'
??_B?1??getS@@YAAAUS@@XZ@51
; CHECK: `struct S & __cdecl getS(void)'::`2'::`local static guard'{2}
??_C@_02PCEFGMJL@hi?$AA@
; CHECK: const char * {"hi"}
@ -158,8 +158,8 @@
??_EBase@@UEAAPEAXI@Z
; CHECK: virtual void * __cdecl Base::`vector deleting dtor'(unsigned int)
; ??_EDerived@@$4PPPPPPPM@A@EAAPEAXI@Z
; FIXME: [thunk]:virtual void * __cdecl Derived::`vector deleting dtor'`vtordisp{4294967292, 0}' (unsigned int)
??_EDerived@@$4PPPPPPPM@A@EAAPEAXI@Z
; CHECK: [thunk]: virtual void * __cdecl Derived::`vector deleting dtor'`vtordisp{-4, 0}'(unsigned int)
??_F?$SomeTemplate@H@@QAEXXZ
; CHECK: void __thiscall SomeTemplate<int>::`default ctor closure'(void)
@ -203,17 +203,17 @@
??_V@YAXPEAXAEAVklass@@@Z
; CHECK: void __cdecl operator delete[](void *, class klass &)
; ??_R0?AUBase@@@8
; FIXME: struct Base `RTTI Type Descriptor'
??_R0?AUBase@@@8
; CHECK: struct Base `RTTI Type Descriptor'
; ??_R1A@?0A@EA@Base@@8
; FIXME: Base::`RTTI Base Class Descriptor at (0, -1, 0, 64)'
??_R1A@?0A@EA@Base@@8
; CHECK: Base::`RTTI Base Class Descriptor at (0, -1, 0, 64)'
; ??_R2Base@@8
; FIXME: Base::`RTTI Base Class Array'
??_R2Base@@8
; CHECK: Base::`RTTI Base Class Array'
; ??_R3Base@@8
; FIXME: Base::`RTTI Class Hierarchy Descriptor'
??_R3Base@@8
; CHECK: Base::`RTTI Class Hierarchy Descriptor'
??_R4Base@@6B@
; CHECK: const Base::`RTTI Complete Object Locator'