forked from OSchip/llvm-project
[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:
parent
3820f582eb
commit
469f076356
|
@ -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() {
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Reference in New Issue