|  | //===- 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 "MicrosoftDemangleNodes.h" | 
|  | #include "llvm/Demangle/Demangle.h" | 
|  |  | 
|  | #include "llvm/Demangle/Compiler.h" | 
|  | #include "llvm/Demangle/StringView.h" | 
|  | #include "llvm/Demangle/Utility.h" | 
|  |  | 
|  | #include <array> | 
|  | #include <cctype> | 
|  | #include <cstdio> | 
|  | #include <tuple> | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace ms_demangle; | 
|  |  | 
|  | static bool startsWithDigit(StringView S) { | 
|  | return !S.empty() && std::isdigit(S.front()); | 
|  | } | 
|  |  | 
|  | enum class QualifierMangleMode { Drop, Mangle, Result }; | 
|  |  | 
|  | struct NodeList { | 
|  | Node *N = nullptr; | 
|  | NodeList *Next = nullptr; | 
|  | }; | 
|  |  | 
|  | enum class FunctionIdentifierCodeGroup { Basic, Under, DoubleUnder }; | 
|  |  | 
|  | enum NameBackrefBehavior : uint8_t { | 
|  | NBB_None = 0,          // don't save any names as backrefs. | 
|  | NBB_Template = 1 << 0, // save template instanations. | 
|  | NBB_Simple = 1 << 1,   // save simple names. | 
|  | }; | 
|  |  | 
|  | 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 SpecialIntrinsicKind | 
|  | consumeSpecialIntrinsicKind(StringView &MangledName) { | 
|  | if (MangledName.consumeFront("?_7")) | 
|  | return SpecialIntrinsicKind::Vftable; | 
|  | if (MangledName.consumeFront("?_8")) | 
|  | return SpecialIntrinsicKind::Vbtable; | 
|  | if (MangledName.consumeFront("?_9")) | 
|  | return SpecialIntrinsicKind::VcallThunk; | 
|  | if (MangledName.consumeFront("?_A")) | 
|  | return SpecialIntrinsicKind::Typeof; | 
|  | if (MangledName.consumeFront("?_B")) | 
|  | return SpecialIntrinsicKind::LocalStaticGuard; | 
|  | if (MangledName.consumeFront("?_C")) | 
|  | return SpecialIntrinsicKind::StringLiteralSymbol; | 
|  | if (MangledName.consumeFront("?_P")) | 
|  | return SpecialIntrinsicKind::UdtReturning; | 
|  | if (MangledName.consumeFront("?_R0")) | 
|  | return SpecialIntrinsicKind::RttiTypeDescriptor; | 
|  | if (MangledName.consumeFront("?_R1")) | 
|  | return SpecialIntrinsicKind::RttiBaseClassDescriptor; | 
|  | if (MangledName.consumeFront("?_R2")) | 
|  | return SpecialIntrinsicKind::RttiBaseClassArray; | 
|  | if (MangledName.consumeFront("?_R3")) | 
|  | return SpecialIntrinsicKind::RttiClassHierarchyDescriptor; | 
|  | if (MangledName.consumeFront("?_R4")) | 
|  | return SpecialIntrinsicKind::RttiCompleteObjLocator; | 
|  | if (MangledName.consumeFront("?_S")) | 
|  | return SpecialIntrinsicKind::LocalVftable; | 
|  | if (MangledName.consumeFront("?__E")) | 
|  | return SpecialIntrinsicKind::DynamicInitializer; | 
|  | if (MangledName.consumeFront("?__F")) | 
|  | return SpecialIntrinsicKind::DynamicAtexitDestructor; | 
|  | if (MangledName.consumeFront("?__J")) | 
|  | return SpecialIntrinsicKind::LocalStaticThreadGuard; | 
|  | return SpecialIntrinsicKind::None; | 
|  | } | 
|  |  | 
|  | 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 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 isCustomType(StringView S) { return S[0] == '?'; } | 
|  |  | 
|  | 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"); | 
|  | } | 
|  |  | 
|  | static FunctionRefQualifier | 
|  | demangleFunctionRefQualifier(StringView &MangledName) { | 
|  | if (MangledName.consumeFront('G')) | 
|  | return FunctionRefQualifier::Reference; | 
|  | else if (MangledName.consumeFront('H')) | 
|  | return FunctionRefQualifier::RValueReference; | 
|  | return FunctionRefQualifier::None; | 
|  | } | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct BackrefContext { | 
|  | static constexpr size_t Max = 10; | 
|  |  | 
|  | TypeNode *FunctionParams[Max]; | 
|  | size_t FunctionParamCount = 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. | 
|  | NamedIdentifierNode *Names[Max]; | 
|  | size_t NamesCount = 0; | 
|  | }; | 
|  |  | 
|  | // 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; | 
|  | virtual ~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. | 
|  | SymbolNode *parse(StringView &MangledName); | 
|  |  | 
|  | // True if an error occurred. | 
|  | bool Error = false; | 
|  |  | 
|  | void dumpBackReferences(); | 
|  |  | 
|  | private: | 
|  | SymbolNode *demangleEncodedSymbol(StringView &MangledName, | 
|  | QualifiedNameNode *QN); | 
|  |  | 
|  | VariableSymbolNode *demangleVariableEncoding(StringView &MangledName, | 
|  | StorageClass SC); | 
|  | FunctionSymbolNode *demangleFunctionEncoding(StringView &MangledName); | 
|  |  | 
|  | Qualifiers demanglePointerExtQualifiers(StringView &MangledName); | 
|  |  | 
|  | // Parser functions. This is a recursive-descent parser. | 
|  | TypeNode *demangleType(StringView &MangledName, QualifierMangleMode QMM); | 
|  | PrimitiveTypeNode *demanglePrimitiveType(StringView &MangledName); | 
|  | CustomTypeNode *demangleCustomType(StringView &MangledName); | 
|  | TagTypeNode *demangleClassType(StringView &MangledName); | 
|  | PointerTypeNode *demanglePointerType(StringView &MangledName); | 
|  | PointerTypeNode *demangleMemberPointerType(StringView &MangledName); | 
|  | FunctionSignatureNode *demangleFunctionType(StringView &MangledName, | 
|  | bool HasThisQuals); | 
|  |  | 
|  | ArrayTypeNode *demangleArrayType(StringView &MangledName); | 
|  |  | 
|  | NodeArrayNode *demangleTemplateParameterList(StringView &MangledName); | 
|  | NodeArrayNode *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); | 
|  | void memorizeIdentifier(IdentifierNode *Identifier); | 
|  |  | 
|  | /// Allocate a copy of \p Borrowed into memory that we own. | 
|  | StringView copyString(StringView Borrowed); | 
|  |  | 
|  | QualifiedNameNode *demangleFullyQualifiedTypeName(StringView &MangledName); | 
|  | QualifiedNameNode *demangleFullyQualifiedSymbolName(StringView &MangledName); | 
|  |  | 
|  | IdentifierNode *demangleUnqualifiedTypeName(StringView &MangledName, | 
|  | bool Memorize); | 
|  | IdentifierNode *demangleUnqualifiedSymbolName(StringView &MangledName, | 
|  | NameBackrefBehavior NBB); | 
|  |  | 
|  | QualifiedNameNode *demangleNameScopeChain(StringView &MangledName, | 
|  | IdentifierNode *UnqualifiedName); | 
|  | IdentifierNode *demangleNameScopePiece(StringView &MangledName); | 
|  |  | 
|  | NamedIdentifierNode *demangleBackRefName(StringView &MangledName); | 
|  | IdentifierNode *demangleTemplateInstantiationName(StringView &MangledName, | 
|  | NameBackrefBehavior NBB); | 
|  | IdentifierNode *demangleFunctionIdentifierCode(StringView &MangledName); | 
|  | IdentifierNode * | 
|  | demangleFunctionIdentifierCode(StringView &MangledName, | 
|  | FunctionIdentifierCodeGroup Group); | 
|  | StructorIdentifierNode *demangleStructorIdentifier(StringView &MangledName, | 
|  | bool IsDestructor); | 
|  | ConversionOperatorIdentifierNode * | 
|  | demangleConversionOperatorIdentifier(StringView &MangledName); | 
|  | LiteralOperatorIdentifierNode * | 
|  | demangleLiteralOperatorIdentifier(StringView &MangledName); | 
|  |  | 
|  | SymbolNode *demangleSpecialIntrinsic(StringView &MangledName); | 
|  | SpecialTableSymbolNode * | 
|  | demangleSpecialTableSymbolNode(StringView &MangledName, | 
|  | SpecialIntrinsicKind SIK); | 
|  | LocalStaticGuardVariableNode * | 
|  | demangleLocalStaticGuard(StringView &MangledName); | 
|  | VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena, | 
|  | StringView &MangledName, | 
|  | StringView VariableName); | 
|  | VariableSymbolNode * | 
|  | demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, | 
|  | StringView &MangledName); | 
|  | FunctionSymbolNode *demangleInitFiniStub(StringView &MangledName, | 
|  | bool IsDestructor); | 
|  |  | 
|  | NamedIdentifierNode *demangleSimpleName(StringView &MangledName, | 
|  | bool Memorize); | 
|  | NamedIdentifierNode *demangleAnonymousNamespaceName(StringView &MangledName); | 
|  | NamedIdentifierNode *demangleLocallyScopedNamePiece(StringView &MangledName); | 
|  | EncodedStringLiteralNode *demangleStringLiteral(StringView &MangledName); | 
|  | FunctionSymbolNode *demangleVcallThunkNode(StringView &MangledName); | 
|  |  | 
|  | StringView demangleSimpleString(StringView &MangledName, bool Memorize); | 
|  |  | 
|  | FuncClass demangleFunctionClass(StringView &MangledName); | 
|  | CallingConv demangleCallingConvention(StringView &MangledName); | 
|  | StorageClass demangleVariableStorageClass(StringView &MangledName); | 
|  | void demangleThrowSpecification(StringView &MangledName); | 
|  | wchar_t demangleWcharLiteral(StringView &MangledName); | 
|  | uint8_t demangleCharLiteral(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 *); | 
|  | BackrefContext Backrefs; | 
|  | }; | 
|  | } // namespace | 
|  |  | 
|  | StringView Demangler::copyString(StringView Borrowed) { | 
|  | char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1); | 
|  | std::strcpy(Stable, Borrowed.begin()); | 
|  |  | 
|  | return {Stable, Borrowed.size()}; | 
|  | } | 
|  |  | 
|  | SpecialTableSymbolNode * | 
|  | Demangler::demangleSpecialTableSymbolNode(StringView &MangledName, | 
|  | SpecialIntrinsicKind K) { | 
|  | NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>(); | 
|  | switch (K) { | 
|  | case SpecialIntrinsicKind::Vftable: | 
|  | NI->Name = "`vftable'"; | 
|  | break; | 
|  | case SpecialIntrinsicKind::Vbtable: | 
|  | NI->Name = "`vbtable'"; | 
|  | break; | 
|  | case SpecialIntrinsicKind::LocalVftable: | 
|  | NI->Name = "`local vftable'"; | 
|  | break; | 
|  | case SpecialIntrinsicKind::RttiCompleteObjLocator: | 
|  | NI->Name = "`RTTI Complete Object Locator'"; | 
|  | break; | 
|  | default: | 
|  | LLVM_BUILTIN_UNREACHABLE; | 
|  | } | 
|  | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI); | 
|  | SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>(); | 
|  | STSN->Name = QN; | 
|  | bool IsMember = false; | 
|  | char Front = MangledName.popFront(); | 
|  | if (Front != '6' && Front != '7') { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName); | 
|  | if (!MangledName.consumeFront('@')) | 
|  | STSN->TargetName = demangleFullyQualifiedTypeName(MangledName); | 
|  | return STSN; | 
|  | } | 
|  |  | 
|  | LocalStaticGuardVariableNode * | 
|  | Demangler::demangleLocalStaticGuard(StringView &MangledName) { | 
|  | LocalStaticGuardIdentifierNode *LSGI = | 
|  | Arena.alloc<LocalStaticGuardIdentifierNode>(); | 
|  | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, LSGI); | 
|  | LocalStaticGuardVariableNode *LSGVN = | 
|  | Arena.alloc<LocalStaticGuardVariableNode>(); | 
|  | LSGVN->Name = QN; | 
|  |  | 
|  | if (MangledName.consumeFront("4IA")) | 
|  | LSGVN->IsVisible = false; | 
|  | else if (MangledName.consumeFront("5")) | 
|  | LSGVN->IsVisible = true; | 
|  | else { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | if (!MangledName.empty()) | 
|  | LSGI->ScopeIndex = demangleUnsigned(MangledName); | 
|  | return LSGVN; | 
|  | } | 
|  |  | 
|  | static NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena, | 
|  | StringView Name) { | 
|  | NamedIdentifierNode *Id = Arena.alloc<NamedIdentifierNode>(); | 
|  | Id->Name = Name; | 
|  | return Id; | 
|  | } | 
|  |  | 
|  | static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena, | 
|  | IdentifierNode *Identifier) { | 
|  | QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>(); | 
|  | QN->Components = Arena.alloc<NodeArrayNode>(); | 
|  | QN->Components->Count = 1; | 
|  | QN->Components->Nodes = Arena.allocArray<Node *>(1); | 
|  | QN->Components->Nodes[0] = Identifier; | 
|  | return QN; | 
|  | } | 
|  |  | 
|  | static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena, | 
|  | StringView Name) { | 
|  | NamedIdentifierNode *Id = synthesizeNamedIdentifier(Arena, Name); | 
|  | return synthesizeQualifiedName(Arena, Id); | 
|  | } | 
|  |  | 
|  | static VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena, | 
|  | TypeNode *Type, | 
|  | StringView VariableName) { | 
|  | VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>(); | 
|  | VSN->Type = Type; | 
|  | VSN->Name = synthesizeQualifiedName(Arena, VariableName); | 
|  | return VSN; | 
|  | } | 
|  |  | 
|  | VariableSymbolNode *Demangler::demangleUntypedVariable( | 
|  | ArenaAllocator &Arena, StringView &MangledName, StringView VariableName) { | 
|  | NamedIdentifierNode *NI = synthesizeNamedIdentifier(Arena, VariableName); | 
|  | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI); | 
|  | VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>(); | 
|  | VSN->Name = QN; | 
|  | if (MangledName.consumeFront("8")) | 
|  | return VSN; | 
|  |  | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | VariableSymbolNode * | 
|  | Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, | 
|  | StringView &MangledName) { | 
|  | RttiBaseClassDescriptorNode *RBCDN = | 
|  | Arena.alloc<RttiBaseClassDescriptorNode>(); | 
|  | RBCDN->NVOffset = demangleUnsigned(MangledName); | 
|  | RBCDN->VBPtrOffset = demangleSigned(MangledName); | 
|  | RBCDN->VBTableOffset = demangleUnsigned(MangledName); | 
|  | RBCDN->Flags = demangleUnsigned(MangledName); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>(); | 
|  | VSN->Name = demangleNameScopeChain(MangledName, RBCDN); | 
|  | MangledName.consumeFront('8'); | 
|  | return VSN; | 
|  | } | 
|  |  | 
|  | FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName, | 
|  | bool IsDestructor) { | 
|  | DynamicStructorIdentifierNode *DSIN = | 
|  | Arena.alloc<DynamicStructorIdentifierNode>(); | 
|  | DSIN->IsDestructor = IsDestructor; | 
|  |  | 
|  | bool IsKnownStaticDataMember = false; | 
|  | if (MangledName.consumeFront('?')) | 
|  | IsKnownStaticDataMember = true; | 
|  |  | 
|  | QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName); | 
|  |  | 
|  | SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN); | 
|  | FunctionSymbolNode *FSN = nullptr; | 
|  | Symbol->Name = QN; | 
|  |  | 
|  | if (Symbol->kind() == NodeKind::VariableSymbol) { | 
|  | DSIN->Variable = static_cast<VariableSymbolNode *>(Symbol); | 
|  |  | 
|  | // Older versions of clang mangled this type of symbol incorrectly.  They | 
|  | // would omit the leading ? and they would only emit a single @ at the end. | 
|  | // The correct mangling is a leading ? and 2 trailing @ signs.  Handle | 
|  | // both cases. | 
|  | int AtCount = IsKnownStaticDataMember ? 2 : 1; | 
|  | for (int I = 0; I < AtCount; ++I) { | 
|  | if (MangledName.consumeFront('@')) | 
|  | continue; | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | FSN = demangleFunctionEncoding(MangledName); | 
|  | FSN->Name = synthesizeQualifiedName(Arena, DSIN); | 
|  | } else { | 
|  | if (IsKnownStaticDataMember) { | 
|  | // This was supposed to be a static data member, but we got a function. | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | FSN = static_cast<FunctionSymbolNode *>(Symbol); | 
|  | DSIN->Name = Symbol->Name; | 
|  | FSN->Name = synthesizeQualifiedName(Arena, DSIN); | 
|  | } | 
|  |  | 
|  | return FSN; | 
|  | } | 
|  |  | 
|  | SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) { | 
|  | SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName); | 
|  | if (SIK == SpecialIntrinsicKind::None) | 
|  | return nullptr; | 
|  |  | 
|  | switch (SIK) { | 
|  | case SpecialIntrinsicKind::StringLiteralSymbol: | 
|  | return demangleStringLiteral(MangledName); | 
|  | case SpecialIntrinsicKind::Vftable: | 
|  | case SpecialIntrinsicKind::Vbtable: | 
|  | case SpecialIntrinsicKind::LocalVftable: | 
|  | case SpecialIntrinsicKind::RttiCompleteObjLocator: | 
|  | return demangleSpecialTableSymbolNode(MangledName, SIK); | 
|  | case SpecialIntrinsicKind::VcallThunk: | 
|  | return demangleVcallThunkNode(MangledName); | 
|  | case SpecialIntrinsicKind::LocalStaticGuard: | 
|  | return demangleLocalStaticGuard(MangledName); | 
|  | case SpecialIntrinsicKind::RttiTypeDescriptor: { | 
|  | TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result); | 
|  | if (Error) | 
|  | break; | 
|  | if (!MangledName.consumeFront("@8")) | 
|  | break; | 
|  | if (!MangledName.empty()) | 
|  | break; | 
|  | return synthesizeVariable(Arena, T, "`RTTI Type Descriptor'"); | 
|  | } | 
|  | case SpecialIntrinsicKind::RttiBaseClassArray: | 
|  | return demangleUntypedVariable(Arena, MangledName, | 
|  | "`RTTI Base Class Array'"); | 
|  | case SpecialIntrinsicKind::RttiClassHierarchyDescriptor: | 
|  | return demangleUntypedVariable(Arena, MangledName, | 
|  | "`RTTI Class Hierarchy Descriptor'"); | 
|  | case SpecialIntrinsicKind::RttiBaseClassDescriptor: | 
|  | return demangleRttiBaseClassDescriptorNode(Arena, MangledName); | 
|  | case SpecialIntrinsicKind::DynamicInitializer: | 
|  | return demangleInitFiniStub(MangledName, false); | 
|  | case SpecialIntrinsicKind::DynamicAtexitDestructor: | 
|  | return demangleInitFiniStub(MangledName, true); | 
|  | default: | 
|  | break; | 
|  | } | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | IdentifierNode * | 
|  | Demangler::demangleFunctionIdentifierCode(StringView &MangledName) { | 
|  | assert(MangledName.startsWith('?')); | 
|  | MangledName = MangledName.dropFront(); | 
|  |  | 
|  | if (MangledName.consumeFront("__")) | 
|  | return demangleFunctionIdentifierCode( | 
|  | MangledName, FunctionIdentifierCodeGroup::DoubleUnder); | 
|  | else if (MangledName.consumeFront("_")) | 
|  | return demangleFunctionIdentifierCode(MangledName, | 
|  | FunctionIdentifierCodeGroup::Under); | 
|  | return demangleFunctionIdentifierCode(MangledName, | 
|  | FunctionIdentifierCodeGroup::Basic); | 
|  | } | 
|  |  | 
|  | StructorIdentifierNode * | 
|  | Demangler::demangleStructorIdentifier(StringView &MangledName, | 
|  | bool IsDestructor) { | 
|  | StructorIdentifierNode *N = Arena.alloc<StructorIdentifierNode>(); | 
|  | N->IsDestructor = IsDestructor; | 
|  | return N; | 
|  | } | 
|  |  | 
|  | ConversionOperatorIdentifierNode * | 
|  | Demangler::demangleConversionOperatorIdentifier(StringView &MangledName) { | 
|  | ConversionOperatorIdentifierNode *N = | 
|  | Arena.alloc<ConversionOperatorIdentifierNode>(); | 
|  | return N; | 
|  | } | 
|  |  | 
|  | LiteralOperatorIdentifierNode * | 
|  | Demangler::demangleLiteralOperatorIdentifier(StringView &MangledName) { | 
|  | LiteralOperatorIdentifierNode *N = | 
|  | Arena.alloc<LiteralOperatorIdentifierNode>(); | 
|  | N->Name = demangleSimpleString(MangledName, false); | 
|  | return N; | 
|  | } | 
|  |  | 
|  | IntrinsicFunctionKind | 
|  | translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group) { | 
|  | // Not all ? identifiers are intrinsics *functions*.  This function only maps | 
|  | // operator codes for the special functions, all others are handled elsewhere, | 
|  | // hence the IFK::None entries in the table. | 
|  | using IFK = IntrinsicFunctionKind; | 
|  | static IFK Basic[36] = { | 
|  | IFK::None,             // ?0 # Foo::Foo() | 
|  | IFK::None,             // ?1 # Foo::~Foo() | 
|  | IFK::New,              // ?2 # operator new | 
|  | IFK::Delete,           // ?3 # operator delete | 
|  | IFK::Assign,           // ?4 # operator= | 
|  | IFK::RightShift,       // ?5 # operator>> | 
|  | IFK::LeftShift,        // ?6 # operator<< | 
|  | IFK::LogicalNot,       // ?7 # operator! | 
|  | IFK::Equals,           // ?8 # operator== | 
|  | IFK::NotEquals,        // ?9 # operator!= | 
|  | IFK::ArraySubscript,   // ?A # operator[] | 
|  | IFK::None,             // ?B # Foo::operator <type>() | 
|  | IFK::Pointer,          // ?C # operator-> | 
|  | IFK::Dereference,      // ?D # operator* | 
|  | IFK::Increment,        // ?E # operator++ | 
|  | IFK::Decrement,        // ?F # operator-- | 
|  | IFK::Minus,            // ?G # operator- | 
|  | IFK::Plus,             // ?H # operator+ | 
|  | IFK::BitwiseAnd,       // ?I # operator& | 
|  | IFK::MemberPointer,    // ?J # operator->* | 
|  | IFK::Divide,           // ?K # operator/ | 
|  | IFK::Modulus,          // ?L # operator% | 
|  | IFK::LessThan,         // ?M operator< | 
|  | IFK::LessThanEqual,    // ?N operator<= | 
|  | IFK::GreaterThan,      // ?O operator> | 
|  | IFK::GreaterThanEqual, // ?P operator>= | 
|  | IFK::Comma,            // ?Q operator, | 
|  | IFK::Parens,           // ?R operator() | 
|  | IFK::BitwiseNot,       // ?S operator~ | 
|  | IFK::BitwiseXor,       // ?T operator^ | 
|  | IFK::BitwiseOr,        // ?U operator| | 
|  | IFK::LogicalAnd,       // ?V operator&& | 
|  | IFK::LogicalOr,        // ?W operator|| | 
|  | IFK::TimesEqual,       // ?X operator*= | 
|  | IFK::PlusEqual,        // ?Y operator+= | 
|  | IFK::MinusEqual,       // ?Z operator-= | 
|  | }; | 
|  | static IFK Under[36] = { | 
|  | IFK::DivEqual,           // ?_0 operator/= | 
|  | IFK::ModEqual,           // ?_1 operator%= | 
|  | IFK::RshEqual,           // ?_2 operator>>= | 
|  | IFK::LshEqual,           // ?_3 operator<<= | 
|  | IFK::BitwiseAndEqual,    // ?_4 operator&= | 
|  | IFK::BitwiseOrEqual,     // ?_5 operator|= | 
|  | IFK::BitwiseXorEqual,    // ?_6 operator^= | 
|  | IFK::None,               // ?_7 # vftable | 
|  | IFK::None,               // ?_8 # vbtable | 
|  | IFK::None,               // ?_9 # vcall | 
|  | IFK::None,               // ?_A # typeof | 
|  | IFK::None,               // ?_B # local static guard | 
|  | IFK::None,               // ?_C # string literal | 
|  | IFK::VbaseDtor,          // ?_D # vbase destructor | 
|  | IFK::VecDelDtor,         // ?_E # vector deleting destructor | 
|  | IFK::DefaultCtorClosure, // ?_F # default constructor closure | 
|  | IFK::ScalarDelDtor,      // ?_G # scalar deleting destructor | 
|  | IFK::VecCtorIter,        // ?_H # vector constructor iterator | 
|  | IFK::VecDtorIter,        // ?_I # vector destructor iterator | 
|  | IFK::VecVbaseCtorIter,   // ?_J # vector vbase constructor iterator | 
|  | IFK::VdispMap,           // ?_K # virtual displacement map | 
|  | IFK::EHVecCtorIter,      // ?_L # eh vector constructor iterator | 
|  | IFK::EHVecDtorIter,      // ?_M # eh vector destructor iterator | 
|  | IFK::EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator | 
|  | IFK::CopyCtorClosure,    // ?_O # copy constructor closure | 
|  | IFK::None,               // ?_P<name> # udt returning <name> | 
|  | IFK::None,               // ?_Q # <unknown> | 
|  | IFK::None,               // ?_R0 - ?_R4 # RTTI Codes | 
|  | IFK::None,               // ?_S # local vftable | 
|  | IFK::LocalVftableCtorClosure, // ?_T # local vftable constructor closure | 
|  | IFK::ArrayNew,                // ?_U operator new[] | 
|  | IFK::ArrayDelete,             // ?_V operator delete[] | 
|  | IFK::None,                    // ?_W <unused> | 
|  | IFK::None,                    // ?_X <unused> | 
|  | IFK::None,                    // ?_Y <unused> | 
|  | IFK::None,                    // ?_Z <unused> | 
|  | }; | 
|  | static IFK DoubleUnder[36] = { | 
|  | IFK::None,                       // ?__0 <unused> | 
|  | IFK::None,                       // ?__1 <unused> | 
|  | IFK::None,                       // ?__2 <unused> | 
|  | IFK::None,                       // ?__3 <unused> | 
|  | IFK::None,                       // ?__4 <unused> | 
|  | IFK::None,                       // ?__5 <unused> | 
|  | IFK::None,                       // ?__6 <unused> | 
|  | IFK::None,                       // ?__7 <unused> | 
|  | IFK::None,                       // ?__8 <unused> | 
|  | IFK::None,                       // ?__9 <unused> | 
|  | IFK::ManVectorCtorIter,          // ?__A managed vector ctor iterator | 
|  | IFK::ManVectorDtorIter,          // ?__B managed vector dtor iterator | 
|  | IFK::EHVectorCopyCtorIter,       // ?__C EH vector copy ctor iterator | 
|  | IFK::EHVectorVbaseCopyCtorIter,  // ?__D EH vector vbase copy ctor iter | 
|  | IFK::None,                       // ?__E dynamic initializer for `T' | 
|  | IFK::None,                       // ?__F dynamic atexit destructor for `T' | 
|  | IFK::VectorCopyCtorIter,         // ?__G vector copy constructor iter | 
|  | IFK::VectorVbaseCopyCtorIter,    // ?__H vector vbase copy ctor iter | 
|  | IFK::ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy ctor | 
|  | // iter | 
|  | IFK::None,                       // ?__J local static thread guard | 
|  | IFK::None,                       // ?__K operator ""_name | 
|  | IFK::CoAwait,                    // ?__L co_await | 
|  | IFK::None,                       // ?__M <unused> | 
|  | IFK::None,                       // ?__N <unused> | 
|  | IFK::None,                       // ?__O <unused> | 
|  | IFK::None,                       // ?__P <unused> | 
|  | IFK::None,                       // ?__Q <unused> | 
|  | IFK::None,                       // ?__R <unused> | 
|  | IFK::None,                       // ?__S <unused> | 
|  | IFK::None,                       // ?__T <unused> | 
|  | IFK::None,                       // ?__U <unused> | 
|  | IFK::None,                       // ?__V <unused> | 
|  | IFK::None,                       // ?__W <unused> | 
|  | IFK::None,                       // ?__X <unused> | 
|  | IFK::None,                       // ?__Y <unused> | 
|  | IFK::None,                       // ?__Z <unused> | 
|  | }; | 
|  |  | 
|  | int Index = (CH >= '0' && CH <= '9') ? (CH - '0') : (CH - 'A' + 10); | 
|  | switch (Group) { | 
|  | case FunctionIdentifierCodeGroup::Basic: | 
|  | return Basic[Index]; | 
|  | case FunctionIdentifierCodeGroup::Under: | 
|  | return Under[Index]; | 
|  | case FunctionIdentifierCodeGroup::DoubleUnder: | 
|  | return DoubleUnder[Index]; | 
|  | } | 
|  | LLVM_BUILTIN_UNREACHABLE; | 
|  | } | 
|  |  | 
|  | IdentifierNode * | 
|  | Demangler::demangleFunctionIdentifierCode(StringView &MangledName, | 
|  | FunctionIdentifierCodeGroup Group) { | 
|  | switch (Group) { | 
|  | case FunctionIdentifierCodeGroup::Basic: | 
|  | switch (char CH = MangledName.popFront()) { | 
|  | case '0': | 
|  | case '1': | 
|  | return demangleStructorIdentifier(MangledName, CH == '1'); | 
|  | case 'B': | 
|  | return demangleConversionOperatorIdentifier(MangledName); | 
|  | default: | 
|  | return Arena.alloc<IntrinsicFunctionIdentifierNode>( | 
|  | translateIntrinsicFunctionCode(CH, Group)); | 
|  | } | 
|  | break; | 
|  | case FunctionIdentifierCodeGroup::Under: | 
|  | return Arena.alloc<IntrinsicFunctionIdentifierNode>( | 
|  | translateIntrinsicFunctionCode(MangledName.popFront(), Group)); | 
|  | case FunctionIdentifierCodeGroup::DoubleUnder: | 
|  | switch (char CH = MangledName.popFront()) { | 
|  | case 'K': | 
|  | return demangleLiteralOperatorIdentifier(MangledName); | 
|  | default: | 
|  | return Arena.alloc<IntrinsicFunctionIdentifierNode>( | 
|  | translateIntrinsicFunctionCode(CH, Group)); | 
|  | } | 
|  | } | 
|  | // No Mangling Yet:      Spaceship,                    // operator<=> | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName, | 
|  | QualifiedNameNode *Name) { | 
|  | // Read a variable. | 
|  | switch (MangledName.front()) { | 
|  | case '0': | 
|  | case '1': | 
|  | case '2': | 
|  | case '3': | 
|  | case '4': { | 
|  | StorageClass SC = demangleVariableStorageClass(MangledName); | 
|  | return demangleVariableEncoding(MangledName, SC); | 
|  | } | 
|  | case '8': | 
|  | return nullptr; | 
|  | } | 
|  | FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName); | 
|  |  | 
|  | IdentifierNode *UQN = Name->getUnqualifiedIdentifier(); | 
|  | if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) { | 
|  | ConversionOperatorIdentifierNode *COIN = | 
|  | static_cast<ConversionOperatorIdentifierNode *>(UQN); | 
|  | COIN->TargetType = FSN->Signature->ReturnType; | 
|  | } | 
|  | return FSN; | 
|  | } | 
|  |  | 
|  | // Parser entry point. | 
|  | SymbolNode *Demangler::parse(StringView &MangledName) { | 
|  | // We can't demangle MD5 names, just output them as-is. | 
|  | // Also, MSVC-style mangled symbols must start with '?'. | 
|  | if (MangledName.startsWith("??@")) { | 
|  | // This is an MD5 mangled name.  We can't demangle it, just return the | 
|  | // mangled name. | 
|  | SymbolNode *S = Arena.alloc<SymbolNode>(NodeKind::Md5Symbol); | 
|  | S->Name = synthesizeQualifiedName(Arena, MangledName); | 
|  | return S; | 
|  | } | 
|  |  | 
|  | if (!MangledName.startsWith('?')) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | MangledName.consumeFront('?'); | 
|  |  | 
|  | // ?$ is a template instantiation, but all other names that start with ? are | 
|  | // operators / special names. | 
|  | if (SymbolNode *SI = demangleSpecialIntrinsic(MangledName)) | 
|  | return SI; | 
|  |  | 
|  | // What follows is a main symbol name. This may include namespaces or class | 
|  | // back references. | 
|  | QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN); | 
|  | if (Symbol) { | 
|  | Symbol->Name = QN; | 
|  | } | 
|  |  | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | return Symbol; | 
|  | } | 
|  |  | 
|  | // <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 | 
|  |  | 
|  | VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName, | 
|  | StorageClass SC) { | 
|  | VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>(); | 
|  |  | 
|  | VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop); | 
|  | VSN->SC = SC; | 
|  |  | 
|  | // <variable-type> ::= <type> <cvr-qualifiers> | 
|  | //                 ::= <type> <pointee-cvr-qualifiers> # pointers, references | 
|  | switch (VSN->Type->kind()) { | 
|  | case NodeKind::PointerType: { | 
|  | PointerTypeNode *PTN = static_cast<PointerTypeNode *>(VSN->Type); | 
|  |  | 
|  | Qualifiers ExtraChildQuals = Q_None; | 
|  | PTN->Quals = Qualifiers(VSN->Type->Quals | | 
|  | demanglePointerExtQualifiers(MangledName)); | 
|  |  | 
|  | bool IsMember = false; | 
|  | std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName); | 
|  |  | 
|  | if (PTN->ClassParent) { | 
|  | QualifiedNameNode *BackRefName = | 
|  | demangleFullyQualifiedTypeName(MangledName); | 
|  | (void)BackRefName; | 
|  | } | 
|  | PTN->Pointee->Quals = Qualifiers(PTN->Pointee->Quals | ExtraChildQuals); | 
|  |  | 
|  | break; | 
|  | } | 
|  | default: | 
|  | VSN->Type->Quals = demangleQualifiers(MangledName).first; | 
|  | break; | 
|  | } | 
|  |  | 
|  | return VSN; | 
|  | } | 
|  |  | 
|  | // 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, ... | 
|  | std::pair<uint64_t, bool> Demangler::demangleNumber(StringView &MangledName) { | 
|  | bool IsNegative = MangledName.consumeFront('?'); | 
|  |  | 
|  | if (startsWithDigit(MangledName)) { | 
|  | uint64_t Ret = MangledName[0] - '0' + 1; | 
|  | MangledName = MangledName.dropFront(1); | 
|  | return {Ret, IsNegative}; | 
|  | } | 
|  |  | 
|  | uint64_t Ret = 0; | 
|  | for (size_t i = 0; i < MangledName.size(); ++i) { | 
|  | char C = MangledName[i]; | 
|  | if (C == '@') { | 
|  | MangledName = MangledName.dropFront(i + 1); | 
|  | return {Ret, IsNegative}; | 
|  | } | 
|  | if ('A' <= C && C <= 'P') { | 
|  | Ret = (Ret << 4) + (C - 'A'); | 
|  | continue; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | Error = true; | 
|  | 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) { | 
|  | if (Backrefs.NamesCount >= BackrefContext::Max) | 
|  | return; | 
|  | for (size_t i = 0; i < Backrefs.NamesCount; ++i) | 
|  | if (S == Backrefs.Names[i]->Name) | 
|  | return; | 
|  | NamedIdentifierNode *N = Arena.alloc<NamedIdentifierNode>(); | 
|  | N->Name = S; | 
|  | Backrefs.Names[Backrefs.NamesCount++] = N; | 
|  | } | 
|  |  | 
|  | NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) { | 
|  | assert(startsWithDigit(MangledName)); | 
|  |  | 
|  | size_t I = MangledName[0] - '0'; | 
|  | if (I >= Backrefs.NamesCount) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | MangledName = MangledName.dropFront(); | 
|  | return Backrefs.Names[I]; | 
|  | } | 
|  |  | 
|  | void Demangler::memorizeIdentifier(IdentifierNode *Identifier) { | 
|  | // Render this class template name into a string buffer so that we can | 
|  | // memorize it for the purpose of back-referencing. | 
|  | OutputStream OS; | 
|  | if (initializeOutputStream(nullptr, nullptr, OS, 1024)) | 
|  | // FIXME: Propagate out-of-memory as an error? | 
|  | std::terminate(); | 
|  | Identifier->output(OS, OF_Default); | 
|  | OS << '\0'; | 
|  | char *Name = OS.getBuffer(); | 
|  |  | 
|  | StringView Owned = copyString(Name); | 
|  | memorizeString(Owned); | 
|  | std::free(Name); | 
|  | } | 
|  |  | 
|  | IdentifierNode * | 
|  | Demangler::demangleTemplateInstantiationName(StringView &MangledName, | 
|  | NameBackrefBehavior NBB) { | 
|  | assert(MangledName.startsWith("?$")); | 
|  | MangledName.consumeFront("?$"); | 
|  |  | 
|  | BackrefContext OuterContext; | 
|  | std::swap(OuterContext, Backrefs); | 
|  |  | 
|  | IdentifierNode *Identifier = | 
|  | demangleUnqualifiedSymbolName(MangledName, NBB_Simple); | 
|  | if (!Error) | 
|  | Identifier->TemplateParams = demangleTemplateParameterList(MangledName); | 
|  |  | 
|  | std::swap(OuterContext, Backrefs); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | if (NBB & NBB_Template) | 
|  | memorizeIdentifier(Identifier); | 
|  |  | 
|  | return Identifier; | 
|  | } | 
|  |  | 
|  | NamedIdentifierNode *Demangler::demangleSimpleName(StringView &MangledName, | 
|  | bool Memorize) { | 
|  | StringView S = demangleSimpleString(MangledName, Memorize); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | NamedIdentifierNode *Name = Arena.alloc<NamedIdentifierNode>(); | 
|  | Name->Name = S; | 
|  | return Name; | 
|  | } | 
|  |  | 
|  | static bool isRebasedHexDigit(char C) { return (C >= 'A' && C <= 'P'); } | 
|  |  | 
|  | static uint8_t rebasedHexDigitToNumber(char C) { | 
|  | assert(isRebasedHexDigit(C)); | 
|  | return (C <= 'J') ? (C - 'A') : (10 + C - 'K'); | 
|  | } | 
|  |  | 
|  | uint8_t Demangler::demangleCharLiteral(StringView &MangledName) { | 
|  | if (!MangledName.startsWith('?')) | 
|  | return MangledName.popFront(); | 
|  |  | 
|  | MangledName = MangledName.dropFront(); | 
|  | if (MangledName.empty()) | 
|  | goto CharLiteralError; | 
|  |  | 
|  | if (MangledName.consumeFront('$')) { | 
|  | // Two hex digits | 
|  | if (MangledName.size() < 2) | 
|  | goto CharLiteralError; | 
|  | StringView Nibbles = MangledName.substr(0, 2); | 
|  | if (!isRebasedHexDigit(Nibbles[0]) || !isRebasedHexDigit(Nibbles[1])) | 
|  | goto CharLiteralError; | 
|  | // Don't append the null terminator. | 
|  | uint8_t C1 = rebasedHexDigitToNumber(Nibbles[0]); | 
|  | uint8_t C2 = rebasedHexDigitToNumber(Nibbles[1]); | 
|  | MangledName = MangledName.dropFront(2); | 
|  | return (C1 << 4) | C2; | 
|  | } | 
|  |  | 
|  | if (startsWithDigit(MangledName)) { | 
|  | const char *Lookup = ",/\\:. \n\t'-"; | 
|  | char C = Lookup[MangledName[0] - '0']; | 
|  | MangledName = MangledName.dropFront(); | 
|  | return C; | 
|  | } | 
|  |  | 
|  | if (MangledName[0] >= 'a' && MangledName[0] <= 'z') { | 
|  | char Lookup[26] = {'\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7', | 
|  | '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', | 
|  | '\xEF', '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', | 
|  | '\xF6', '\xF7', '\xF8', '\xF9', '\xFA'}; | 
|  | char C = Lookup[MangledName[0] - 'a']; | 
|  | MangledName = MangledName.dropFront(); | 
|  | return C; | 
|  | } | 
|  |  | 
|  | if (MangledName[0] >= 'A' && MangledName[0] <= 'Z') { | 
|  | char Lookup[26] = {'\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', | 
|  | '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', | 
|  | '\xCF', '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', | 
|  | '\xD6', '\xD7', '\xD8', '\xD9', '\xDA'}; | 
|  | char C = Lookup[MangledName[0] - 'A']; | 
|  | MangledName = MangledName.dropFront(); | 
|  | return C; | 
|  | } | 
|  |  | 
|  | CharLiteralError: | 
|  | Error = true; | 
|  | return '\0'; | 
|  | } | 
|  |  | 
|  | wchar_t Demangler::demangleWcharLiteral(StringView &MangledName) { | 
|  | uint8_t C1, C2; | 
|  |  | 
|  | C1 = demangleCharLiteral(MangledName); | 
|  | if (Error) | 
|  | goto WCharLiteralError; | 
|  | C2 = demangleCharLiteral(MangledName); | 
|  | if (Error) | 
|  | goto WCharLiteralError; | 
|  |  | 
|  | return ((wchar_t)C1 << 8) | (wchar_t)C2; | 
|  |  | 
|  | WCharLiteralError: | 
|  | Error = true; | 
|  | return L'\0'; | 
|  | } | 
|  |  | 
|  | static void writeHexDigit(char *Buffer, uint8_t Digit) { | 
|  | assert(Digit <= 15); | 
|  | *Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10); | 
|  | } | 
|  |  | 
|  | static void outputHex(OutputStream &OS, unsigned C) { | 
|  | if (C == 0) { | 
|  | OS << "\\x00"; | 
|  | return; | 
|  | } | 
|  | // It's easier to do the math if we can work from right to left, but we need | 
|  | // to print the numbers from left to right.  So render this into a temporary | 
|  | // buffer first, then output the temporary buffer.  Each byte is of the form | 
|  | // \xAB, which means that each byte needs 4 characters.  Since there are at | 
|  | // most 4 bytes, we need a 4*4+1 = 17 character temporary buffer. | 
|  | char TempBuffer[17]; | 
|  |  | 
|  | ::memset(TempBuffer, 0, sizeof(TempBuffer)); | 
|  | constexpr int MaxPos = 15; | 
|  |  | 
|  | int Pos = MaxPos - 1; | 
|  | while (C != 0) { | 
|  | for (int I = 0; I < 2; ++I) { | 
|  | writeHexDigit(&TempBuffer[Pos--], C % 16); | 
|  | C /= 16; | 
|  | } | 
|  | TempBuffer[Pos--] = 'x'; | 
|  | TempBuffer[Pos--] = '\\'; | 
|  | assert(Pos >= 0); | 
|  | } | 
|  | OS << StringView(&TempBuffer[Pos + 1]); | 
|  | } | 
|  |  | 
|  | static void outputEscapedChar(OutputStream &OS, unsigned C) { | 
|  | switch (C) { | 
|  | case '\'': // single quote | 
|  | OS << "\\\'"; | 
|  | return; | 
|  | case '\"': // double quote | 
|  | OS << "\\\""; | 
|  | return; | 
|  | case '\\': // backslash | 
|  | OS << "\\\\"; | 
|  | return; | 
|  | case '\a': // bell | 
|  | OS << "\\a"; | 
|  | return; | 
|  | case '\b': // backspace | 
|  | OS << "\\b"; | 
|  | return; | 
|  | case '\f': // form feed | 
|  | OS << "\\f"; | 
|  | return; | 
|  | case '\n': // new line | 
|  | OS << "\\n"; | 
|  | return; | 
|  | case '\r': // carriage return | 
|  | OS << "\\r"; | 
|  | return; | 
|  | case '\t': // tab | 
|  | OS << "\\t"; | 
|  | return; | 
|  | case '\v': // vertical tab | 
|  | OS << "\\v"; | 
|  | return; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (C > 0x1F && C < 0x7F) { | 
|  | // Standard ascii char. | 
|  | OS << (char)C; | 
|  | return; | 
|  | } | 
|  |  | 
|  | outputHex(OS, C); | 
|  | } | 
|  |  | 
|  | unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) { | 
|  | const uint8_t *End = StringBytes + Length - 1; | 
|  | unsigned Count = 0; | 
|  | while (Length > 0 && *End == 0) { | 
|  | --Length; | 
|  | --End; | 
|  | ++Count; | 
|  | } | 
|  | return Count; | 
|  | } | 
|  |  | 
|  | unsigned countEmbeddedNulls(const uint8_t *StringBytes, unsigned Length) { | 
|  | unsigned Result = 0; | 
|  | for (unsigned I = 0; I < Length; ++I) { | 
|  | if (*StringBytes++ == 0) | 
|  | ++Result; | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars, | 
|  | unsigned NumBytes) { | 
|  | assert(NumBytes > 0); | 
|  |  | 
|  | // If the number of bytes is odd, this is guaranteed to be a char string. | 
|  | if (NumBytes % 2 == 1) | 
|  | return 1; | 
|  |  | 
|  | // All strings can encode at most 32 bytes of data.  If it's less than that, | 
|  | // then we encoded the entire string.  In this case we check for a 1-byte, | 
|  | // 2-byte, or 4-byte null terminator. | 
|  | if (NumBytes < 32) { | 
|  | unsigned TrailingNulls = countTrailingNullBytes(StringBytes, NumChars); | 
|  | if (TrailingNulls >= 4) | 
|  | return 4; | 
|  | if (TrailingNulls >= 2) | 
|  | return 2; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | // The whole string was not able to be encoded.  Try to look at embedded null | 
|  | // terminators to guess.  The heuristic is that we count all embedded null | 
|  | // terminators.  If more than 2/3 are null, it's a char32.  If more than 1/3 | 
|  | // are null, it's a char16.  Otherwise it's a char8.  This obviously isn't | 
|  | // perfect and is biased towards languages that have ascii alphabets, but this | 
|  | // was always going to be best effort since the encoding is lossy. | 
|  | unsigned Nulls = countEmbeddedNulls(StringBytes, NumChars); | 
|  | if (Nulls >= 2 * NumChars / 3) | 
|  | return 4; | 
|  | if (Nulls >= NumChars / 3) | 
|  | return 2; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static unsigned decodeMultiByteChar(const uint8_t *StringBytes, | 
|  | unsigned CharIndex, unsigned CharBytes) { | 
|  | assert(CharBytes == 1 || CharBytes == 2 || CharBytes == 4); | 
|  | unsigned Offset = CharIndex * CharBytes; | 
|  | unsigned Result = 0; | 
|  | StringBytes = StringBytes + Offset; | 
|  | for (unsigned I = 0; I < CharBytes; ++I) { | 
|  | unsigned C = static_cast<unsigned>(StringBytes[I]); | 
|  | Result |= C << (8 * I); | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) { | 
|  | FunctionSymbolNode *FSN = Arena.alloc<FunctionSymbolNode>(); | 
|  | VcallThunkIdentifierNode *VTIN = Arena.alloc<VcallThunkIdentifierNode>(); | 
|  | FSN->Signature = Arena.alloc<ThunkSignatureNode>(); | 
|  | FSN->Signature->FunctionClass = FC_NoParameterList; | 
|  |  | 
|  | FSN->Name = demangleNameScopeChain(MangledName, VTIN); | 
|  | if (!Error) | 
|  | Error = !MangledName.consumeFront("$B"); | 
|  | if (!Error) | 
|  | VTIN->OffsetInVTable = demangleUnsigned(MangledName); | 
|  | if (!Error) | 
|  | Error = !MangledName.consumeFront('A'); | 
|  | if (!Error) | 
|  | FSN->Signature->CallConvention = demangleCallingConvention(MangledName); | 
|  | return (Error) ? nullptr : FSN; | 
|  | } | 
|  |  | 
|  | EncodedStringLiteralNode * | 
|  | Demangler::demangleStringLiteral(StringView &MangledName) { | 
|  | // This function uses goto, so declare all variables up front. | 
|  | OutputStream OS; | 
|  | StringView CRC; | 
|  | uint64_t StringByteSize; | 
|  | bool IsWcharT = false; | 
|  | bool IsNegative = false; | 
|  | size_t CrcEndPos = 0; | 
|  | char *ResultBuffer = nullptr; | 
|  |  | 
|  | EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>(); | 
|  |  | 
|  | // Prefix indicating the beginning of a string literal | 
|  | if (!MangledName.consumeFront("@_")) | 
|  | goto StringLiteralError; | 
|  | if (MangledName.empty()) | 
|  | goto StringLiteralError; | 
|  |  | 
|  | // Char Type (regular or wchar_t) | 
|  | switch (MangledName.popFront()) { | 
|  | case '1': | 
|  | IsWcharT = true; | 
|  | LLVM_FALLTHROUGH; | 
|  | case '0': | 
|  | break; | 
|  | default: | 
|  | goto StringLiteralError; | 
|  | } | 
|  |  | 
|  | // Encoded Length | 
|  | std::tie(StringByteSize, IsNegative) = demangleNumber(MangledName); | 
|  | if (Error || IsNegative) | 
|  | goto StringLiteralError; | 
|  |  | 
|  | // CRC 32 (always 8 characters plus a terminator) | 
|  | CrcEndPos = MangledName.find('@'); | 
|  | if (CrcEndPos == StringView::npos) | 
|  | goto StringLiteralError; | 
|  | CRC = MangledName.substr(0, CrcEndPos); | 
|  | MangledName = MangledName.dropFront(CrcEndPos + 1); | 
|  | if (MangledName.empty()) | 
|  | goto StringLiteralError; | 
|  |  | 
|  | if (initializeOutputStream(nullptr, nullptr, OS, 1024)) | 
|  | // FIXME: Propagate out-of-memory as an error? | 
|  | std::terminate(); | 
|  | if (IsWcharT) { | 
|  | Result->Char = CharKind::Wchar; | 
|  | if (StringByteSize > 64) | 
|  | Result->IsTruncated = true; | 
|  |  | 
|  | while (!MangledName.consumeFront('@')) { | 
|  | assert(StringByteSize >= 2); | 
|  | wchar_t W = demangleWcharLiteral(MangledName); | 
|  | if (StringByteSize != 2 || Result->IsTruncated) | 
|  | outputEscapedChar(OS, W); | 
|  | StringByteSize -= 2; | 
|  | if (Error) | 
|  | goto StringLiteralError; | 
|  | } | 
|  | } else { | 
|  | // The max byte length is actually 32, but some compilers mangled strings | 
|  | // incorrectly, so we have to assume it can go higher. | 
|  | constexpr unsigned MaxStringByteLength = 32 * 4; | 
|  | uint8_t StringBytes[MaxStringByteLength]; | 
|  |  | 
|  | unsigned BytesDecoded = 0; | 
|  | while (!MangledName.consumeFront('@')) { | 
|  | assert(StringByteSize >= 1); | 
|  | StringBytes[BytesDecoded++] = demangleCharLiteral(MangledName); | 
|  | } | 
|  |  | 
|  | if (StringByteSize > BytesDecoded) | 
|  | Result->IsTruncated = true; | 
|  |  | 
|  | unsigned CharBytes = | 
|  | guessCharByteSize(StringBytes, BytesDecoded, StringByteSize); | 
|  | assert(StringByteSize % CharBytes == 0); | 
|  | switch (CharBytes) { | 
|  | case 1: | 
|  | Result->Char = CharKind::Char; | 
|  | break; | 
|  | case 2: | 
|  | Result->Char = CharKind::Char16; | 
|  | break; | 
|  | case 4: | 
|  | Result->Char = CharKind::Char32; | 
|  | break; | 
|  | default: | 
|  | LLVM_BUILTIN_UNREACHABLE; | 
|  | } | 
|  | const unsigned NumChars = BytesDecoded / CharBytes; | 
|  | for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) { | 
|  | unsigned NextChar = | 
|  | decodeMultiByteChar(StringBytes, CharIndex, CharBytes); | 
|  | if (CharIndex + 1 < NumChars || Result->IsTruncated) | 
|  | outputEscapedChar(OS, NextChar); | 
|  | } | 
|  | } | 
|  |  | 
|  | OS << '\0'; | 
|  | ResultBuffer = OS.getBuffer(); | 
|  | Result->DecodedString = copyString(ResultBuffer); | 
|  | std::free(ResultBuffer); | 
|  | return Result; | 
|  |  | 
|  | StringLiteralError: | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | 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 {}; | 
|  | } | 
|  |  | 
|  | NamedIdentifierNode * | 
|  | Demangler::demangleAnonymousNamespaceName(StringView &MangledName) { | 
|  | assert(MangledName.startsWith("?A")); | 
|  | MangledName.consumeFront("?A"); | 
|  |  | 
|  | NamedIdentifierNode *Node = Arena.alloc<NamedIdentifierNode>(); | 
|  | Node->Name = "`anonymous namespace'"; | 
|  | size_t EndPos = MangledName.find('@'); | 
|  | if (EndPos == StringView::npos) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  | StringView NamespaceKey = MangledName.substr(0, EndPos); | 
|  | memorizeString(NamespaceKey); | 
|  | MangledName = MangledName.substr(EndPos + 1); | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | NamedIdentifierNode * | 
|  | Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) { | 
|  | assert(startsWithLocalScopePattern(MangledName)); | 
|  |  | 
|  | NamedIdentifierNode *Identifier = Arena.alloc<NamedIdentifierNode>(); | 
|  | MangledName.consumeFront('?'); | 
|  | auto Number = demangleNumber(MangledName); | 
|  | assert(!Number.second); | 
|  |  | 
|  | // One ? to terminate the number | 
|  | MangledName.consumeFront('?'); | 
|  |  | 
|  | assert(!Error); | 
|  | Node *Scope = parse(MangledName); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | // Render the parent symbol's name into a buffer. | 
|  | OutputStream OS; | 
|  | if (initializeOutputStream(nullptr, nullptr, OS, 1024)) | 
|  | // FIXME: Propagate out-of-memory as an error? | 
|  | std::terminate(); | 
|  | OS << '`'; | 
|  | Scope->output(OS, OF_Default); | 
|  | OS << '\''; | 
|  | OS << "::`" << Number.first << "'"; | 
|  | OS << '\0'; | 
|  | char *Result = OS.getBuffer(); | 
|  | Identifier->Name = copyString(Result); | 
|  | std::free(Result); | 
|  | return Identifier; | 
|  | } | 
|  |  | 
|  | // Parses a type name in the form of A@B@C@@ which represents C::B::A. | 
|  | QualifiedNameNode * | 
|  | Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) { | 
|  | IdentifierNode *Identifier = demangleUnqualifiedTypeName(MangledName, true); | 
|  | if (Error) | 
|  | return nullptr; | 
|  | assert(Identifier); | 
|  |  | 
|  | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier); | 
|  | if (Error) | 
|  | return nullptr; | 
|  | assert(QN); | 
|  | return QN; | 
|  | } | 
|  |  | 
|  | // 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. | 
|  | QualifiedNameNode * | 
|  | Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) { | 
|  | // This is the final component of a symbol name (i.e. the leftmost component | 
|  | // of a mangled name.  Since the only possible template instantiation that | 
|  | // can appear in this context is a function template, and since those are | 
|  | // not saved for the purposes of name backreferences, only backref simple | 
|  | // names. | 
|  | IdentifierNode *Identifier = | 
|  | demangleUnqualifiedSymbolName(MangledName, NBB_Simple); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | if (Identifier->kind() == NodeKind::StructorIdentifier) { | 
|  | StructorIdentifierNode *SIN = | 
|  | static_cast<StructorIdentifierNode *>(Identifier); | 
|  | assert(QN->Components->Count >= 2); | 
|  | Node *ClassNode = QN->Components->Nodes[QN->Components->Count - 2]; | 
|  | SIN->Class = static_cast<IdentifierNode *>(ClassNode); | 
|  | } | 
|  | assert(QN); | 
|  | return QN; | 
|  | } | 
|  |  | 
|  | IdentifierNode *Demangler::demangleUnqualifiedTypeName(StringView &MangledName, | 
|  | bool Memorize) { | 
|  | // 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 demangleTemplateInstantiationName(MangledName, NBB_Template); | 
|  |  | 
|  | return demangleSimpleName(MangledName, Memorize); | 
|  | } | 
|  |  | 
|  | IdentifierNode * | 
|  | Demangler::demangleUnqualifiedSymbolName(StringView &MangledName, | 
|  | NameBackrefBehavior NBB) { | 
|  | if (startsWithDigit(MangledName)) | 
|  | return demangleBackRefName(MangledName); | 
|  | if (MangledName.startsWith("?$")) | 
|  | return demangleTemplateInstantiationName(MangledName, NBB); | 
|  | if (MangledName.startsWith('?')) | 
|  | return demangleFunctionIdentifierCode(MangledName); | 
|  | return demangleSimpleName(MangledName, (NBB & NBB_Simple) != 0); | 
|  | } | 
|  |  | 
|  | IdentifierNode *Demangler::demangleNameScopePiece(StringView &MangledName) { | 
|  | if (startsWithDigit(MangledName)) | 
|  | return demangleBackRefName(MangledName); | 
|  |  | 
|  | if (MangledName.startsWith("?$")) | 
|  | return demangleTemplateInstantiationName(MangledName, NBB_Template); | 
|  |  | 
|  | if (MangledName.startsWith("?A")) | 
|  | return demangleAnonymousNamespaceName(MangledName); | 
|  |  | 
|  | if (startsWithLocalScopePattern(MangledName)) | 
|  | return demangleLocallyScopedNamePiece(MangledName); | 
|  |  | 
|  | return demangleSimpleName(MangledName, true); | 
|  | } | 
|  |  | 
|  | static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head, | 
|  | size_t Count) { | 
|  | NodeArrayNode *N = Arena.alloc<NodeArrayNode>(); | 
|  | N->Count = Count; | 
|  | N->Nodes = Arena.allocArray<Node *>(Count); | 
|  | for (size_t I = 0; I < Count; ++I) { | 
|  | N->Nodes[I] = Head->N; | 
|  | Head = Head->Next; | 
|  | } | 
|  | return N; | 
|  | } | 
|  |  | 
|  | QualifiedNameNode * | 
|  | Demangler::demangleNameScopeChain(StringView &MangledName, | 
|  | IdentifierNode *UnqualifiedName) { | 
|  | NodeList *Head = Arena.alloc<NodeList>(); | 
|  |  | 
|  | Head->N = UnqualifiedName; | 
|  |  | 
|  | size_t Count = 1; | 
|  | while (!MangledName.consumeFront("@")) { | 
|  | ++Count; | 
|  | NodeList *NewHead = Arena.alloc<NodeList>(); | 
|  | NewHead->Next = Head; | 
|  | Head = NewHead; | 
|  |  | 
|  | if (MangledName.empty()) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | assert(!Error); | 
|  | IdentifierNode *Elem = demangleNameScopePiece(MangledName); | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | Head->N = Elem; | 
|  | } | 
|  |  | 
|  | QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>(); | 
|  | QN->Components = nodeListToNodeArray(Arena, Head, Count); | 
|  | return QN; | 
|  | } | 
|  |  | 
|  | FuncClass Demangler::demangleFunctionClass(StringView &MangledName) { | 
|  | switch (MangledName.popFront()) { | 
|  | case '9': | 
|  | return FuncClass(FC_ExternC | FC_NoParameterList); | 
|  | case 'A': | 
|  | return FC_Private; | 
|  | case 'B': | 
|  | return FuncClass(FC_Private | FC_Far); | 
|  | case 'C': | 
|  | return FuncClass(FC_Private | FC_Static); | 
|  | case 'D': | 
|  | return FuncClass(FC_Private | FC_Static); | 
|  | case 'E': | 
|  | return FuncClass(FC_Private | FC_Virtual); | 
|  | case 'F': | 
|  | return FuncClass(FC_Private | FC_Virtual); | 
|  | case 'G': | 
|  | return FuncClass(FC_Private | FC_StaticThisAdjust); | 
|  | case 'H': | 
|  | return FuncClass(FC_Private | FC_StaticThisAdjust | FC_Far); | 
|  | case 'I': | 
|  | return FuncClass(FC_Protected); | 
|  | case 'J': | 
|  | return FuncClass(FC_Protected | FC_Far); | 
|  | case 'K': | 
|  | return FuncClass(FC_Protected | FC_Static); | 
|  | case 'L': | 
|  | return FuncClass(FC_Protected | FC_Static | FC_Far); | 
|  | case 'M': | 
|  | return FuncClass(FC_Protected | FC_Virtual); | 
|  | case 'N': | 
|  | return FuncClass(FC_Protected | FC_Virtual | FC_Far); | 
|  | case 'O': | 
|  | return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust); | 
|  | case 'P': | 
|  | return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust | FC_Far); | 
|  | case 'Q': | 
|  | return FuncClass(FC_Public); | 
|  | case 'R': | 
|  | return FuncClass(FC_Public | FC_Far); | 
|  | case 'S': | 
|  | return FuncClass(FC_Public | FC_Static); | 
|  | case 'T': | 
|  | return FuncClass(FC_Public | FC_Static | FC_Far); | 
|  | case 'U': | 
|  | return FuncClass(FC_Public | FC_Virtual); | 
|  | case 'V': | 
|  | return FuncClass(FC_Public | FC_Virtual | FC_Far); | 
|  | case 'W': | 
|  | return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust); | 
|  | case 'X': | 
|  | return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust | FC_Far); | 
|  | case 'Y': | 
|  | return FuncClass(FC_Global); | 
|  | case 'Z': | 
|  | return FuncClass(FC_Global | FC_Far); | 
|  | case '$': { | 
|  | FuncClass VFlag = FC_VirtualThisAdjust; | 
|  | if (MangledName.consumeFront('R')) | 
|  | VFlag = FuncClass(VFlag | FC_VirtualThisAdjustEx); | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | case '0': | 
|  | return FuncClass(FC_Private | FC_Virtual | VFlag); | 
|  | case '1': | 
|  | return FuncClass(FC_Private | FC_Virtual | VFlag | FC_Far); | 
|  | case '2': | 
|  | return FuncClass(FC_Protected | FC_Virtual | VFlag); | 
|  | case '3': | 
|  | return FuncClass(FC_Protected | FC_Virtual | VFlag | FC_Far); | 
|  | case '4': | 
|  | return FuncClass(FC_Public | FC_Virtual | VFlag); | 
|  | case '5': | 
|  | return FuncClass(FC_Public | FC_Virtual | VFlag | FC_Far); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Error = true; | 
|  | return FC_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); | 
|  | } | 
|  |  | 
|  | // <variable-type> ::= <type> <cvr-qualifiers> | 
|  | //                 ::= <type> <pointee-cvr-qualifiers> # pointers, references | 
|  | TypeNode *Demangler::demangleType(StringView &MangledName, | 
|  | QualifierMangleMode QMM) { | 
|  | Qualifiers Quals = Q_None; | 
|  | bool IsMember = false; | 
|  | if (QMM == QualifierMangleMode::Mangle) { | 
|  | std::tie(Quals, IsMember) = demangleQualifiers(MangledName); | 
|  | } else if (QMM == QualifierMangleMode::Result) { | 
|  | if (MangledName.consumeFront('?')) | 
|  | std::tie(Quals, IsMember) = demangleQualifiers(MangledName); | 
|  | } | 
|  |  | 
|  | TypeNode *Ty = nullptr; | 
|  | if (isTagType(MangledName)) | 
|  | Ty = demangleClassType(MangledName); | 
|  | else if (isPointerType(MangledName)) { | 
|  | if (isMemberPointer(MangledName)) | 
|  | 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); | 
|  | else { | 
|  | assert(MangledName.startsWith("$$A6")); | 
|  | MangledName.consumeFront("$$A6"); | 
|  | Ty = demangleFunctionType(MangledName, false); | 
|  | } | 
|  | } else if (isCustomType(MangledName)) { | 
|  | Ty = demangleCustomType(MangledName); | 
|  | } else { | 
|  | Ty = demanglePrimitiveType(MangledName); | 
|  | if (!Ty || Error) | 
|  | return Ty; | 
|  | } | 
|  |  | 
|  | Ty->Quals = Qualifiers(Ty->Quals | Quals); | 
|  | return Ty; | 
|  | } | 
|  |  | 
|  | void Demangler::demangleThrowSpecification(StringView &MangledName) { | 
|  | if (MangledName.consumeFront('Z')) | 
|  | return; | 
|  |  | 
|  | Error = true; | 
|  | } | 
|  |  | 
|  | FunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName, | 
|  | bool HasThisQuals) { | 
|  | FunctionSignatureNode *FTy = Arena.alloc<FunctionSignatureNode>(); | 
|  |  | 
|  | if (HasThisQuals) { | 
|  | FTy->Quals = demanglePointerExtQualifiers(MangledName); | 
|  | FTy->RefQualifier = demangleFunctionRefQualifier(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; | 
|  | } | 
|  |  | 
|  | FunctionSymbolNode * | 
|  | Demangler::demangleFunctionEncoding(StringView &MangledName) { | 
|  | FuncClass ExtraFlags = FC_None; | 
|  | if (MangledName.consumeFront("$$J0")) | 
|  | ExtraFlags = FC_ExternC; | 
|  |  | 
|  | FuncClass FC = demangleFunctionClass(MangledName); | 
|  | FC = FuncClass(ExtraFlags | FC); | 
|  |  | 
|  | FunctionSignatureNode *FSN = nullptr; | 
|  | ThunkSignatureNode *TTN = nullptr; | 
|  | if (FC & FC_StaticThisAdjust) { | 
|  | TTN = Arena.alloc<ThunkSignatureNode>(); | 
|  | TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName); | 
|  | } else if (FC & FC_VirtualThisAdjust) { | 
|  | TTN = Arena.alloc<ThunkSignatureNode>(); | 
|  | if (FC & FC_VirtualThisAdjustEx) { | 
|  | TTN->ThisAdjust.VBPtrOffset = demangleSigned(MangledName); | 
|  | TTN->ThisAdjust.VBOffsetOffset = demangleSigned(MangledName); | 
|  | } | 
|  | TTN->ThisAdjust.VtordispOffset = demangleSigned(MangledName); | 
|  | TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName); | 
|  | } | 
|  |  | 
|  | if (FC & FC_NoParameterList) { | 
|  | // This is an extern "C" function whose full signature hasn't been mangled. | 
|  | // This happens when we need to mangle a local symbol inside of an extern | 
|  | // "C" function. | 
|  | FSN = Arena.alloc<FunctionSignatureNode>(); | 
|  | } else { | 
|  | bool HasThisQuals = !(FC & (FC_Global | FC_Static)); | 
|  | FSN = demangleFunctionType(MangledName, HasThisQuals); | 
|  | } | 
|  | if (TTN) { | 
|  | *static_cast<FunctionSignatureNode *>(TTN) = *FSN; | 
|  | FSN = TTN; | 
|  | } | 
|  | FSN->FunctionClass = FC; | 
|  |  | 
|  | FunctionSymbolNode *Symbol = Arena.alloc<FunctionSymbolNode>(); | 
|  | Symbol->Signature = FSN; | 
|  | return Symbol; | 
|  | } | 
|  |  | 
|  | CustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) { | 
|  | assert(MangledName.startsWith('?')); | 
|  | MangledName.popFront(); | 
|  |  | 
|  | CustomTypeNode *CTN = Arena.alloc<CustomTypeNode>(); | 
|  | CTN->Identifier = demangleUnqualifiedTypeName(MangledName, true); | 
|  | if (!MangledName.consumeFront('@')) | 
|  | Error = true; | 
|  | if (Error) | 
|  | return nullptr; | 
|  | return CTN; | 
|  | } | 
|  |  | 
|  | // Reads a primitive type. | 
|  | PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) { | 
|  | if (MangledName.consumeFront("$$T")) | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Nullptr); | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | case 'X': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Void); | 
|  | case 'D': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char); | 
|  | case 'C': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Schar); | 
|  | case 'E': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uchar); | 
|  | case 'F': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Short); | 
|  | case 'G': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ushort); | 
|  | case 'H': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int); | 
|  | case 'I': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint); | 
|  | case 'J': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Long); | 
|  | case 'K': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ulong); | 
|  | case 'M': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Float); | 
|  | case 'N': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Double); | 
|  | case 'O': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ldouble); | 
|  | case '_': { | 
|  | if (MangledName.empty()) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  | switch (MangledName.popFront()) { | 
|  | case 'N': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Bool); | 
|  | case 'J': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int64); | 
|  | case 'K': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint64); | 
|  | case 'W': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Wchar); | 
|  | case 'S': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char16); | 
|  | case 'U': | 
|  | return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char32); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | TagTypeNode *Demangler::demangleClassType(StringView &MangledName) { | 
|  | TagTypeNode *TT = nullptr; | 
|  |  | 
|  | switch (MangledName.popFront()) { | 
|  | case 'T': | 
|  | TT = Arena.alloc<TagTypeNode>(TagKind::Union); | 
|  | break; | 
|  | case 'U': | 
|  | TT = Arena.alloc<TagTypeNode>(TagKind::Struct); | 
|  | break; | 
|  | case 'V': | 
|  | TT = Arena.alloc<TagTypeNode>(TagKind::Class); | 
|  | break; | 
|  | case 'W': | 
|  | if (MangledName.popFront() != '4') { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  | TT = Arena.alloc<TagTypeNode>(TagKind::Enum); | 
|  | break; | 
|  | default: | 
|  | assert(false); | 
|  | } | 
|  |  | 
|  | TT->QualifiedName = demangleFullyQualifiedTypeName(MangledName); | 
|  | return TT; | 
|  | } | 
|  |  | 
|  | // <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type> | 
|  | //                       # the E is required for 64-bit non-static pointers | 
|  | PointerTypeNode *Demangler::demanglePointerType(StringView &MangledName) { | 
|  | PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>(); | 
|  |  | 
|  | std::tie(Pointer->Quals, Pointer->Affinity) = | 
|  | demanglePointerCVQualifiers(MangledName); | 
|  |  | 
|  | if (MangledName.consumeFront("6")) { | 
|  | Pointer->Pointee = demangleFunctionType(MangledName, false); | 
|  | return Pointer; | 
|  | } | 
|  |  | 
|  | Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); | 
|  | Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); | 
|  |  | 
|  | Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle); | 
|  | return Pointer; | 
|  | } | 
|  |  | 
|  | PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) { | 
|  | PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>(); | 
|  |  | 
|  | std::tie(Pointer->Quals, Pointer->Affinity) = | 
|  | demanglePointerCVQualifiers(MangledName); | 
|  | assert(Pointer->Affinity == PointerAffinity::Pointer); | 
|  |  | 
|  | Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); | 
|  | Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); | 
|  |  | 
|  | if (MangledName.consumeFront("8")) { | 
|  | Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName); | 
|  | Pointer->Pointee = demangleFunctionType(MangledName, true); | 
|  | } else { | 
|  | Qualifiers PointeeQuals = Q_None; | 
|  | bool IsMember = false; | 
|  | std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName); | 
|  | assert(IsMember); | 
|  | Pointer->ClassParent = demangleFullyQualifiedTypeName(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; | 
|  | } | 
|  |  | 
|  | ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) { | 
|  | assert(MangledName.front() == 'Y'); | 
|  | MangledName.popFront(); | 
|  |  | 
|  | uint64_t Rank = 0; | 
|  | bool IsNegative = false; | 
|  | std::tie(Rank, IsNegative) = demangleNumber(MangledName); | 
|  | if (IsNegative || Rank == 0) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | ArrayTypeNode *ATy = Arena.alloc<ArrayTypeNode>(); | 
|  | NodeList *Head = Arena.alloc<NodeList>(); | 
|  | NodeList *Tail = Head; | 
|  |  | 
|  | for (uint64_t I = 0; I < Rank; ++I) { | 
|  | uint64_t D = 0; | 
|  | std::tie(D, IsNegative) = demangleNumber(MangledName); | 
|  | if (IsNegative) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  | Tail->N = Arena.alloc<IntegerLiteralNode>(D, IsNegative); | 
|  | if (I + 1 < Rank) { | 
|  | Tail->Next = Arena.alloc<NodeList>(); | 
|  | Tail = Tail->Next; | 
|  | } | 
|  | } | 
|  | ATy->Dimensions = nodeListToNodeArray(Arena, Head, Rank); | 
|  |  | 
|  | if (MangledName.consumeFront("$$C")) { | 
|  | bool IsMember = false; | 
|  | std::tie(ATy->Quals, IsMember) = demangleQualifiers(MangledName); | 
|  | if (IsMember) { | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop); | 
|  | return ATy; | 
|  | } | 
|  |  | 
|  | // Reads a function or a template parameters. | 
|  | NodeArrayNode * | 
|  | Demangler::demangleFunctionParameterList(StringView &MangledName) { | 
|  | // Empty parameter list. | 
|  | if (MangledName.consumeFront('X')) | 
|  | return {}; | 
|  |  | 
|  | NodeList *Head = Arena.alloc<NodeList>(); | 
|  | NodeList **Current = &Head; | 
|  | size_t Count = 0; | 
|  | while (!Error && !MangledName.startsWith('@') && | 
|  | !MangledName.startsWith('Z')) { | 
|  | ++Count; | 
|  |  | 
|  | if (startsWithDigit(MangledName)) { | 
|  | size_t N = MangledName[0] - '0'; | 
|  | if (N >= Backrefs.FunctionParamCount) { | 
|  | Error = true; | 
|  | return {}; | 
|  | } | 
|  | MangledName = MangledName.dropFront(); | 
|  |  | 
|  | *Current = Arena.alloc<NodeList>(); | 
|  | (*Current)->N = Backrefs.FunctionParams[N]; | 
|  | Current = &(*Current)->Next; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | size_t OldSize = MangledName.size(); | 
|  |  | 
|  | *Current = Arena.alloc<NodeList>(); | 
|  | TypeNode *TN = demangleType(MangledName, QualifierMangleMode::Drop); | 
|  |  | 
|  | (*Current)->N = TN; | 
|  |  | 
|  | size_t CharsConsumed = OldSize - MangledName.size(); | 
|  | assert(CharsConsumed != 0); | 
|  |  | 
|  | // Single-letter types are ignored for backreferences because memorizing | 
|  | // them doesn't save anything. | 
|  | if (Backrefs.FunctionParamCount <= 9 && CharsConsumed > 1) | 
|  | Backrefs.FunctionParams[Backrefs.FunctionParamCount++] = TN; | 
|  |  | 
|  | Current = &(*Current)->Next; | 
|  | } | 
|  |  | 
|  | if (Error) | 
|  | return {}; | 
|  |  | 
|  | NodeArrayNode *NA = nodeListToNodeArray(Arena, Head, Count); | 
|  | // 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 NA; | 
|  |  | 
|  | if (MangledName.consumeFront('Z')) { | 
|  | // This is a variadic parameter list.  We probably need a variadic node to | 
|  | // append to the end. | 
|  | return NA; | 
|  | } | 
|  |  | 
|  | Error = true; | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | NodeArrayNode * | 
|  | Demangler::demangleTemplateParameterList(StringView &MangledName) { | 
|  | NodeList *Head; | 
|  | NodeList **Current = &Head; | 
|  | size_t Count = 0; | 
|  |  | 
|  | while (!Error && !MangledName.startsWith('@')) { | 
|  | if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") || | 
|  | MangledName.consumeFront("$$$V") || MangledName.consumeFront("$$Z")) { | 
|  | // parameter pack separator | 
|  | continue; | 
|  | } | 
|  |  | 
|  | ++Count; | 
|  |  | 
|  | // Template parameter lists don't participate in back-referencing. | 
|  | *Current = Arena.alloc<NodeList>(); | 
|  |  | 
|  | NodeList &TP = **Current; | 
|  |  | 
|  | TemplateParameterReferenceNode *TPRN = nullptr; | 
|  | if (MangledName.consumeFront("$$Y")) { | 
|  | // Template alias | 
|  | TP.N = demangleFullyQualifiedTypeName(MangledName); | 
|  | } else if (MangledName.consumeFront("$$B")) { | 
|  | // Array | 
|  | TP.N = demangleType(MangledName, QualifierMangleMode::Drop); | 
|  | } else if (MangledName.consumeFront("$$C")) { | 
|  | // Type has qualifiers. | 
|  | TP.N = demangleType(MangledName, QualifierMangleMode::Mangle); | 
|  | } else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") || | 
|  | MangledName.startsWith("$I") || MangledName.startsWith("$J")) { | 
|  | // Pointer to member | 
|  | TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>(); | 
|  | TPRN->IsMemberPointer = true; | 
|  |  | 
|  | MangledName = MangledName.dropFront(); | 
|  | // 1 - single inheritance       <name> | 
|  | // H - multiple inheritance     <name> <number> | 
|  | // I - virtual inheritance      <name> <number> <number> <number> | 
|  | // J - unspecified inheritance  <name> <number> <number> <number> | 
|  | char InheritanceSpecifier = MangledName.popFront(); | 
|  | SymbolNode *S = nullptr; | 
|  | if (MangledName.startsWith('?')) { | 
|  | S = parse(MangledName); | 
|  | memorizeIdentifier(S->Name->getUnqualifiedIdentifier()); | 
|  | } | 
|  |  | 
|  | switch (InheritanceSpecifier) { | 
|  | case 'J': | 
|  | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = | 
|  | demangleSigned(MangledName); | 
|  | LLVM_FALLTHROUGH; | 
|  | case 'I': | 
|  | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = | 
|  | demangleSigned(MangledName); | 
|  | LLVM_FALLTHROUGH; | 
|  | case 'H': | 
|  | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = | 
|  | demangleSigned(MangledName); | 
|  | LLVM_FALLTHROUGH; | 
|  | case '1': | 
|  | break; | 
|  | default: | 
|  | Error = true; | 
|  | break; | 
|  | } | 
|  | TPRN->Affinity = PointerAffinity::Pointer; | 
|  | TPRN->Symbol = S; | 
|  | } else if (MangledName.startsWith("$E?")) { | 
|  | MangledName.consumeFront("$E"); | 
|  | // Reference to symbol | 
|  | TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>(); | 
|  | TPRN->Symbol = parse(MangledName); | 
|  | TPRN->Affinity = PointerAffinity::Reference; | 
|  | } else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) { | 
|  | TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>(); | 
|  |  | 
|  | // Data member pointer. | 
|  | MangledName = MangledName.dropFront(); | 
|  | char InheritanceSpecifier = MangledName.popFront(); | 
|  |  | 
|  | switch (InheritanceSpecifier) { | 
|  | case 'G': | 
|  | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = | 
|  | demangleSigned(MangledName); | 
|  | LLVM_FALLTHROUGH; | 
|  | case 'F': | 
|  | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = | 
|  | demangleSigned(MangledName); | 
|  | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = | 
|  | demangleSigned(MangledName); | 
|  | LLVM_FALLTHROUGH; | 
|  | case '0': | 
|  | break; | 
|  | default: | 
|  | Error = true; | 
|  | break; | 
|  | } | 
|  | TPRN->IsMemberPointer = true; | 
|  |  | 
|  | } else if (MangledName.consumeFront("$0")) { | 
|  | // Integral non-type template parameter | 
|  | bool IsNegative = false; | 
|  | uint64_t Value = 0; | 
|  | std::tie(Value, IsNegative) = demangleNumber(MangledName); | 
|  |  | 
|  | TP.N = Arena.alloc<IntegerLiteralNode>(Value, IsNegative); | 
|  | } else { | 
|  | TP.N = demangleType(MangledName, QualifierMangleMode::Drop); | 
|  | } | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | Current = &TP.Next; | 
|  | } | 
|  |  | 
|  | if (Error) | 
|  | return nullptr; | 
|  |  | 
|  | // Template parameter lists cannot be variadic, so it can only be terminated | 
|  | // by @. | 
|  | if (MangledName.consumeFront('@')) | 
|  | return nodeListToNodeArray(Arena, Head, Count); | 
|  | Error = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | void Demangler::dumpBackReferences() { | 
|  | std::printf("%d function parameter backreferences\n", | 
|  | (int)Backrefs.FunctionParamCount); | 
|  |  | 
|  | // Create an output stream so we can render each type. | 
|  | OutputStream OS; | 
|  | if (initializeOutputStream(nullptr, nullptr, OS, 1024)) | 
|  | std::terminate(); | 
|  | for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) { | 
|  | OS.setCurrentPosition(0); | 
|  |  | 
|  | TypeNode *T = Backrefs.FunctionParams[I]; | 
|  | T->output(OS, OF_Default); | 
|  |  | 
|  | std::printf("  [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(), | 
|  | OS.getBuffer()); | 
|  | } | 
|  | std::free(OS.getBuffer()); | 
|  |  | 
|  | if (Backrefs.FunctionParamCount > 0) | 
|  | std::printf("\n"); | 
|  | std::printf("%d name backreferences\n", (int)Backrefs.NamesCount); | 
|  | for (size_t I = 0; I < Backrefs.NamesCount; ++I) { | 
|  | std::printf("  [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(), | 
|  | Backrefs.Names[I]->Name.begin()); | 
|  | } | 
|  | if (Backrefs.NamesCount > 0) | 
|  | std::printf("\n"); | 
|  | } | 
|  |  | 
|  | char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N, | 
|  | int *Status, MSDemangleFlags Flags) { | 
|  | int InternalStatus = demangle_success; | 
|  | Demangler D; | 
|  | OutputStream S; | 
|  |  | 
|  | StringView Name{MangledName}; | 
|  | SymbolNode *AST = D.parse(Name); | 
|  |  | 
|  | if (Flags & MSDF_DumpBackrefs) | 
|  | D.dumpBackReferences(); | 
|  |  | 
|  | if (D.Error) | 
|  | InternalStatus = demangle_invalid_mangled_name; | 
|  | else if (initializeOutputStream(Buf, N, S, 1024)) | 
|  | InternalStatus = demangle_memory_alloc_failure; | 
|  | else { | 
|  | AST->output(S, OF_Default); | 
|  | S += '\0'; | 
|  | if (N != nullptr) | 
|  | *N = S.getCurrentPosition(); | 
|  | Buf = S.getBuffer(); | 
|  | } | 
|  |  | 
|  | if (Status) | 
|  | *Status = InternalStatus; | 
|  | return InternalStatus == demangle_success ? Buf : nullptr; | 
|  | } |