|  | //===- MicrosoftDemangle.cpp ----------------------------------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is dual licensed under the MIT and the University of Illinois Open | 
|  | // Source Licenses. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file defines a demangler for MSVC-style mangled symbols. | 
|  | // | 
|  | // This file has no dependencies on the rest of LLVM so that it can be | 
|  | // easily reused in other programs such as libcxxabi. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Demangle/Demangle.h" | 
|  |  | 
|  | #include "Compiler.h" | 
|  | #include "StringView.h" | 
|  | #include "Utility.h" | 
|  |  | 
|  | #include <cctype> | 
|  | #include <tuple> | 
|  |  | 
|  | // This memory allocator is extremely fast, but it doesn't call dtors | 
|  | // for allocated objects. That means you can't use STL containers | 
|  | // (such as std::vector) with this allocator. But it pays off -- | 
|  | // the demangler is 3x faster with this allocator compared to one with | 
|  | // STL containers. | 
|  | namespace { | 
|  | constexpr size_t AllocUnit = 4096; | 
|  |  | 
|  | class ArenaAllocator { | 
|  | struct AllocatorNode { | 
|  | uint8_t *Buf = nullptr; | 
|  | size_t Used = 0; | 
|  | size_t Capacity = 0; | 
|  | AllocatorNode *Next = nullptr; | 
|  | }; | 
|  |  | 
|  | void addNode(size_t Capacity) { | 
|  | AllocatorNode *NewHead = new AllocatorNode; | 
|  | NewHead->Buf = new uint8_t[Capacity]; | 
|  | NewHead->Next = Head; | 
|  | NewHead->Capacity = Capacity; | 
|  | Head = NewHead; | 
|  | NewHead->Used = 0; | 
|  | } | 
|  |  | 
|  | public: | 
|  | ArenaAllocator() { addNode(AllocUnit); } | 
|  |  | 
|  | ~ArenaAllocator() { | 
|  | while (Head) { | 
|  | assert(Head->Buf); | 
|  | delete[] Head->Buf; | 
|  | AllocatorNode *Next = Head->Next; | 
|  | delete Head; | 
|  | Head = Next; | 
|  | } | 
|  | } | 
|  |  | 
|  | char *allocUnalignedBuffer(size_t Length) { | 
|  | uint8_t *Buf = Head->Buf + Head->Used; | 
|  |  | 
|  | Head->Used += Length; | 
|  | if (Head->Used > Head->Capacity) { | 
|  | // It's possible we need a buffer which is larger than our default unit | 
|  | // size, so we need to be careful to add a node with capacity that is at | 
|  | // least as large as what we need. | 
|  | addNode(std::max(AllocUnit, Length)); | 
|  | Head->Used = Length; | 
|  | Buf = Head->Buf; | 
|  | } | 
|  |  | 
|  | return reinterpret_cast<char *>(Buf); | 
|  | } | 
|  |  | 
|  | template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) { | 
|  |  | 
|  | size_t Size = sizeof(T); | 
|  | assert(Head && Head->Buf); | 
|  |  | 
|  | size_t P = (size_t)Head->Buf + Head->Used; | 
|  | uintptr_t AlignedP = | 
|  | (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1)); | 
|  | uint8_t *PP = (uint8_t *)AlignedP; | 
|  | size_t Adjustment = AlignedP - P; | 
|  |  | 
|  | Head->Used += Size + Adjustment; | 
|  | if (Head->Used < Head->Capacity) | 
|  | return new (PP) T(std::forward<Args>(ConstructorArgs)...); | 
|  |  | 
|  | addNode(AllocUnit); | 
|  | Head->Used = Size; | 
|  | return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...); | 
|  | } | 
|  |  | 
|  | private: | 
|  | AllocatorNode *Head = nullptr; | 
|  | }; | 
|  | } // namespace | 
|  |  | 
|  | static bool startsWithDigit(StringView S) { | 
|  | return !S.empty() && std::isdigit(S.front()); | 
|  | } | 
|  |  | 
|  | // Writes a space if the last token does not end with a punctuation. | 
|  | static void outputSpaceIfNecessary(OutputStream &OS) { | 
|  | if (OS.empty()) | 
|  | return; | 
|  |  | 
|  | char C = OS.back(); | 
|  | if (isalnum(C) || C == '>') | 
|  | OS << " "; | 
|  | } | 
|  |  | 
|  | // Storage classes | 
|  | enum Qualifiers : uint8_t { | 
|  | Q_None = 0, | 
|  | Q_Const = 1 << 0, | 
|  | Q_Volatile = 1 << 1, | 
|  | Q_Far = 1 << 2, | 
|  | Q_Huge = 1 << 3, | 
|  | Q_Unaligned = 1 << 4, | 
|  | Q_Restrict = 1 << 5, | 
|  | Q_Pointer64 = 1 << 6 | 
|  | }; | 
|  |  | 
|  | enum class StorageClass : uint8_t { | 
|  | None, | 
|  | PrivateStatic, | 
|  | ProtectedStatic, | 
|  | PublicStatic, | 
|  | Global, | 
|  | FunctionLocalStatic | 
|  | }; | 
|  |  | 
|  | enum class QualifierMangleMode { Drop, Mangle, Result }; | 
|  |  | 
|  | enum class PointerAffinity { Pointer, Reference, RValueReference }; | 
|  |  | 
|  | // Calling conventions | 
|  | enum class CallingConv : uint8_t { | 
|  | None, | 
|  | Cdecl, | 
|  | Pascal, | 
|  | Thiscall, | 
|  | Stdcall, | 
|  | Fastcall, | 
|  | Clrcall, | 
|  | Eabi, | 
|  | Vectorcall, | 
|  | Regcall, | 
|  | }; | 
|  |  | 
|  | enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef }; | 
|  |  | 
|  | // Types | 
|  | enum class PrimTy : uint8_t { | 
|  | Unknown, | 
|  | None, | 
|  | Function, | 
|  | Ptr, | 
|  | MemberPtr, | 
|  | Array, | 
|  |  | 
|  | Struct, | 
|  | Union, | 
|  | Class, | 
|  | Enum, | 
|  |  | 
|  | Void, | 
|  | Bool, | 
|  | Char, | 
|  | Schar, | 
|  | Uchar, | 
|  | Char16, | 
|  | Char32, | 
|  | Short, | 
|  | Ushort, | 
|  | Int, | 
|  | Uint, | 
|  | Long, | 
|  | Ulong, | 
|  | Int64, | 
|  | Uint64, | 
|  | Wchar, | 
|  | Float, | 
|  | Double, | 
|  | Ldouble, | 
|  | Nullptr | 
|  | }; | 
|  |  | 
|  | // Function classes | 
|  | enum FuncClass : uint8_t { | 
|  | Public = 1 << 0, | 
|  | Protected = 1 << 1, | 
|  | Private = 1 << 2, | 
|  | Global = 1 << 3, | 
|  | Static = 1 << 4, | 
|  | Virtual = 1 << 5, | 
|  | Far = 1 << 6, | 
|  | }; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct Type; | 
|  | struct Name; | 
|  |  | 
|  | struct FunctionParams { | 
|  | bool IsVariadic = false; | 
|  |  | 
|  | Type *Current = nullptr; | 
|  |  | 
|  | FunctionParams *Next = nullptr; | 
|  | }; | 
|  |  | 
|  | struct TemplateParams { | 
|  | bool IsTemplateTemplate = false; | 
|  | bool IsAliasTemplate = false; | 
|  |  | 
|  | // Type can be null if this is a template template parameter.  In that case | 
|  | // only Name will be valid. | 
|  | Type *ParamType = nullptr; | 
|  |  | 
|  | // Name can be valid if this is a template template parameter (see above) or | 
|  | // this is a function declaration (e.g. foo<&SomeFunc>).  In the latter case | 
|  | // Name contains the name of the function and Type contains the signature. | 
|  | Name *ParamName = nullptr; | 
|  |  | 
|  | TemplateParams *Next = nullptr; | 
|  | }; | 
|  |  | 
|  | // The type class. Mangled symbols are first parsed and converted to | 
|  | // this type and then converted to string. | 
|  | struct Type { | 
|  | virtual ~Type() {} | 
|  |  | 
|  | virtual Type *clone(ArenaAllocator &Arena) const; | 
|  |  | 
|  | // Write the "first half" of a given type.  This is a static functions to | 
|  | // give the code a chance to do processing that is common to a subset of | 
|  | // subclasses | 
|  | static void outputPre(OutputStream &OS, Type &Ty); | 
|  |  | 
|  | // Write the "second half" of a given type.  This is a static functions to | 
|  | // give the code a chance to do processing that is common to a subset of | 
|  | // subclasses | 
|  | static void outputPost(OutputStream &OS, Type &Ty); | 
|  |  | 
|  | virtual void outputPre(OutputStream &OS); | 
|  | virtual void outputPost(OutputStream &OS); | 
|  |  | 
|  | // Primitive type such as Int. | 
|  | PrimTy Prim = PrimTy::Unknown; | 
|  |  | 
|  | Qualifiers Quals = Q_None; | 
|  | StorageClass Storage = StorageClass::None; // storage class | 
|  | }; | 
|  |  | 
|  | // Represents an identifier which may be a template. | 
|  | struct Name { | 
|  | // Name read from an MangledName string. | 
|  | StringView Str; | 
|  |  | 
|  | // Overloaded operators are represented as special BackReferences in mangled | 
|  | // symbols. If this is an operator name, "op" has an operator name (e.g. | 
|  | // ">>"). Otherwise, empty. | 
|  | StringView Operator; | 
|  |  | 
|  | // Template parameters. Null if not a template. | 
|  | TemplateParams *TParams = nullptr; | 
|  |  | 
|  | // Nested BackReferences (e.g. "A::B::C") are represented as a linked list. | 
|  | Name *Next = nullptr; | 
|  | }; | 
|  |  | 
|  | struct PointerType : public Type { | 
|  | Type *clone(ArenaAllocator &Arena) const override; | 
|  | void outputPre(OutputStream &OS) override; | 
|  | void outputPost(OutputStream &OS) override; | 
|  |  | 
|  | PointerAffinity Affinity; | 
|  |  | 
|  | // Represents a type X in "a pointer to X", "a reference to X", | 
|  | // "an array of X", or "a function returning X". | 
|  | Type *Pointee = nullptr; | 
|  | }; | 
|  |  | 
|  | struct MemberPointerType : public Type { | 
|  | Type *clone(ArenaAllocator &Arena) const override; | 
|  | void outputPre(OutputStream &OS) override; | 
|  | void outputPost(OutputStream &OS) override; | 
|  |  | 
|  | Name *MemberName = nullptr; | 
|  |  | 
|  | // Represents a type X in "a pointer to X", "a reference to X", | 
|  | // "an array of X", or "a function returning X". | 
|  | Type *Pointee = nullptr; | 
|  | }; | 
|  |  | 
|  | struct FunctionType : public Type { | 
|  | Type *clone(ArenaAllocator &Arena) const override; | 
|  | void outputPre(OutputStream &OS) override; | 
|  | void outputPost(OutputStream &OS) override; | 
|  |  | 
|  | // True if this FunctionType instance is the Pointee of a PointerType or | 
|  | // MemberPointerType. | 
|  | bool IsFunctionPointer = false; | 
|  |  | 
|  | Type *ReturnType = nullptr; | 
|  | // If this is a reference, the type of reference. | 
|  | ReferenceKind RefKind; | 
|  |  | 
|  | CallingConv CallConvention; | 
|  | FuncClass FunctionClass; | 
|  |  | 
|  | FunctionParams Params; | 
|  | }; | 
|  |  | 
|  | struct UdtType : public Type { | 
|  | Type *clone(ArenaAllocator &Arena) const override; | 
|  | void outputPre(OutputStream &OS) override; | 
|  |  | 
|  | Name *UdtName = nullptr; | 
|  | }; | 
|  |  | 
|  | struct ArrayType : public Type { | 
|  | Type *clone(ArenaAllocator &Arena) const override; | 
|  | void outputPre(OutputStream &OS) override; | 
|  | void outputPost(OutputStream &OS) override; | 
|  |  | 
|  | // Either NextDimension or ElementType will be valid. | 
|  | ArrayType *NextDimension = nullptr; | 
|  | uint32_t ArrayDimension = 0; | 
|  |  | 
|  | Type *ElementType = nullptr; | 
|  | }; | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | static bool isMemberPointer(StringView MangledName) { | 
|  | switch (MangledName.popFront()) { | 
|  | case '$': | 
|  | // This is probably an rvalue reference (e.g. $$Q), and you cannot have an | 
|  | // rvalue reference to a member. | 
|  | return false; | 
|  | case 'A': | 
|  | // 'A' indicates a reference, and you cannot have a reference to a member | 
|  | // function or member. | 
|  | return false; | 
|  | case 'P': | 
|  | case 'Q': | 
|  | case 'R': | 
|  | case 'S': | 
|  | // These 4 values indicate some kind of pointer, but we still don't know | 
|  | // what. | 
|  | break; | 
|  | default: | 
|  | assert(false && "Ty is not a pointer type!"); | 
|  | } | 
|  |  | 
|  | // If it starts with a number, then 6 indicates a non-member function | 
|  | // pointer, and 8 indicates a member function pointer. | 
|  | if (startsWithDigit(MangledName)) { | 
|  | assert(MangledName[0] == '6' || MangledName[0] == '8'); | 
|  | return (MangledName[0] == '8'); | 
|  | } | 
|  |  | 
|  | // Remove ext qualifiers since those can appear on either type and are | 
|  | // therefore not indicative. | 
|  | MangledName.consumeFront('E'); // 64-bit | 
|  | MangledName.consumeFront('I'); // restrict | 
|  | MangledName.consumeFront('F'); // unaligned | 
|  |  | 
|  | assert(!MangledName.empty()); | 
|  |  | 
|  | // The next value should be either ABCD (non-member) or QRST (member). | 
|  | switch (MangledName.front()) { | 
|  | case 'A': | 
|  | case 'B': | 
|  | case 'C': | 
|  | case 'D': | 
|  | return false; | 
|  | case 'Q': | 
|  | case 'R': | 
|  | case 'S': | 
|  | case 'T': | 
|  | return true; | 
|  | default: | 
|  | assert(false); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static void outputCallingConvention(OutputStream &OS, CallingConv CC) { | 
|  | outputSpaceIfNecessary(OS); | 
|  |  | 
|  | switch (CC) { | 
|  | case CallingConv::Cdecl: | 
|  | OS << "__cdecl"; | 
|  | break; | 
|  | case CallingConv::Fastcall: | 
|  | OS << "__fastcall"; | 
|  | break; | 
|  | case CallingConv::Pascal: | 
|  | OS << "__pascal"; | 
|  | break; | 
|  | case CallingConv::Regcall: | 
|  | OS << "__regcall"; | 
|  | break; | 
|  | case CallingConv::Stdcall: | 
|  | OS << "__stdcall"; | 
|  | break; | 
|  | case CallingConv::Thiscall: | 
|  | OS << "__thiscall"; | 
|  | break; | 
|  | case CallingConv::Eabi: | 
|  | OS << "__eabi"; | 
|  | break; | 
|  | case CallingConv::Vectorcall: | 
|  | OS << "__vectorcall"; | 
|  | break; | 
|  | case CallingConv::Clrcall: | 
|  | OS << "__clrcall"; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static bool startsWithLocalScopePattern(StringView S) { | 
|  | if (!S.consumeFront('?')) | 
|  | return false; | 
|  | if (S.size() < 2) | 
|  | return false; | 
|  |  | 
|  | size_t End = S.find('?'); | 
|  | if (End == StringView::npos) | 
|  | return false; | 
|  | StringView Candidate = S.substr(0, End); | 
|  | if (Candidate.empty()) | 
|  | return false; | 
|  |  | 
|  | // \?[0-9]\? | 
|  | // ?@? is the discriminator 0. | 
|  | if (Candidate.size() == 1) | 
|  | return Candidate[0] == '@' || (Candidate[0] >= '0' && Candidate[0] <= '9'); | 
|  |  | 
|  | // If it's not 0-9, then it's an encoded number terminated with an @ | 
|  | if (Candidate.back() != '@') | 
|  | return false; | 
|  | Candidate = Candidate.dropBack(); | 
|  |  | 
|  | // An encoded number starts with B-P and all subsequent digits are in A-P. | 
|  | // Note that the reason the first digit cannot be A is two fold.  First, it | 
|  | // would create an ambiguity with ?A which delimits the beginning of an | 
|  | // anonymous namespace.  Second, A represents 0, and you don't start a multi | 
|  | // digit number with a leading 0.  Presumably the anonymous namespace | 
|  | // ambiguity is also why single digit encoded numbers use 0-9 rather than A-J. | 
|  | if (Candidate[0] < 'B' || Candidate[0] > 'P') | 
|  | return false; | 
|  | Candidate = Candidate.dropFront(); | 
|  | while (!Candidate.empty()) { | 
|  | if (Candidate[0] < 'A' || Candidate[0] > 'P') | 
|  | return false; | 
|  | Candidate = Candidate.dropFront(); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static void outputName(OutputStream &OS, const Name *TheName); | 
|  |  | 
|  | // Write a function or template parameter list. | 
|  | static void outputParameterList(OutputStream &OS, | 
|  | const FunctionParams &Params) { | 
|  | if (!Params.Current) { | 
|  | OS << "void"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | const FunctionParams *Head = &Params; | 
|  | while (Head) { | 
|  | Type::outputPre(OS, *Head->Current); | 
|  | Type::outputPost(OS, *Head->Current); | 
|  |  | 
|  | Head = Head->Next; | 
|  |  | 
|  | if (Head) | 
|  | OS << ", "; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void outputParameterList(OutputStream &OS, | 
|  | const TemplateParams &Params) { | 
|  | if (!Params.ParamType && !Params.ParamName) { | 
|  | OS << "<>"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | OS << "<"; | 
|  | const TemplateParams *Head = &Params; | 
|  | while (Head) { | 
|  | // Type can be null if this is a template template parameter, | 
|  | // and Name can be null if this is a simple type. | 
|  |  | 
|  | if (Head->ParamType && Head->ParamName) { | 
|  | // Function pointer. | 
|  | OS << "&"; | 
|  | Type::outputPre(OS, *Head->ParamType); | 
|  | outputName(OS, Head->ParamName); | 
|  | Type::outputPost(OS, *Head->ParamType); | 
|  | } else if (Head->ParamType) { | 
|  | // simple type. | 
|  | Type::outputPre(OS, *Head->ParamType); | 
|  | Type::outputPost(OS, *Head->ParamType); | 
|  | } else { | 
|  | // Template alias. | 
|  | outputName(OS, Head->ParamName); | 
|  | } | 
|  |  | 
|  | Head = Head->Next; | 
|  |  | 
|  | if (Head) | 
|  | OS << ", "; | 
|  | } | 
|  | OS << ">"; | 
|  | } | 
|  |  | 
|  | static void outputName(OutputStream &OS, const Name *TheName) { | 
|  | if (!TheName) | 
|  | return; | 
|  |  | 
|  | outputSpaceIfNecessary(OS); | 
|  |  | 
|  | const Name *Previous = nullptr; | 
|  | // Print out namespaces or outer class BackReferences. | 
|  | for (; TheName->Next; TheName = TheName->Next) { | 
|  | Previous = TheName; | 
|  | OS << TheName->Str; | 
|  | if (TheName->TParams) | 
|  | outputParameterList(OS, *TheName->TParams); | 
|  | OS << "::"; | 
|  | } | 
|  |  | 
|  | // Print out a regular name. | 
|  | if (TheName->Operator.empty()) { | 
|  | OS << TheName->Str; | 
|  | if (TheName->TParams) | 
|  | outputParameterList(OS, *TheName->TParams); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Print out ctor or dtor. | 
|  | if (TheName->Operator == "dtor") | 
|  | OS << "~"; | 
|  |  | 
|  | if (TheName->Operator == "ctor" || TheName->Operator == "dtor") { | 
|  | OS << Previous->Str; | 
|  | if (Previous->TParams) | 
|  | outputParameterList(OS, *Previous->TParams); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Print out an overloaded operator. | 
|  | if (!TheName->Str.empty()) | 
|  | OS << TheName->Str << "::"; | 
|  | OS << "operator" << TheName->Operator; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | Type *Type::clone(ArenaAllocator &Arena) const { | 
|  | return Arena.alloc<Type>(*this); | 
|  | } | 
|  |  | 
|  | // Write the "first half" of a given type. | 
|  | void Type::outputPre(OutputStream &OS, Type &Ty) { | 
|  | // Function types require custom handling of const and static so we | 
|  | // handle them separately.  All other types use the same decoration | 
|  | // for these modifiers, so handle them here in common code. | 
|  | if (Ty.Prim == PrimTy::Function) { | 
|  | Ty.outputPre(OS); | 
|  | return; | 
|  | } | 
|  |  | 
|  | switch (Ty.Storage) { | 
|  | case StorageClass::PrivateStatic: | 
|  | case StorageClass::PublicStatic: | 
|  | case StorageClass::ProtectedStatic: | 
|  | OS << "static "; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | Ty.outputPre(OS); | 
|  |  | 
|  | 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"; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Write the "second half" of a given type. | 
|  | void Type::outputPost(OutputStream &OS, Type &Ty) { Ty.outputPost(OS); } | 
|  |  | 
|  | void Type::outputPre(OutputStream &OS) { | 
|  | switch (Prim) { | 
|  | case PrimTy::Void: | 
|  | OS << "void"; | 
|  | break; | 
|  | case PrimTy::Bool: | 
|  | OS << "bool"; | 
|  | break; | 
|  | case PrimTy::Char: | 
|  | OS << "char"; | 
|  | break; | 
|  | case PrimTy::Schar: | 
|  | OS << "signed char"; | 
|  | break; | 
|  | case PrimTy::Uchar: | 
|  | OS << "unsigned char"; | 
|  | break; | 
|  | case PrimTy::Char16: | 
|  | OS << "char16_t"; | 
|  | break; | 
|  | case PrimTy::Char32: | 
|  | OS << "char32_t"; | 
|  | break; | 
|  | case PrimTy::Short: | 
|  | OS << "short"; | 
|  | break; | 
|  | case PrimTy::Ushort: | 
|  | OS << "unsigned short"; | 
|  | break; | 
|  | case PrimTy::Int: | 
|  | OS << "int"; | 
|  | break; | 
|  | case PrimTy::Uint: | 
|  | OS << "unsigned int"; | 
|  | break; | 
|  | case PrimTy::Long: | 
|  | OS << "long"; | 
|  | break; | 
|  | case PrimTy::Ulong: | 
|  | OS << "unsigned long"; | 
|  | break; | 
|  | case PrimTy::Int64: | 
|  | OS << "__int64"; | 
|  | break; | 
|  | case PrimTy::Uint64: | 
|  | OS << "unsigned __int64"; | 
|  | break; | 
|  | case PrimTy::Wchar: | 
|  | OS << "wchar_t"; | 
|  | break; | 
|  | case PrimTy::Float: | 
|  | OS << "float"; | 
|  | break; | 
|  | case PrimTy::Double: | 
|  | OS << "double"; | 
|  | break; | 
|  | case PrimTy::Ldouble: | 
|  | OS << "long double"; | 
|  | break; | 
|  | case PrimTy::Nullptr: | 
|  | OS << "std::nullptr_t"; | 
|  | break; | 
|  | default: | 
|  | assert(false && "Invalid primitive type!"); | 
|  | } | 
|  | } | 
|  | void Type::outputPost(OutputStream &OS) {} | 
|  |  | 
|  | Type *PointerType::clone(ArenaAllocator &Arena) const { | 
|  | return Arena.alloc<PointerType>(*this); | 
|  | } | 
|  |  | 
|  | static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity, | 
|  | const Name *MemberName, | 
|  | const Type *Pointee) { | 
|  | // "[]" and "()" (for function parameters) take precedence over "*", | 
|  | // so "int *x(int)" means "x is a function returning int *". We need | 
|  | // parentheses to supercede the default precedence. (e.g. we want to | 
|  | // emit something like "int (*x)(int)".) | 
|  | if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array) { | 
|  | OS << "("; | 
|  | if (Pointee->Prim == PrimTy::Function) { | 
|  | const FunctionType *FTy = static_cast<const FunctionType *>(Pointee); | 
|  | assert(FTy->IsFunctionPointer); | 
|  | outputCallingConvention(OS, FTy->CallConvention); | 
|  | OS << " "; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (MemberName) { | 
|  | outputName(OS, MemberName); | 
|  | OS << "::"; | 
|  | } | 
|  |  | 
|  | if (Affinity == PointerAffinity::Pointer) | 
|  | OS << "*"; | 
|  | else if (Affinity == PointerAffinity::Reference) | 
|  | OS << "&"; | 
|  | else | 
|  | OS << "&&"; | 
|  | } | 
|  |  | 
|  | void PointerType::outputPre(OutputStream &OS) { | 
|  | Type::outputPre(OS, *Pointee); | 
|  |  | 
|  | outputSpaceIfNecessary(OS); | 
|  |  | 
|  | if (Quals & Q_Unaligned) | 
|  | OS << "__unaligned "; | 
|  |  | 
|  | outputPointerIndicator(OS, Affinity, nullptr, Pointee); | 
|  |  | 
|  | // FIXME: We should output this, but it requires updating lots of tests. | 
|  | // if (Ty.Quals & Q_Pointer64) | 
|  | //  OS << " __ptr64"; | 
|  | } | 
|  |  | 
|  | void PointerType::outputPost(OutputStream &OS) { | 
|  | if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array) | 
|  | OS << ")"; | 
|  |  | 
|  | Type::outputPost(OS, *Pointee); | 
|  | } | 
|  |  | 
|  | Type *MemberPointerType::clone(ArenaAllocator &Arena) const { | 
|  | return Arena.alloc<MemberPointerType>(*this); | 
|  | } | 
|  |  | 
|  | void MemberPointerType::outputPre(OutputStream &OS) { | 
|  | Type::outputPre(OS, *Pointee); | 
|  |  | 
|  | outputSpaceIfNecessary(OS); | 
|  |  | 
|  | outputPointerIndicator(OS, PointerAffinity::Pointer, MemberName, Pointee); | 
|  |  | 
|  | // FIXME: We should output this, but it requires updating lots of tests. | 
|  | // if (Ty.Quals & Q_Pointer64) | 
|  | //  OS << " __ptr64"; | 
|  | if (Quals & Q_Restrict) | 
|  | OS << " __restrict"; | 
|  | } | 
|  |  | 
|  | void MemberPointerType::outputPost(OutputStream &OS) { | 
|  | if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array) | 
|  | OS << ")"; | 
|  |  | 
|  | Type::outputPost(OS, *Pointee); | 
|  | } | 
|  |  | 
|  | Type *FunctionType::clone(ArenaAllocator &Arena) const { | 
|  | return Arena.alloc<FunctionType>(*this); | 
|  | } | 
|  |  | 
|  | void FunctionType::outputPre(OutputStream &OS) { | 
|  | if (!(FunctionClass & Global)) { | 
|  | if (FunctionClass & Static) | 
|  | OS << "static "; | 
|  | } | 
|  |  | 
|  | if (ReturnType) { | 
|  | Type::outputPre(OS, *ReturnType); | 
|  | OS << " "; | 
|  | } | 
|  |  | 
|  | // Function pointers print the calling convention as void (__cdecl *)(params) | 
|  | // rather than void __cdecl (*)(params).  So we need to let the PointerType | 
|  | // class handle this. | 
|  | if (!IsFunctionPointer) | 
|  | outputCallingConvention(OS, CallConvention); | 
|  | } | 
|  |  | 
|  | void FunctionType::outputPost(OutputStream &OS) { | 
|  | OS << "("; | 
|  | outputParameterList(OS, Params); | 
|  | OS << ")"; | 
|  | if (Quals & Q_Const) | 
|  | OS << " const"; | 
|  | if (Quals & Q_Volatile) | 
|  | OS << " volatile"; | 
|  | if (Quals & Q_Restrict) | 
|  | OS << " __restrict"; | 
|  | if (Quals & Q_Unaligned) | 
|  | OS << " __unaligned"; | 
|  |  | 
|  | if (RefKind == ReferenceKind::LValueRef) | 
|  | OS << " &"; | 
|  | else if (RefKind == ReferenceKind::RValueRef) | 
|  | OS << " &&"; | 
|  |  | 
|  | if (ReturnType) | 
|  | Type::outputPost(OS, *ReturnType); | 
|  | return; | 
|  | } | 
|  |  | 
|  | Type *UdtType::clone(ArenaAllocator &Arena) const { | 
|  | return Arena.alloc<UdtType>(*this); | 
|  | } | 
|  |  | 
|  | void UdtType::outputPre(OutputStream &OS) { | 
|  | switch (Prim) { | 
|  | case PrimTy::Class: | 
|  | OS << "class "; | 
|  | break; | 
|  | case PrimTy::Struct: | 
|  | OS << "struct "; | 
|  | break; | 
|  | case PrimTy::Union: | 
|  | OS << "union "; | 
|  | break; | 
|  | case PrimTy::Enum: | 
|  | OS << "enum "; | 
|  | break; | 
|  | default: | 
|  | assert(false && "Not a udt type!"); | 
|  | } | 
|  |  | 
|  | outputName(OS, UdtName); | 
|  | } | 
|  |  | 
|  | Type *ArrayType::clone(ArenaAllocator &Arena) const { | 
|  | return Arena.alloc<ArrayType>(*this); | 
|  | } | 
|  |  | 
|  | void ArrayType::outputPre(OutputStream &OS) { | 
|  | Type::outputPre(OS, *ElementType); | 
|  | } | 
|  |  | 
|  | void ArrayType::outputPost(OutputStream &OS) { | 
|  | if (ArrayDimension > 0) | 
|  | OS << "[" << ArrayDimension << "]"; | 
|  | if (NextDimension) | 
|  | Type::outputPost(OS, *NextDimension); | 
|  | else if (ElementType) | 
|  | Type::outputPost(OS, *ElementType); | 
|  | } | 
|  |  | 
|  | struct Symbol { | 
|  | Name *SymbolName = nullptr; | 
|  | Type *SymbolType = nullptr; | 
|  | }; | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Demangler class takes the main role in demangling symbols. | 
|  | // It has a set of functions to parse mangled symbols into Type instances. | 
|  | // It also has a set of functions to cnovert Type instances to strings. | 
|  | class Demangler { | 
|  | public: | 
|  | Demangler() = default; | 
|  |  | 
|  | // 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); | 
|  | void output(const Symbol *S, OutputStream &OS); | 
|  |  | 
|  | // True if an error occurred. | 
|  | bool Error = false; | 
|  |  | 
|  | private: | 
|  | Type *demangleVariableEncoding(StringView &MangledName); | 
|  | Type *demangleFunctionEncoding(StringView &MangledName); | 
|  |  | 
|  | Qualifiers demanglePointerExtQualifiers(StringView &MangledName); | 
|  |  | 
|  | // Parser functions. This is a recursive-descent parser. | 
|  | Type *demangleType(StringView &MangledName, QualifierMangleMode QMM); | 
|  | Type *demangleBasicType(StringView &MangledName); | 
|  | UdtType *demangleClassType(StringView &MangledName); | 
|  | PointerType *demanglePointerType(StringView &MangledName); | 
|  | MemberPointerType *demangleMemberPointerType(StringView &MangledName); | 
|  | FunctionType *demangleFunctionType(StringView &MangledName, bool HasThisQuals, | 
|  | bool IsFunctionPointer); | 
|  |  | 
|  | ArrayType *demangleArrayType(StringView &MangledName); | 
|  |  | 
|  | TemplateParams *demangleTemplateParameterList(StringView &MangledName); | 
|  | FunctionParams demangleFunctionParameterList(StringView &MangledName); | 
|  |  | 
|  | int demangleNumber(StringView &MangledName); | 
|  |  | 
|  | void memorizeString(StringView s); | 
|  |  | 
|  | /// Allocate a copy of \p Borrowed into memory that we own. | 
|  | StringView copyString(StringView Borrowed); | 
|  |  | 
|  | Name *demangleFullyQualifiedTypeName(StringView &MangledName); | 
|  | Name *demangleFullyQualifiedSymbolName(StringView &MangledName); | 
|  |  | 
|  | Name *demangleUnqualifiedTypeName(StringView &MangledName); | 
|  | Name *demangleUnqualifiedSymbolName(StringView &MangledName); | 
|  |  | 
|  | Name *demangleNameScopeChain(StringView &MangledName, Name *UnqualifiedName); | 
|  | Name *demangleNameScopePiece(StringView &MangledName); | 
|  |  | 
|  | Name *demangleBackRefName(StringView &MangledName); | 
|  | Name *demangleClassTemplateName(StringView &MangledName); | 
|  | Name *demangleOperatorName(StringView &MangledName); | 
|  | Name *demangleSimpleName(StringView &MangledName, bool Memorize); | 
|  | Name *demangleAnonymousNamespaceName(StringView &MangledName); | 
|  | Name *demangleLocallyScopedNamePiece(StringView &MangledName); | 
|  |  | 
|  | StringView demangleSimpleString(StringView &MangledName, bool Memorize); | 
|  |  | 
|  | FuncClass demangleFunctionClass(StringView &MangledName); | 
|  | CallingConv demangleCallingConvention(StringView &MangledName); | 
|  | StorageClass demangleVariableStorageClass(StringView &MangledName); | 
|  | ReferenceKind demangleReferenceKind(StringView &MangledName); | 
|  | void demangleThrowSpecification(StringView &MangledName); | 
|  |  | 
|  | std::pair<Qualifiers, bool> demangleQualifiers(StringView &MangledName); | 
|  |  | 
|  | // Memory allocator. | 
|  | ArenaAllocator Arena; | 
|  |  | 
|  | // A single type uses one global back-ref table for all function params. | 
|  | // This means back-refs can even go "into" other types.  Examples: | 
|  | // | 
|  | //  // Second int* is a back-ref to first. | 
|  | //  void foo(int *, int*); | 
|  | // | 
|  | //  // Second int* is not a back-ref to first (first is not a function param). | 
|  | //  int* foo(int*); | 
|  | // | 
|  | //  // Second int* is a back-ref to first (ALL function types share the same | 
|  | //  // back-ref map. | 
|  | //  using F = void(*)(int*); | 
|  | //  F G(int *); | 
|  | Type *FunctionParamBackRefs[10]; | 
|  | size_t FunctionParamBackRefCount = 0; | 
|  |  | 
|  | // The first 10 BackReferences in a mangled name can be back-referenced by | 
|  | // special name @[0-9]. This is a storage for the first 10 BackReferences. | 
|  | StringView BackReferences[10]; | 
|  | size_t BackRefCount = 0; | 
|  | }; | 
|  | } // namespace | 
|  |  | 
|  | StringView Demangler::copyString(StringView Borrowed) { | 
|  | char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1); | 
|  | std::strcpy(Stable, Borrowed.begin()); | 
|  |  | 
|  | return {Stable, Borrowed.size()}; | 
|  | } | 
|  |  | 
|  | // Parser entry point. | 
|  | Symbol *Demangler::parse(StringView &MangledName) { | 
|  | Symbol *S = Arena.alloc<Symbol>(); | 
|  |  | 
|  | // MSVC-style mangled symbols must start with '?'. | 
|  | if (!MangledName.consumeFront("?")) { | 
|  | S->SymbolName = Arena.alloc<Name>(); | 
|  | S->SymbolName->Str = MangledName; | 
|  | S->SymbolType = Arena.alloc<Type>(); | 
|  | S->SymbolType->Prim = PrimTy::Unknown; | 
|  | return S; | 
|  | } | 
|  |  | 
|  | // What follows is a main symbol name. This may include | 
|  | // namespaces or class BackReferences. | 
|  | S->SymbolName = demangleFullyQualifiedSymbolName(MangledName); | 
|  |  | 
|  | // Read a variable. | 
|  | S->SymbolType = startsWithDigit(MangledName) | 
|  | ? demangleVariableEncoding(MangledName) | 
|  | : demangleFunctionEncoding(MangledName); | 
|  |  | 
|  | return S; | 
|  | } | 
|  |  | 
|  | // <type-encoding> ::= <storage-class> <variable-type> | 
|  | // <storage-class> ::= 0  # private static member | 
|  | //                 ::= 1  # protected static member | 
|  | //                 ::= 2  # public static member | 
|  | //                 ::= 3  # global | 
|  | //                 ::= 4  # static local | 
|  |  | 
|  | Type *Demangler::demangleVariableEncoding(StringView &MangledName) { | 
|  | StorageClass SC = demangleVariableStorageClass(MangledName); | 
|  |  | 
|  | Type *Ty = demangleType(MangledName, QualifierMangleMode::Drop); | 
|  |  | 
|  | Ty->Storage = SC; | 
|  |  | 
|  | // <variable-type> ::= <type> <cvr-qualifiers> | 
|  | //                 ::= <type> <pointee-cvr-qualifiers> # pointers, references | 
|  | switch (Ty->Prim) { | 
|  | case PrimTy::Ptr: | 
|  | case PrimTy::MemberPtr: { | 
|  | Qualifiers ExtraChildQuals = Q_None; | 
|  | Ty->Quals = | 
|  | Qualifiers(Ty->Quals | demanglePointerExtQualifiers(MangledName)); | 
|  |  | 
|  | bool IsMember = false; | 
|  | std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName); | 
|  |  | 
|  | if (Ty->Prim == PrimTy::MemberPtr) { | 
|  | assert(IsMember); | 
|  | Name *BackRefName = demangleFullyQualifiedTypeName(MangledName); | 
|  | (void)BackRefName; | 
|  | MemberPointerType *MPTy = static_cast<MemberPointerType *>(Ty); | 
|  | MPTy->Pointee->Quals = Qualifiers(MPTy->Pointee->Quals | ExtraChildQuals); | 
|  | } else { | 
|  | PointerType *PTy = static_cast<PointerType *>(Ty); | 
|  | PTy->Pointee->Quals = Qualifiers(PTy->Pointee->Quals | ExtraChildQuals); | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | default: | 
|  | Ty->Quals = demangleQualifiers(MangledName).first; | 
|  | break; | 
|  | } | 
|  |  | 
|  | return Ty; | 
|  | } | 
|  |  | 
|  | // Sometimes numbers are encoded in mangled symbols. For example, | 
|  | // "int (*x)[20]" is a valid C type (x is a pointer to an array of | 
|  | // length 20), so we need some way to embed numbers as part of symbols. | 
|  | // This function parses it. | 
|  | // | 
|  | // <number>               ::= [?] <non-negative integer> | 
|  | // | 
|  | // <non-negative integer> ::= <decimal digit> # when 1 <= Number <= 10 | 
|  | //                        ::= <hex digit>+ @  # when Numbrer == 0 or >= 10 | 
|  | // | 
|  | // <hex-digit>            ::= [A-P]           # A = 0, B = 1, ... | 
|  | int Demangler::demangleNumber(StringView &MangledName) { | 
|  | bool neg = MangledName.consumeFront("?"); | 
|  |  | 
|  | if (startsWithDigit(MangledName)) { | 
|  | int32_t Ret = MangledName[0] - '0' + 1; | 
|  | MangledName = MangledName.dropFront(1); | 
|  | return neg ? -Ret : Ret; | 
|  | } | 
|  |  | 
|  | int Ret = 0; | 
|  | for (size_t i = 0; i < MangledName.size(); ++i) { | 
|  | char C = MangledName[i]; | 
|  | if (C == '@') { | 
|  | MangledName = MangledName.dropFront(i + 1); | 
|  | return neg ? -Ret : Ret; | 
|  | } | 
|  | if ('A' <= C && C <= 'P') { | 
|  | Ret = (Ret << 4) + (C - 'A'); | 
|  | continue; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | Error = true; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | // First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9. | 
|  | // Memorize it. | 
|  | void Demangler::memorizeString(StringView S) { | 
|  | if (BackRefCount >= sizeof(BackReferences) / sizeof(*BackReferences)) | 
|  | return; | 
|  | for (size_t i = 0; i < BackRefCount; ++i) | 
|  | if (S == BackReferences[i]) | 
|  | return; | 
|  | BackReferences[BackRefCount++] = S; | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleBackRefName(StringView &MangledName) { | 
|  | assert(startsWithDigit(MangledName)); | 
|  |  | 
|  | size_t I = MangledName[0] - '0'; | 
|  | if (I >= BackRefCount) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | MangledName = MangledName.dropFront(); | 
|  | Name *Node = Arena.alloc<Name>(); | 
|  | Node->Str = BackReferences[I]; | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleClassTemplateName(StringView &MangledName) { | 
|  | assert(MangledName.startsWith("?$")); | 
|  | MangledName.consumeFront("?$"); | 
|  |  | 
|  | Name *Node = demangleSimpleName(MangledName, false); | 
|  | Node->TParams = demangleTemplateParameterList(MangledName); | 
|  |  | 
|  | // Render this class template name into a string buffer so that we can | 
|  | // memorize it for the purpose of back-referencing. | 
|  | OutputStream OS = OutputStream::create(nullptr, nullptr, 1024); | 
|  | outputName(OS, Node); | 
|  | OS << '\0'; | 
|  | char *Name = OS.getBuffer(); | 
|  |  | 
|  | StringView Owned = copyString(Name); | 
|  | memorizeString(Owned); | 
|  | std::free(Name); | 
|  |  | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleOperatorName(StringView &MangledName) { | 
|  | assert(MangledName.startsWith('?')); | 
|  | MangledName.consumeFront('?'); | 
|  |  | 
|  | auto NameString = [this, &MangledName]() -> StringView { | 
|  | switch (MangledName.popFront()) { | 
|  | case '0': | 
|  | return "ctor"; | 
|  | case '1': | 
|  | return "dtor"; | 
|  | case '2': | 
|  | return " new"; | 
|  | case '3': | 
|  | return " delete"; | 
|  | case '4': | 
|  | return "="; | 
|  | case '5': | 
|  | return ">>"; | 
|  | case '6': | 
|  | return "<<"; | 
|  | case '7': | 
|  | return "!"; | 
|  | case '8': | 
|  | return "=="; | 
|  | case '9': | 
|  | return "!="; | 
|  | case 'A': | 
|  | return "[]"; | 
|  | case 'C': | 
|  | return "->"; | 
|  | case 'D': | 
|  | return "*"; | 
|  | case 'E': | 
|  | return "++"; | 
|  | case 'F': | 
|  | return "--"; | 
|  | case 'G': | 
|  | return "-"; | 
|  | case 'H': | 
|  | return "+"; | 
|  | case 'I': | 
|  | return "&"; | 
|  | case 'J': | 
|  | return "->*"; | 
|  | case 'K': | 
|  | return "/"; | 
|  | case 'L': | 
|  | return "%"; | 
|  | case 'M': | 
|  | return "<"; | 
|  | case 'N': | 
|  | return "<="; | 
|  | case 'O': | 
|  | return ">"; | 
|  | case 'P': | 
|  | return ">="; | 
|  | case 'Q': | 
|  | return ","; | 
|  | case 'R': | 
|  | return "()"; | 
|  | case 'S': | 
|  | return "~"; | 
|  | case 'T': | 
|  | return "^"; | 
|  | case 'U': | 
|  | return "|"; | 
|  | case 'V': | 
|  | return "&&"; | 
|  | case 'W': | 
|  | return "||"; | 
|  | case 'X': | 
|  | return "*="; | 
|  | case 'Y': | 
|  | return "+="; | 
|  | case 'Z': | 
|  | return "-="; | 
|  | case '_': { | 
|  | if (MangledName.empty()) | 
|  | break; | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | case '0': | 
|  | return "/="; | 
|  | case '1': | 
|  | return "%="; | 
|  | case '2': | 
|  | return ">>="; | 
|  | case '3': | 
|  | return "<<="; | 
|  | case '4': | 
|  | return "&="; | 
|  | case '5': | 
|  | return "|="; | 
|  | case '6': | 
|  | return "^="; | 
|  | case 'U': | 
|  | return " new[]"; | 
|  | case 'V': | 
|  | return " delete[]"; | 
|  | case '_': | 
|  | if (MangledName.consumeFront("L")) | 
|  | return " co_await"; | 
|  | if (MangledName.consumeFront("K")) { | 
|  | size_t EndPos = MangledName.find('@'); | 
|  | if (EndPos == StringView::npos) | 
|  | break; | 
|  | StringView OpName = demangleSimpleString(MangledName, false); | 
|  | size_t FullSize = OpName.size() + 3; // <space>""OpName | 
|  | char *Buffer = Arena.allocUnalignedBuffer(FullSize); | 
|  | Buffer[0] = ' '; | 
|  | Buffer[1] = '"'; | 
|  | Buffer[2] = '"'; | 
|  | std::memcpy(Buffer + 3, OpName.begin(), OpName.size()); | 
|  | return {Buffer, FullSize}; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | Error = true; | 
|  | return ""; | 
|  | }; | 
|  |  | 
|  | Name *Node = Arena.alloc<Name>(); | 
|  | Node->Operator = NameString(); | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) { | 
|  | StringView S = demangleSimpleString(MangledName, Memorize); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | Name *Node = Arena.alloc<Name>(); | 
|  | Node->Str = S; | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | StringView Demangler::demangleSimpleString(StringView &MangledName, | 
|  | bool Memorize) { | 
|  | StringView S; | 
|  | for (size_t i = 0; i < MangledName.size(); ++i) { | 
|  | if (MangledName[i] != '@') | 
|  | continue; | 
|  | S = MangledName.substr(0, i); | 
|  | MangledName = MangledName.dropFront(i + 1); | 
|  |  | 
|  | if (Memorize) | 
|  | memorizeString(S); | 
|  | return S; | 
|  | } | 
|  |  | 
|  | Error = true; | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleAnonymousNamespaceName(StringView &MangledName) { | 
|  | assert(MangledName.startsWith("?A")); | 
|  | MangledName.consumeFront("?A"); | 
|  |  | 
|  | Name *Node = Arena.alloc<Name>(); | 
|  | Node->Str = "`anonymous namespace'"; | 
|  | if (MangledName.consumeFront('@')) | 
|  | return Node; | 
|  |  | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) { | 
|  | assert(startsWithLocalScopePattern(MangledName)); | 
|  |  | 
|  | Name *Node = Arena.alloc<Name>(); | 
|  | MangledName.consumeFront('?'); | 
|  | int ScopeIdentifier = demangleNumber(MangledName); | 
|  |  | 
|  | // One ? to terminate the number | 
|  | MangledName.consumeFront('?'); | 
|  |  | 
|  | assert(!Error); | 
|  | Symbol *Scope = parse(MangledName); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | // Render the parent symbol's name into a buffer. | 
|  | OutputStream OS = OutputStream::create(nullptr, nullptr, 1024); | 
|  | OS << '`'; | 
|  | output(Scope, OS); | 
|  | OS << '\''; | 
|  | OS << "::`" << ScopeIdentifier << "'"; | 
|  | OS << '\0'; | 
|  | char *Result = OS.getBuffer(); | 
|  | Node->Str = copyString(Result); | 
|  | std::free(Result); | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | // Parses a type name in the form of A@B@C@@ which represents C::B::A. | 
|  | Name *Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) { | 
|  | Name *TypeName = demangleUnqualifiedTypeName(MangledName); | 
|  | assert(TypeName); | 
|  |  | 
|  | Name *QualName = demangleNameScopeChain(MangledName, TypeName); | 
|  | assert(QualName); | 
|  | return QualName; | 
|  | } | 
|  |  | 
|  | // Parses a symbol name in the form of A@B@C@@ which represents C::B::A. | 
|  | // Symbol names have slightly different rules regarding what can appear | 
|  | // so we separate out the implementations for flexibility. | 
|  | Name *Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) { | 
|  | Name *SymbolName = demangleUnqualifiedSymbolName(MangledName); | 
|  | assert(SymbolName); | 
|  |  | 
|  | Name *QualName = demangleNameScopeChain(MangledName, SymbolName); | 
|  | assert(QualName); | 
|  | return QualName; | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleUnqualifiedTypeName(StringView &MangledName) { | 
|  | // An inner-most name can be a back-reference, because a fully-qualified name | 
|  | // (e.g. Scope + Inner) can contain other fully qualified names inside of | 
|  | // them (for example template parameters), and these nested parameters can | 
|  | // refer to previously mangled types. | 
|  | if (startsWithDigit(MangledName)) | 
|  | return demangleBackRefName(MangledName); | 
|  |  | 
|  | if (MangledName.startsWith("?$")) | 
|  | return demangleClassTemplateName(MangledName); | 
|  |  | 
|  | return demangleSimpleName(MangledName, true); | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleUnqualifiedSymbolName(StringView &MangledName) { | 
|  | if (startsWithDigit(MangledName)) | 
|  | return demangleBackRefName(MangledName); | 
|  | if (MangledName.startsWith("?$")) | 
|  | return demangleClassTemplateName(MangledName); | 
|  | if (MangledName.startsWith('?')) | 
|  | return demangleOperatorName(MangledName); | 
|  | return demangleSimpleName(MangledName, true); | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleNameScopePiece(StringView &MangledName) { | 
|  | if (startsWithDigit(MangledName)) | 
|  | return demangleBackRefName(MangledName); | 
|  |  | 
|  | if (MangledName.startsWith("?$")) | 
|  | return demangleClassTemplateName(MangledName); | 
|  |  | 
|  | if (MangledName.startsWith("?A")) | 
|  | return demangleAnonymousNamespaceName(MangledName); | 
|  |  | 
|  | if (startsWithLocalScopePattern(MangledName)) | 
|  | return demangleLocallyScopedNamePiece(MangledName); | 
|  |  | 
|  | return demangleSimpleName(MangledName, true); | 
|  | } | 
|  |  | 
|  | Name *Demangler::demangleNameScopeChain(StringView &MangledName, | 
|  | Name *UnqualifiedName) { | 
|  | Name *Head = UnqualifiedName; | 
|  |  | 
|  | while (!MangledName.consumeFront("@")) { | 
|  | if (MangledName.empty()) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | assert(!Error); | 
|  | Name *Elem = demangleNameScopePiece(MangledName); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | Elem->Next = Head; | 
|  | Head = Elem; | 
|  | } | 
|  | return Head; | 
|  | } | 
|  |  | 
|  | FuncClass Demangler::demangleFunctionClass(StringView &MangledName) { | 
|  | SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName); | 
|  | RestoreOnError.shouldRestore(false); | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | case 'A': | 
|  | return Private; | 
|  | case 'B': | 
|  | return FuncClass(Private | Far); | 
|  | case 'C': | 
|  | return FuncClass(Private | Static); | 
|  | case 'D': | 
|  | return FuncClass(Private | Static); | 
|  | case 'E': | 
|  | return FuncClass(Private | Virtual); | 
|  | case 'F': | 
|  | return FuncClass(Private | Virtual); | 
|  | case 'I': | 
|  | return Protected; | 
|  | case 'J': | 
|  | return FuncClass(Protected | Far); | 
|  | case 'K': | 
|  | return FuncClass(Protected | Static); | 
|  | case 'L': | 
|  | return FuncClass(Protected | Static | Far); | 
|  | case 'M': | 
|  | return FuncClass(Protected | Virtual); | 
|  | case 'N': | 
|  | return FuncClass(Protected | Virtual | Far); | 
|  | case 'Q': | 
|  | return Public; | 
|  | case 'R': | 
|  | return FuncClass(Public | Far); | 
|  | case 'S': | 
|  | return FuncClass(Public | Static); | 
|  | case 'T': | 
|  | return FuncClass(Public | Static | Far); | 
|  | case 'U': | 
|  | return FuncClass(Public | Virtual); | 
|  | case 'V': | 
|  | return FuncClass(Public | Virtual | Far); | 
|  | case 'Y': | 
|  | return Global; | 
|  | case 'Z': | 
|  | return FuncClass(Global | Far); | 
|  | } | 
|  |  | 
|  | Error = true; | 
|  | RestoreOnError.shouldRestore(true); | 
|  | return Public; | 
|  | } | 
|  |  | 
|  | CallingConv Demangler::demangleCallingConvention(StringView &MangledName) { | 
|  | switch (MangledName.popFront()) { | 
|  | case 'A': | 
|  | case 'B': | 
|  | return CallingConv::Cdecl; | 
|  | case 'C': | 
|  | case 'D': | 
|  | return CallingConv::Pascal; | 
|  | case 'E': | 
|  | case 'F': | 
|  | return CallingConv::Thiscall; | 
|  | case 'G': | 
|  | case 'H': | 
|  | return CallingConv::Stdcall; | 
|  | case 'I': | 
|  | case 'J': | 
|  | return CallingConv::Fastcall; | 
|  | case 'M': | 
|  | case 'N': | 
|  | return CallingConv::Clrcall; | 
|  | case 'O': | 
|  | case 'P': | 
|  | return CallingConv::Eabi; | 
|  | case 'Q': | 
|  | return CallingConv::Vectorcall; | 
|  | } | 
|  |  | 
|  | return CallingConv::None; | 
|  | } | 
|  |  | 
|  | StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) { | 
|  | assert(std::isdigit(MangledName.front())); | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | case '0': | 
|  | return StorageClass::PrivateStatic; | 
|  | case '1': | 
|  | return StorageClass::ProtectedStatic; | 
|  | case '2': | 
|  | return StorageClass::PublicStatic; | 
|  | case '3': | 
|  | return StorageClass::Global; | 
|  | case '4': | 
|  | return StorageClass::FunctionLocalStatic; | 
|  | } | 
|  | Error = true; | 
|  | return StorageClass::None; | 
|  | } | 
|  |  | 
|  | std::pair<Qualifiers, bool> | 
|  | Demangler::demangleQualifiers(StringView &MangledName) { | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | // Member qualifiers | 
|  | case 'Q': | 
|  | return std::make_pair(Q_None, true); | 
|  | case 'R': | 
|  | return std::make_pair(Q_Const, true); | 
|  | case 'S': | 
|  | return std::make_pair(Q_Volatile, true); | 
|  | case 'T': | 
|  | return std::make_pair(Qualifiers(Q_Const | Q_Volatile), true); | 
|  | // Non-Member qualifiers | 
|  | case 'A': | 
|  | return std::make_pair(Q_None, false); | 
|  | case 'B': | 
|  | return std::make_pair(Q_Const, false); | 
|  | case 'C': | 
|  | return std::make_pair(Q_Volatile, false); | 
|  | case 'D': | 
|  | return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false); | 
|  | } | 
|  | Error = true; | 
|  | return std::make_pair(Q_None, false); | 
|  | } | 
|  |  | 
|  | static bool isTagType(StringView S) { | 
|  | switch (S.front()) { | 
|  | case 'T': // union | 
|  | case 'U': // struct | 
|  | case 'V': // class | 
|  | case 'W': // enum | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool isPointerType(StringView S) { | 
|  | if (S.startsWith("$$Q")) // foo && | 
|  | return true; | 
|  |  | 
|  | switch (S.front()) { | 
|  | case 'A': // foo & | 
|  | case 'P': // foo * | 
|  | case 'Q': // foo *const | 
|  | case 'R': // foo *volatile | 
|  | case 'S': // foo *const volatile | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool isArrayType(StringView S) { return S[0] == 'Y'; } | 
|  |  | 
|  | static bool isFunctionType(StringView S) { | 
|  | return S.startsWith("$$A8@@") || S.startsWith("$$A6"); | 
|  | } | 
|  |  | 
|  | // <variable-type> ::= <type> <cvr-qualifiers> | 
|  | //                 ::= <type> <pointee-cvr-qualifiers> # pointers, references | 
|  | Type *Demangler::demangleType(StringView &MangledName, | 
|  | QualifierMangleMode QMM) { | 
|  | Qualifiers Quals = Q_None; | 
|  | bool IsMember = false; | 
|  | bool IsMemberKnown = false; | 
|  | if (QMM == QualifierMangleMode::Mangle) { | 
|  | std::tie(Quals, IsMember) = demangleQualifiers(MangledName); | 
|  | IsMemberKnown = true; | 
|  | } else if (QMM == QualifierMangleMode::Result) { | 
|  | if (MangledName.consumeFront('?')) { | 
|  | std::tie(Quals, IsMember) = demangleQualifiers(MangledName); | 
|  | IsMemberKnown = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | Type *Ty = nullptr; | 
|  | if (isTagType(MangledName)) | 
|  | Ty = demangleClassType(MangledName); | 
|  | else if (isPointerType(MangledName)) { | 
|  | if (!IsMemberKnown) | 
|  | IsMember = isMemberPointer(MangledName); | 
|  |  | 
|  | if (IsMember) | 
|  | Ty = demangleMemberPointerType(MangledName); | 
|  | else | 
|  | Ty = demanglePointerType(MangledName); | 
|  | } else if (isArrayType(MangledName)) | 
|  | Ty = demangleArrayType(MangledName); | 
|  | else if (isFunctionType(MangledName)) { | 
|  | if (MangledName.consumeFront("$$A8@@")) | 
|  | Ty = demangleFunctionType(MangledName, true, false); | 
|  | else { | 
|  | assert(MangledName.startsWith("$$A6")); | 
|  | MangledName.consumeFront("$$A6"); | 
|  | Ty = demangleFunctionType(MangledName, false, false); | 
|  | } | 
|  | } else { | 
|  | Ty = demangleBasicType(MangledName); | 
|  | assert(Ty && !Error); | 
|  | if (!Ty || Error) | 
|  | return Ty; | 
|  | } | 
|  |  | 
|  | Ty->Quals = Qualifiers(Ty->Quals | Quals); | 
|  | return Ty; | 
|  | } | 
|  |  | 
|  | ReferenceKind Demangler::demangleReferenceKind(StringView &MangledName) { | 
|  | if (MangledName.consumeFront('G')) | 
|  | return ReferenceKind::LValueRef; | 
|  | else if (MangledName.consumeFront('H')) | 
|  | return ReferenceKind::RValueRef; | 
|  | return ReferenceKind::None; | 
|  | } | 
|  |  | 
|  | void Demangler::demangleThrowSpecification(StringView &MangledName) { | 
|  | if (MangledName.consumeFront('Z')) | 
|  | return; | 
|  |  | 
|  | Error = true; | 
|  | } | 
|  |  | 
|  | FunctionType *Demangler::demangleFunctionType(StringView &MangledName, | 
|  | bool HasThisQuals, | 
|  | bool IsFunctionPointer) { | 
|  | FunctionType *FTy = Arena.alloc<FunctionType>(); | 
|  | FTy->Prim = PrimTy::Function; | 
|  | FTy->IsFunctionPointer = IsFunctionPointer; | 
|  |  | 
|  | if (HasThisQuals) { | 
|  | FTy->Quals = demanglePointerExtQualifiers(MangledName); | 
|  | FTy->RefKind = demangleReferenceKind(MangledName); | 
|  | FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers(MangledName).first); | 
|  | } | 
|  |  | 
|  | // Fields that appear on both member and non-member functions. | 
|  | FTy->CallConvention = demangleCallingConvention(MangledName); | 
|  |  | 
|  | // <return-type> ::= <type> | 
|  | //               ::= @ # structors (they have no declared return type) | 
|  | bool IsStructor = MangledName.consumeFront('@'); | 
|  | if (!IsStructor) | 
|  | FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result); | 
|  |  | 
|  | FTy->Params = demangleFunctionParameterList(MangledName); | 
|  |  | 
|  | demangleThrowSpecification(MangledName); | 
|  |  | 
|  | return FTy; | 
|  | } | 
|  |  | 
|  | Type *Demangler::demangleFunctionEncoding(StringView &MangledName) { | 
|  | FuncClass FC = demangleFunctionClass(MangledName); | 
|  |  | 
|  | bool HasThisQuals = !(FC & (Global | Static)); | 
|  | FunctionType *FTy = demangleFunctionType(MangledName, HasThisQuals, false); | 
|  | FTy->FunctionClass = FC; | 
|  |  | 
|  | return FTy; | 
|  | } | 
|  |  | 
|  | // Reads a primitive type. | 
|  | Type *Demangler::demangleBasicType(StringView &MangledName) { | 
|  | Type *Ty = Arena.alloc<Type>(); | 
|  |  | 
|  | if (MangledName.consumeFront("$$T")) { | 
|  | Ty->Prim = PrimTy::Nullptr; | 
|  | return Ty; | 
|  | } | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | case 'X': | 
|  | Ty->Prim = PrimTy::Void; | 
|  | break; | 
|  | case 'D': | 
|  | Ty->Prim = PrimTy::Char; | 
|  | break; | 
|  | case 'C': | 
|  | Ty->Prim = PrimTy::Schar; | 
|  | break; | 
|  | case 'E': | 
|  | Ty->Prim = PrimTy::Uchar; | 
|  | break; | 
|  | case 'F': | 
|  | Ty->Prim = PrimTy::Short; | 
|  | break; | 
|  | case 'G': | 
|  | Ty->Prim = PrimTy::Ushort; | 
|  | break; | 
|  | case 'H': | 
|  | Ty->Prim = PrimTy::Int; | 
|  | break; | 
|  | case 'I': | 
|  | Ty->Prim = PrimTy::Uint; | 
|  | break; | 
|  | case 'J': | 
|  | Ty->Prim = PrimTy::Long; | 
|  | break; | 
|  | case 'K': | 
|  | Ty->Prim = PrimTy::Ulong; | 
|  | break; | 
|  | case 'M': | 
|  | Ty->Prim = PrimTy::Float; | 
|  | break; | 
|  | case 'N': | 
|  | Ty->Prim = PrimTy::Double; | 
|  | break; | 
|  | case 'O': | 
|  | Ty->Prim = PrimTy::Ldouble; | 
|  | break; | 
|  | case '_': { | 
|  | if (MangledName.empty()) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  | switch (MangledName.popFront()) { | 
|  | case 'N': | 
|  | Ty->Prim = PrimTy::Bool; | 
|  | break; | 
|  | case 'J': | 
|  | Ty->Prim = PrimTy::Int64; | 
|  | break; | 
|  | case 'K': | 
|  | Ty->Prim = PrimTy::Uint64; | 
|  | break; | 
|  | case 'W': | 
|  | Ty->Prim = PrimTy::Wchar; | 
|  | break; | 
|  | case 'S': | 
|  | Ty->Prim = PrimTy::Char16; | 
|  | break; | 
|  | case 'U': | 
|  | Ty->Prim = PrimTy::Char32; | 
|  | break; | 
|  | default: | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  | break; | 
|  | } | 
|  | default: | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  | return Ty; | 
|  | } | 
|  |  | 
|  | UdtType *Demangler::demangleClassType(StringView &MangledName) { | 
|  | UdtType *UTy = Arena.alloc<UdtType>(); | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | case 'T': | 
|  | UTy->Prim = PrimTy::Union; | 
|  | break; | 
|  | case 'U': | 
|  | UTy->Prim = PrimTy::Struct; | 
|  | break; | 
|  | case 'V': | 
|  | UTy->Prim = PrimTy::Class; | 
|  | break; | 
|  | case 'W': | 
|  | if (MangledName.popFront() != '4') { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  | UTy->Prim = PrimTy::Enum; | 
|  | break; | 
|  | default: | 
|  | assert(false); | 
|  | } | 
|  |  | 
|  | UTy->UdtName = demangleFullyQualifiedTypeName(MangledName); | 
|  | return UTy; | 
|  | } | 
|  |  | 
|  | static std::pair<Qualifiers, PointerAffinity> | 
|  | demanglePointerCVQualifiers(StringView &MangledName) { | 
|  | if (MangledName.consumeFront("$$Q")) | 
|  | return std::make_pair(Q_None, PointerAffinity::RValueReference); | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | case 'A': | 
|  | return std::make_pair(Q_None, PointerAffinity::Reference); | 
|  | case 'P': | 
|  | return std::make_pair(Q_None, PointerAffinity::Pointer); | 
|  | case 'Q': | 
|  | return std::make_pair(Q_Const, PointerAffinity::Pointer); | 
|  | case 'R': | 
|  | return std::make_pair(Q_Volatile, PointerAffinity::Pointer); | 
|  | case 'S': | 
|  | return std::make_pair(Qualifiers(Q_Const | Q_Volatile), | 
|  | PointerAffinity::Pointer); | 
|  | default: | 
|  | assert(false && "Ty is not a pointer type!"); | 
|  | } | 
|  | return std::make_pair(Q_None, PointerAffinity::Pointer); | 
|  | } | 
|  |  | 
|  | // <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type> | 
|  | //                       # the E is required for 64-bit non-static pointers | 
|  | PointerType *Demangler::demanglePointerType(StringView &MangledName) { | 
|  | PointerType *Pointer = Arena.alloc<PointerType>(); | 
|  |  | 
|  | std::tie(Pointer->Quals, Pointer->Affinity) = | 
|  | demanglePointerCVQualifiers(MangledName); | 
|  |  | 
|  | Pointer->Prim = PrimTy::Ptr; | 
|  | if (MangledName.consumeFront("6")) { | 
|  | Pointer->Pointee = demangleFunctionType(MangledName, false, true); | 
|  | return Pointer; | 
|  | } | 
|  |  | 
|  | Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); | 
|  | Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); | 
|  |  | 
|  | Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle); | 
|  | return Pointer; | 
|  | } | 
|  |  | 
|  | MemberPointerType * | 
|  | Demangler::demangleMemberPointerType(StringView &MangledName) { | 
|  | MemberPointerType *Pointer = Arena.alloc<MemberPointerType>(); | 
|  | Pointer->Prim = PrimTy::MemberPtr; | 
|  |  | 
|  | PointerAffinity Affinity; | 
|  | std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName); | 
|  | assert(Affinity == PointerAffinity::Pointer); | 
|  |  | 
|  | Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); | 
|  | Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); | 
|  |  | 
|  | if (MangledName.consumeFront("8")) { | 
|  | Pointer->MemberName = demangleFullyQualifiedSymbolName(MangledName); | 
|  | Pointer->Pointee = demangleFunctionType(MangledName, true, true); | 
|  | } else { | 
|  | Qualifiers PointeeQuals = Q_None; | 
|  | bool IsMember = false; | 
|  | std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName); | 
|  | assert(IsMember); | 
|  | Pointer->MemberName = demangleFullyQualifiedSymbolName(MangledName); | 
|  |  | 
|  | Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop); | 
|  | Pointer->Pointee->Quals = PointeeQuals; | 
|  | } | 
|  |  | 
|  | return Pointer; | 
|  | } | 
|  |  | 
|  | Qualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) { | 
|  | Qualifiers Quals = Q_None; | 
|  | if (MangledName.consumeFront('E')) | 
|  | Quals = Qualifiers(Quals | Q_Pointer64); | 
|  | if (MangledName.consumeFront('I')) | 
|  | Quals = Qualifiers(Quals | Q_Restrict); | 
|  | if (MangledName.consumeFront('F')) | 
|  | Quals = Qualifiers(Quals | Q_Unaligned); | 
|  |  | 
|  | return Quals; | 
|  | } | 
|  |  | 
|  | ArrayType *Demangler::demangleArrayType(StringView &MangledName) { | 
|  | assert(MangledName.front() == 'Y'); | 
|  | MangledName.popFront(); | 
|  |  | 
|  | int Dimension = demangleNumber(MangledName); | 
|  | if (Dimension <= 0) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | ArrayType *ATy = Arena.alloc<ArrayType>(); | 
|  | ArrayType *Dim = ATy; | 
|  | for (int I = 0; I < Dimension; ++I) { | 
|  | Dim->Prim = PrimTy::Array; | 
|  | Dim->ArrayDimension = demangleNumber(MangledName); | 
|  | Dim->NextDimension = Arena.alloc<ArrayType>(); | 
|  | Dim = Dim->NextDimension; | 
|  | } | 
|  |  | 
|  | if (MangledName.consumeFront("$$C")) { | 
|  | if (MangledName.consumeFront("B")) | 
|  | ATy->Quals = Q_Const; | 
|  | else if (MangledName.consumeFront("C") || MangledName.consumeFront("D")) | 
|  | ATy->Quals = Qualifiers(Q_Const | Q_Volatile); | 
|  | else if (!MangledName.consumeFront("A")) | 
|  | Error = true; | 
|  | } | 
|  |  | 
|  | ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop); | 
|  | Dim->ElementType = ATy->ElementType; | 
|  | return ATy; | 
|  | } | 
|  |  | 
|  | // Reads a function or a template parameters. | 
|  | FunctionParams | 
|  | Demangler::demangleFunctionParameterList(StringView &MangledName) { | 
|  | // Empty parameter list. | 
|  | if (MangledName.consumeFront('X')) | 
|  | return {}; | 
|  |  | 
|  | FunctionParams *Head; | 
|  | FunctionParams **Current = &Head; | 
|  | while (!Error && !MangledName.startsWith('@') && | 
|  | !MangledName.startsWith('Z')) { | 
|  |  | 
|  | if (startsWithDigit(MangledName)) { | 
|  | size_t N = MangledName[0] - '0'; | 
|  | if (N >= FunctionParamBackRefCount) { | 
|  | Error = true; | 
|  | return {}; | 
|  | } | 
|  | MangledName = MangledName.dropFront(); | 
|  |  | 
|  | *Current = Arena.alloc<FunctionParams>(); | 
|  | (*Current)->Current = FunctionParamBackRefs[N]->clone(Arena); | 
|  | Current = &(*Current)->Next; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | size_t OldSize = MangledName.size(); | 
|  |  | 
|  | *Current = Arena.alloc<FunctionParams>(); | 
|  | (*Current)->Current = demangleType(MangledName, QualifierMangleMode::Drop); | 
|  |  | 
|  | size_t CharsConsumed = OldSize - MangledName.size(); | 
|  | assert(CharsConsumed != 0); | 
|  |  | 
|  | // Single-letter types are ignored for backreferences because memorizing | 
|  | // them doesn't save anything. | 
|  | if (FunctionParamBackRefCount <= 9 && CharsConsumed > 1) | 
|  | FunctionParamBackRefs[FunctionParamBackRefCount++] = (*Current)->Current; | 
|  |  | 
|  | Current = &(*Current)->Next; | 
|  | } | 
|  |  | 
|  | if (Error) | 
|  | return {}; | 
|  |  | 
|  | // A non-empty parameter list is terminated by either 'Z' (variadic) parameter | 
|  | // list or '@' (non variadic).  Careful not to consume "@Z", as in that case | 
|  | // the following Z could be a throw specifier. | 
|  | if (MangledName.consumeFront('@')) | 
|  | return *Head; | 
|  |  | 
|  | if (MangledName.consumeFront('Z')) { | 
|  | Head->IsVariadic = true; | 
|  | return *Head; | 
|  | } | 
|  |  | 
|  | Error = true; | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | TemplateParams * | 
|  | Demangler::demangleTemplateParameterList(StringView &MangledName) { | 
|  | TemplateParams *Head; | 
|  | TemplateParams **Current = &Head; | 
|  | while (!Error && !MangledName.startsWith('@')) { | 
|  | // Template parameter lists don't participate in back-referencing. | 
|  | *Current = Arena.alloc<TemplateParams>(); | 
|  |  | 
|  | // Empty parameter pack. | 
|  | if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") || | 
|  | MangledName.consumeFront("$$$V")) { | 
|  | if (!MangledName.startsWith('@')) | 
|  | Error = true; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (MangledName.consumeFront("$$Y")) { | 
|  | (*Current)->IsTemplateTemplate = true; | 
|  | (*Current)->IsAliasTemplate = true; | 
|  | (*Current)->ParamName = demangleFullyQualifiedTypeName(MangledName); | 
|  | } else if (MangledName.consumeFront("$1?")) { | 
|  | (*Current)->ParamName = demangleFullyQualifiedSymbolName(MangledName); | 
|  | (*Current)->ParamType = demangleFunctionEncoding(MangledName); | 
|  | } else { | 
|  | (*Current)->ParamType = | 
|  | demangleType(MangledName, QualifierMangleMode::Drop); | 
|  | } | 
|  |  | 
|  | Current = &(*Current)->Next; | 
|  | } | 
|  |  | 
|  | if (Error) | 
|  | return {}; | 
|  |  | 
|  | // Template parameter lists cannot be variadic, so it can only be terminated | 
|  | // by @. | 
|  | if (MangledName.consumeFront('@')) | 
|  | return Head; | 
|  | Error = true; | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | void Demangler::output(const Symbol *S, OutputStream &OS) { | 
|  | // Converts an AST to a string. | 
|  | // | 
|  | // Converting an AST representing a C++ type to a string is tricky due | 
|  | // to the bad grammar of the C++ declaration inherited from C. You have | 
|  | // to construct a string from inside to outside. For example, if a type | 
|  | // X is a pointer to a function returning int, the order you create a | 
|  | // string becomes something like this: | 
|  | // | 
|  | //   (1) X is a pointer: *X | 
|  | //   (2) (1) is a function returning int: int (*X)() | 
|  | // | 
|  | // So you cannot construct a result just by appending strings to a result. | 
|  | // | 
|  | // To deal with this, we split the function into two. outputPre() writes | 
|  | // the "first half" of type declaration, and outputPost() writes the | 
|  | // "second half". For example, outputPre() writes a return type for a | 
|  | // function and outputPost() writes an parameter list. | 
|  | Type::outputPre(OS, *S->SymbolType); | 
|  | outputName(OS, S->SymbolName); | 
|  | Type::outputPost(OS, *S->SymbolType); | 
|  | } | 
|  |  | 
|  | char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N, | 
|  | int *Status) { | 
|  | Demangler D; | 
|  | StringView Name{MangledName}; | 
|  | Symbol *S = D.parse(Name); | 
|  |  | 
|  | if (D.Error) | 
|  | *Status = llvm::demangle_invalid_mangled_name; | 
|  | else | 
|  | *Status = llvm::demangle_success; | 
|  |  | 
|  | OutputStream OS = OutputStream::create(Buf, N, 1024); | 
|  | D.output(S, OS); | 
|  | OS << '\0'; | 
|  | return OS.getBuffer(); | 
|  | } |