diff options
| -rw-r--r-- | llvm/lib/Demangle/MicrosoftDemangle.cpp | 524 | ||||
| -rw-r--r-- | llvm/test/Demangle/ms-operators.test | 28 |
2 files changed, 415 insertions, 137 deletions
diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp index 4364ff8e55a..172ba0bca93 100644 --- a/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -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('?'); + + // ?$ is a template instantiation, but all other names that start with ? are + // operators / special names. + if (MangledName.startsWith('?') && !MangledName.startsWith("?$")) + return parseOperator(MangledName); - // What follows is a main symbol name. This may include - // namespaces or class BackReferences. + 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: - Oper = Arena.alloc<OperatorInfo>(); + N = Arena.alloc<OperatorInfo>(*Entry); + N = (FullyQualified) ? demangleNameScopeChain(MangledName, N) : N; + break; } - - 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() { diff --git a/llvm/test/Demangle/ms-operators.test b/llvm/test/Demangle/ms-operators.test index 388f3ea9d54..54da11c2ed7 100644 --- a/llvm/test/Demangle/ms-operators.test +++ b/llvm/test/Demangle/ms-operators.test @@ -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' |

