diff options
Diffstat (limited to 'lib/Demangle/MicrosoftDemangle.cpp')
-rw-r--r-- | lib/Demangle/MicrosoftDemangle.cpp | 1048 |
1 files changed, 700 insertions, 348 deletions
diff --git a/lib/Demangle/MicrosoftDemangle.cpp b/lib/Demangle/MicrosoftDemangle.cpp index 596359b7d990..3eac87d61011 100644 --- a/lib/Demangle/MicrosoftDemangle.cpp +++ b/lib/Demangle/MicrosoftDemangle.cpp @@ -29,15 +29,27 @@ // 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() : Head(new AllocatorNode) { Head->Buf = new uint8_t[Unit]; } + ArenaAllocator() { addNode(AllocUnit); } ~ArenaAllocator() { while (Head) { @@ -49,10 +61,25 @@ public: } } + 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(Size < Unit); assert(Head && Head->Buf); size_t P = (size_t)Head->Buf + Head->Used; @@ -62,20 +89,15 @@ public: size_t Adjustment = AlignedP - P; Head->Used += Size + Adjustment; - if (Head->Used < Unit) + if (Head->Used < Head->Capacity) return new (PP) T(std::forward<Args>(ConstructorArgs)...); - AllocatorNode *NewHead = new AllocatorNode; - NewHead->Buf = new uint8_t[ArenaAllocator::Unit]; - NewHead->Next = Head; - Head = NewHead; - NewHead->Used = Size; - return new (NewHead->Buf) T(std::forward<Args>(ConstructorArgs)...); + addNode(AllocUnit); + Head->Used = Size; + return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...); } private: - static constexpr size_t Unit = 4096; - AllocatorNode *Head = nullptr; }; } // namespace @@ -117,7 +139,7 @@ enum class StorageClass : uint8_t { enum class QualifierMangleMode { Drop, Mangle, Result }; -enum class PointerAffinity { Pointer, Reference }; +enum class PointerAffinity { Pointer, Reference, RValueReference }; // Calling conventions enum class CallingConv : uint8_t { @@ -141,7 +163,6 @@ enum class PrimTy : uint8_t { None, Function, Ptr, - Ref, MemberPtr, Array, @@ -155,6 +176,8 @@ enum class PrimTy : uint8_t { Char, Schar, Uchar, + Char16, + Char32, Short, Ushort, Int, @@ -167,6 +190,7 @@ enum class PrimTy : uint8_t { Float, Double, Ldouble, + Nullptr }; // Function classes @@ -183,15 +207,30 @@ enum FuncClass : uint8_t { namespace { struct Type; +struct Name; -// Represents a list of parameters (template params or function arguments. -// It's represented as a linked list. -struct ParamList { +struct FunctionParams { bool IsVariadic = false; Type *Current = nullptr; - ParamList *Next = 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 @@ -232,7 +271,7 @@ struct Name { StringView Operator; // Template parameters. Null if not a template. - ParamList TemplateParams; + TemplateParams *TParams = nullptr; // Nested BackReferences (e.g. "A::B::C") are represented as a linked list. Name *Next = nullptr; @@ -243,6 +282,8 @@ struct PointerType : public Type { 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; @@ -276,7 +317,7 @@ struct FunctionType : public Type { CallingConv CallConvention; FuncClass FunctionClass; - ParamList Params; + FunctionParams Params; }; struct UdtType : public Type { @@ -302,9 +343,13 @@ struct ArrayType : public Type { 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 variable. + // function or member. return false; case 'P': case 'Q': @@ -386,14 +431,58 @@ static void outputCallingConvention(OutputStream &OS, CallingConv CC) { } } +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 ParamList &Params) { +static void outputParameterList(OutputStream &OS, + const FunctionParams &Params) { if (!Params.Current) { OS << "void"; return; } - const ParamList *Head = &Params; + const FunctionParams *Head = &Params; while (Head) { Type::outputPre(OS, *Head->Current); Type::outputPost(OS, *Head->Current); @@ -405,12 +494,39 @@ static void outputParameterList(OutputStream &OS, const ParamList &Params) { } } -static void outputTemplateParams(OutputStream &OS, const Name &TheName) { - if (!TheName.TemplateParams.Current) +static void outputParameterList(OutputStream &OS, + const TemplateParams &Params) { + if (!Params.ParamType && !Params.ParamName) { + OS << "<>"; return; + } OS << "<"; - outputParameterList(OS, TheName.TemplateParams); + 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 << ">"; } @@ -420,29 +536,32 @@ static void outputName(OutputStream &OS, const Name *TheName) { outputSpaceIfNecessary(OS); + const Name *Previous = nullptr; // Print out namespaces or outer class BackReferences. for (; TheName->Next; TheName = TheName->Next) { + Previous = TheName; OS << TheName->Str; - outputTemplateParams(OS, *TheName); + if (TheName->TParams) + outputParameterList(OS, *TheName->TParams); OS << "::"; } // Print out a regular name. if (TheName->Operator.empty()) { OS << TheName->Str; - outputTemplateParams(OS, *TheName); + 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 << TheName->Str; - outputTemplateParams(OS, *TheName); - OS << "::"; - if (TheName->Operator == "dtor") - OS << "~"; - OS << TheName->Str; - outputTemplateParams(OS, *TheName); + OS << Previous->Str; + if (Previous->TParams) + outputParameterList(OS, *Previous->TParams); return; } @@ -514,6 +633,12 @@ void Type::outputPre(OutputStream &OS) { 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; @@ -550,6 +675,9 @@ void Type::outputPre(OutputStream &OS) { case PrimTy::Ldouble: OS << "long double"; break; + case PrimTy::Nullptr: + OS << "std::nullptr_t"; + break; default: assert(false && "Invalid primitive type!"); } @@ -584,8 +712,10 @@ static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity, if (Affinity == PointerAffinity::Pointer) OS << "*"; - else + else if (Affinity == PointerAffinity::Reference) OS << "&"; + else + OS << "&&"; } void PointerType::outputPre(OutputStream &OS) { @@ -596,9 +726,6 @@ void PointerType::outputPre(OutputStream &OS) { if (Quals & Q_Unaligned) OS << "__unaligned "; - PointerAffinity Affinity = (Prim == PrimTy::Ptr) ? PointerAffinity::Pointer - : PointerAffinity::Reference; - outputPointerIndicator(OS, Affinity, nullptr, Pointee); // FIXME: We should output this, but it requires updating lots of tests. @@ -668,6 +795,15 @@ void FunctionType::outputPost(OutputStream &OS) { 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); @@ -716,6 +852,11 @@ void ArrayType::outputPost(OutputStream &OS) { Type::outputPost(OS, *ElementType); } +struct Symbol { + Name *SymbolName = nullptr; + Type *SymbolType = nullptr; +}; + } // namespace namespace { @@ -725,63 +866,68 @@ namespace { // It also has a set of functions to cnovert Type instances to strings. class Demangler { public: - Demangler(OutputStream &OS, StringView s) : OS(OS), MangledName(s) {} + 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. - void parse(); - void output(); + Symbol *parse(StringView &MangledName); + void output(const Symbol *S, OutputStream &OS); // True if an error occurred. bool Error = false; private: - Type *demangleVariableEncoding(); - Type *demangleFunctionEncoding(); + Type *demangleVariableEncoding(StringView &MangledName); + Type *demangleFunctionEncoding(StringView &MangledName); - Qualifiers demanglePointerExtQualifiers(); + Qualifiers demanglePointerExtQualifiers(StringView &MangledName); // Parser functions. This is a recursive-descent parser. - Type *demangleType(QualifierMangleMode QMM); - Type *demangleBasicType(); - UdtType *demangleClassType(); - PointerType *demanglePointerType(); - MemberPointerType *demangleMemberPointerType(); - FunctionType *demangleFunctionType(bool HasThisQuals, bool IsFunctionPointer); + 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(); + ArrayType *demangleArrayType(StringView &MangledName); - ParamList demangleTemplateParameterList(); - ParamList demangleFunctionParameterList(); + TemplateParams *demangleTemplateParameterList(StringView &MangledName); + FunctionParams demangleFunctionParameterList(StringView &MangledName); - int demangleNumber(); - void demangleNamePiece(Name &Node, bool IsHead); + int demangleNumber(StringView &MangledName); - StringView demangleString(bool memorize); void memorizeString(StringView s); - Name *demangleName(); - void demangleOperator(Name *); - StringView demangleOperatorName(); - FuncClass demangleFunctionClass(); - CallingConv demangleCallingConvention(); - StorageClass demangleVariableStorageClass(); - ReferenceKind demangleReferenceKind(); - void demangleThrowSpecification(); - std::pair<Qualifiers, bool> demangleQualifiers(); + /// Allocate a copy of \p Borrowed into memory that we own. + StringView copyString(StringView Borrowed); - // The result is written to this stream. - OutputStream OS; + Name *demangleFullyQualifiedTypeName(StringView &MangledName); + Name *demangleFullyQualifiedSymbolName(StringView &MangledName); - // Mangled symbol. demangle* functions shorten this string - // as they parse it. - StringView MangledName; + Name *demangleUnqualifiedTypeName(StringView &MangledName); + Name *demangleUnqualifiedSymbolName(StringView &MangledName); - // A parsed mangled symbol. - Type *SymbolType = nullptr; + Name *demangleNameScopeChain(StringView &MangledName, Name *UnqualifiedName); + Name *demangleNameScopePiece(StringView &MangledName); - // The main symbol name. (e.g. "ns::foo" in "int ns::foo()".) - Name *SymbolName = nullptr; + 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; @@ -809,28 +955,36 @@ private: }; } // 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. -void Demangler::parse() { +Symbol *Demangler::parse(StringView &MangledName) { + Symbol *S = Arena.alloc<Symbol>(); + // MSVC-style mangled symbols must start with '?'. if (!MangledName.consumeFront("?")) { - SymbolName = Arena.alloc<Name>(); - SymbolName->Str = MangledName; - SymbolType = Arena.alloc<Type>(); - SymbolType->Prim = PrimTy::Unknown; + 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. - SymbolName = demangleName(); + S->SymbolName = demangleFullyQualifiedSymbolName(MangledName); // Read a variable. - if (startsWithDigit(MangledName)) { - SymbolType = demangleVariableEncoding(); - return; - } + S->SymbolType = startsWithDigit(MangledName) + ? demangleVariableEncoding(MangledName) + : demangleFunctionEncoding(MangledName); - // Read a function. - SymbolType = demangleFunctionEncoding(); + return S; } // <type-encoding> ::= <storage-class> <variable-type> @@ -840,10 +994,10 @@ void Demangler::parse() { // ::= 3 # global // ::= 4 # static local -Type *Demangler::demangleVariableEncoding() { - StorageClass SC = demangleVariableStorageClass(); +Type *Demangler::demangleVariableEncoding(StringView &MangledName) { + StorageClass SC = demangleVariableStorageClass(MangledName); - Type *Ty = demangleType(QualifierMangleMode::Drop); + Type *Ty = demangleType(MangledName, QualifierMangleMode::Drop); Ty->Storage = SC; @@ -851,17 +1005,17 @@ Type *Demangler::demangleVariableEncoding() { // ::= <type> <pointee-cvr-qualifiers> # pointers, references switch (Ty->Prim) { case PrimTy::Ptr: - case PrimTy::Ref: case PrimTy::MemberPtr: { Qualifiers ExtraChildQuals = Q_None; - Ty->Quals = Qualifiers(Ty->Quals | demanglePointerExtQualifiers()); + Ty->Quals = + Qualifiers(Ty->Quals | demanglePointerExtQualifiers(MangledName)); bool IsMember = false; - std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(); + std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName); if (Ty->Prim == PrimTy::MemberPtr) { assert(IsMember); - Name *BackRefName = demangleName(); + Name *BackRefName = demangleFullyQualifiedTypeName(MangledName); (void)BackRefName; MemberPointerType *MPTy = static_cast<MemberPointerType *>(Ty); MPTy->Pointee->Quals = Qualifiers(MPTy->Pointee->Quals | ExtraChildQuals); @@ -873,7 +1027,7 @@ Type *Demangler::demangleVariableEncoding() { break; } default: - Ty->Quals = demangleQualifiers().first; + Ty->Quals = demangleQualifiers(MangledName).first; break; } @@ -891,7 +1045,7 @@ Type *Demangler::demangleVariableEncoding() { // ::= <hex digit>+ @ # when Numbrer == 0 or >= 10 // // <hex-digit> ::= [A-P] # A = 0, B = 1, ... -int Demangler::demangleNumber() { +int Demangler::demangleNumber(StringView &MangledName) { bool neg = MangledName.consumeFront("?"); if (startsWithDigit(MangledName)) { @@ -918,23 +1072,6 @@ int Demangler::demangleNumber() { return 0; } -// Read until the next '@'. -StringView Demangler::demangleString(bool Memorize) { - for (size_t i = 0; i < MangledName.size(); ++i) { - if (MangledName[i] != '@') - continue; - StringView ret = MangledName.substr(0, i); - MangledName = MangledName.dropFront(i + 1); - - if (Memorize) - memorizeString(ret); - return ret; - } - - Error = true; - return ""; -} - // First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9. // Memorize it. void Demangler::memorizeString(StringView S) { @@ -946,179 +1083,322 @@ void Demangler::memorizeString(StringView S) { BackReferences[BackRefCount++] = S; } -void Demangler::demangleNamePiece(Name &Node, bool IsHead) { - if (startsWithDigit(MangledName)) { - size_t I = MangledName[0] - '0'; - if (I >= BackRefCount) { - Error = true; - return; - } - MangledName = MangledName.dropFront(); - Node.Str = BackReferences[I]; - } else if (MangledName.consumeFront("?$")) { - // Class template. - Node.Str = demangleString(false); - Node.TemplateParams = demangleTemplateParameterList(); - } else if (!IsHead && MangledName.consumeFront("?A")) { - // Anonymous namespace starts with ?A. So does overloaded operator[], - // but the distinguishing factor is that namespace themselves are not - // mangled, only the variables and functions inside of them are. So - // an anonymous namespace will never occur as the first item in the - // name. - Node.Str = "`anonymous namespace'"; - if (!MangledName.consumeFront('@')) { - Error = true; - return; - } - } else if (MangledName.consumeFront("?")) { - // Overloaded operator. - demangleOperator(&Node); - } else { - // Non-template functions or classes. - Node.Str = demangleString(true); +Name *Demangler::demangleBackRefName(StringView &MangledName) { + assert(startsWithDigit(MangledName)); + + size_t I = MangledName[0] - '0'; + if (I >= BackRefCount) { + Error = true; + return nullptr; } -} -// Parses a name in the form of A@B@C@@ which represents C::B::A. -Name *Demangler::demangleName() { - Name *Head = nullptr; + MangledName = MangledName.dropFront(); + Name *Node = Arena.alloc<Name>(); + Node->Str = BackReferences[I]; + return Node; +} - while (!MangledName.consumeFront("@")) { - Name *Elem = Arena.alloc<Name>(); +Name *Demangler::demangleClassTemplateName(StringView &MangledName) { + assert(MangledName.startsWith("?$")); + MangledName.consumeFront("?$"); - assert(!Error); - demangleNamePiece(*Elem, Head == nullptr); - if (Error) - return nullptr; + Name *Node = demangleSimpleName(MangledName, false); + Node->TParams = demangleTemplateParameterList(MangledName); - Elem->Next = Head; - Head = Elem; - if (MangledName.empty()) { - Error = true; - return nullptr; - } - } + // 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(); - return Head; -} + StringView Owned = copyString(Name); + memorizeString(Owned); + std::free(Name); -void Demangler::demangleOperator(Name *OpName) { - OpName->Operator = demangleOperatorName(); - if (!Error && !MangledName.empty() && MangledName.front() != '@') - demangleNamePiece(*OpName, false); + return Node; } -StringView Demangler::demangleOperatorName() { - SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName); - RestoreOnError.shouldRestore(false); - - 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; +Name *Demangler::demangleOperatorName(StringView &MangledName) { + assert(MangledName.startsWith('?')); + MangledName.consumeFront('?'); + auto NameString = [this, &MangledName]() -> StringView { switch (MangledName.popFront()) { case '0': - return "/="; + return "ctor"; case '1': - return "%="; + return "dtor"; case '2': - return ">>="; + return " new"; case '3': - return "<<="; + return " delete"; case '4': - return "&="; + return "="; case '5': - return "|="; + return ">>"; case '6': - return "^="; + 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 " new[]"; + return "|"; case 'V': - return " delete[]"; - case '_': - if (MangledName.consumeFront("L")) - return " co_await"; + 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; - RestoreOnError.shouldRestore(true); - return ""; + 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() { +FuncClass Demangler::demangleFunctionClass(StringView &MangledName) { SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName); RestoreOnError.shouldRestore(false); @@ -1170,7 +1450,7 @@ FuncClass Demangler::demangleFunctionClass() { return Public; } -CallingConv Demangler::demangleCallingConvention() { +CallingConv Demangler::demangleCallingConvention(StringView &MangledName) { switch (MangledName.popFront()) { case 'A': case 'B': @@ -1200,7 +1480,7 @@ CallingConv Demangler::demangleCallingConvention() { return CallingConv::None; } -StorageClass Demangler::demangleVariableStorageClass() { +StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) { assert(std::isdigit(MangledName.front())); switch (MangledName.popFront()) { @@ -1219,7 +1499,8 @@ StorageClass Demangler::demangleVariableStorageClass() { return StorageClass::None; } -std::pair<Qualifiers, bool> Demangler::demangleQualifiers() { +std::pair<Qualifiers, bool> +Demangler::demangleQualifiers(StringView &MangledName) { switch (MangledName.popFront()) { // Member qualifiers @@ -1245,54 +1526,88 @@ std::pair<Qualifiers, bool> Demangler::demangleQualifiers() { 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(QualifierMangleMode QMM) { +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(); + std::tie(Quals, IsMember) = demangleQualifiers(MangledName); IsMemberKnown = true; } else if (QMM == QualifierMangleMode::Result) { if (MangledName.consumeFront('?')) { - std::tie(Quals, IsMember) = demangleQualifiers(); + std::tie(Quals, IsMember) = demangleQualifiers(MangledName); IsMemberKnown = true; } } Type *Ty = nullptr; - switch (MangledName.front()) { - case 'T': // union - case 'U': // struct - case 'V': // class - case 'W': // enum - Ty = demangleClassType(); - break; - case 'A': // foo & - case 'P': // foo * - case 'Q': // foo *const - case 'R': // foo *volatile - case 'S': // foo *const volatile + if (isTagType(MangledName)) + Ty = demangleClassType(MangledName); + else if (isPointerType(MangledName)) { if (!IsMemberKnown) IsMember = isMemberPointer(MangledName); + if (IsMember) - Ty = demangleMemberPointerType(); + Ty = demangleMemberPointerType(MangledName); else - Ty = demanglePointerType(); - break; - case 'Y': - Ty = demangleArrayType(); - break; - default: - Ty = demangleBasicType(); - break; + 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() { +ReferenceKind Demangler::demangleReferenceKind(StringView &MangledName) { if (MangledName.consumeFront('G')) return ReferenceKind::LValueRef; else if (MangledName.consumeFront('H')) @@ -1300,55 +1615,61 @@ ReferenceKind Demangler::demangleReferenceKind() { return ReferenceKind::None; } -void Demangler::demangleThrowSpecification() { +void Demangler::demangleThrowSpecification(StringView &MangledName) { if (MangledName.consumeFront('Z')) return; Error = true; } -FunctionType *Demangler::demangleFunctionType(bool HasThisQuals, +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(); - FTy->RefKind = demangleReferenceKind(); - FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers().first); + 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(); + FTy->CallConvention = demangleCallingConvention(MangledName); // <return-type> ::= <type> // ::= @ # structors (they have no declared return type) bool IsStructor = MangledName.consumeFront('@'); if (!IsStructor) - FTy->ReturnType = demangleType(QualifierMangleMode::Result); + FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result); - FTy->Params = demangleFunctionParameterList(); + FTy->Params = demangleFunctionParameterList(MangledName); - demangleThrowSpecification(); + demangleThrowSpecification(MangledName); return FTy; } -Type *Demangler::demangleFunctionEncoding() { - FuncClass FC = demangleFunctionClass(); +Type *Demangler::demangleFunctionEncoding(StringView &MangledName) { + FuncClass FC = demangleFunctionClass(MangledName); bool HasThisQuals = !(FC & (Global | Static)); - FunctionType *FTy = demangleFunctionType(HasThisQuals, false); + FunctionType *FTy = demangleFunctionType(MangledName, HasThisQuals, false); FTy->FunctionClass = FC; return FTy; } // Reads a primitive type. -Type *Demangler::demangleBasicType() { +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; @@ -1407,16 +1728,26 @@ Type *Demangler::demangleBasicType() { case 'W': Ty->Prim = PrimTy::Wchar; break; + case 'S': + Ty->Prim = PrimTy::Char16; + break; + case 'U': + Ty->Prim = PrimTy::Char32; + break; default: - assert(false); + Error = true; + return nullptr; } break; } + default: + Error = true; + return nullptr; } return Ty; } -UdtType *Demangler::demangleClassType() { +UdtType *Demangler::demangleClassType(StringView &MangledName) { UdtType *UTy = Arena.alloc<UdtType>(); switch (MangledName.popFront()) { @@ -1440,12 +1771,15 @@ UdtType *Demangler::demangleClassType() { assert(false); } - UTy->UdtName = demangleName(); + 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); @@ -1466,27 +1800,27 @@ demanglePointerCVQualifiers(StringView &MangledName) { // <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type> // # the E is required for 64-bit non-static pointers -PointerType *Demangler::demanglePointerType() { +PointerType *Demangler::demanglePointerType(StringView &MangledName) { PointerType *Pointer = Arena.alloc<PointerType>(); - PointerAffinity Affinity; - std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName); + std::tie(Pointer->Quals, Pointer->Affinity) = + demanglePointerCVQualifiers(MangledName); - Pointer->Prim = - (Affinity == PointerAffinity::Pointer) ? PrimTy::Ptr : PrimTy::Ref; + Pointer->Prim = PrimTy::Ptr; if (MangledName.consumeFront("6")) { - Pointer->Pointee = demangleFunctionType(false, true); + Pointer->Pointee = demangleFunctionType(MangledName, false, true); return Pointer; } - Qualifiers ExtQuals = demanglePointerExtQualifiers(); + Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); - Pointer->Pointee = demangleType(QualifierMangleMode::Mangle); + Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle); return Pointer; } -MemberPointerType *Demangler::demangleMemberPointerType() { +MemberPointerType * +Demangler::demangleMemberPointerType(StringView &MangledName) { MemberPointerType *Pointer = Arena.alloc<MemberPointerType>(); Pointer->Prim = PrimTy::MemberPtr; @@ -1494,27 +1828,27 @@ MemberPointerType *Demangler::demangleMemberPointerType() { std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName); assert(Affinity == PointerAffinity::Pointer); - Qualifiers ExtQuals = demanglePointerExtQualifiers(); + Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); if (MangledName.consumeFront("8")) { - Pointer->MemberName = demangleName(); - Pointer->Pointee = demangleFunctionType(true, true); + Pointer->MemberName = demangleFullyQualifiedSymbolName(MangledName); + Pointer->Pointee = demangleFunctionType(MangledName, true, true); } else { Qualifiers PointeeQuals = Q_None; bool IsMember = false; - std::tie(PointeeQuals, IsMember) = demangleQualifiers(); + std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName); assert(IsMember); - Pointer->MemberName = demangleName(); + Pointer->MemberName = demangleFullyQualifiedSymbolName(MangledName); - Pointer->Pointee = demangleType(QualifierMangleMode::Drop); + Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop); Pointer->Pointee->Quals = PointeeQuals; } return Pointer; } -Qualifiers Demangler::demanglePointerExtQualifiers() { +Qualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) { Qualifiers Quals = Q_None; if (MangledName.consumeFront('E')) Quals = Qualifiers(Quals | Q_Pointer64); @@ -1526,11 +1860,11 @@ Qualifiers Demangler::demanglePointerExtQualifiers() { return Quals; } -ArrayType *Demangler::demangleArrayType() { +ArrayType *Demangler::demangleArrayType(StringView &MangledName) { assert(MangledName.front() == 'Y'); MangledName.popFront(); - int Dimension = demangleNumber(); + int Dimension = demangleNumber(MangledName); if (Dimension <= 0) { Error = true; return nullptr; @@ -1540,7 +1874,7 @@ ArrayType *Demangler::demangleArrayType() { ArrayType *Dim = ATy; for (int I = 0; I < Dimension; ++I) { Dim->Prim = PrimTy::Array; - Dim->ArrayDimension = demangleNumber(); + Dim->ArrayDimension = demangleNumber(MangledName); Dim->NextDimension = Arena.alloc<ArrayType>(); Dim = Dim->NextDimension; } @@ -1554,19 +1888,20 @@ ArrayType *Demangler::demangleArrayType() { Error = true; } - ATy->ElementType = demangleType(QualifierMangleMode::Drop); + ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop); Dim->ElementType = ATy->ElementType; return ATy; } // Reads a function or a template parameters. -ParamList Demangler::demangleFunctionParameterList() { +FunctionParams +Demangler::demangleFunctionParameterList(StringView &MangledName) { // Empty parameter list. if (MangledName.consumeFront('X')) return {}; - ParamList *Head; - ParamList **Current = &Head; + FunctionParams *Head; + FunctionParams **Current = &Head; while (!Error && !MangledName.startsWith('@') && !MangledName.startsWith('Z')) { @@ -1578,7 +1913,7 @@ ParamList Demangler::demangleFunctionParameterList() { } MangledName = MangledName.dropFront(); - *Current = Arena.alloc<ParamList>(); + *Current = Arena.alloc<FunctionParams>(); (*Current)->Current = FunctionParamBackRefs[N]->clone(Arena); Current = &(*Current)->Next; continue; @@ -1586,8 +1921,8 @@ ParamList Demangler::demangleFunctionParameterList() { size_t OldSize = MangledName.size(); - *Current = Arena.alloc<ParamList>(); - (*Current)->Current = demangleType(QualifierMangleMode::Drop); + *Current = Arena.alloc<FunctionParams>(); + (*Current)->Current = demangleType(MangledName, QualifierMangleMode::Drop); size_t CharsConsumed = OldSize - MangledName.size(); assert(CharsConsumed != 0); @@ -1618,14 +1953,33 @@ ParamList Demangler::demangleFunctionParameterList() { return {}; } -ParamList Demangler::demangleTemplateParameterList() { - ParamList *Head; - ParamList **Current = &Head; +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<ParamList>(); - (*Current)->Current = demangleType(QualifierMangleMode::Drop); + *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; } @@ -1636,12 +1990,12 @@ ParamList Demangler::demangleTemplateParameterList() { // Template parameter lists cannot be variadic, so it can only be terminated // by @. if (MangledName.consumeFront('@')) - return *Head; + return Head; Error = true; return {}; } -void Demangler::output() { +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 @@ -1659,26 +2013,24 @@ void Demangler::output() { // 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, *SymbolType); - outputName(OS, SymbolName); - Type::outputPost(OS, *SymbolType); - - // Null terminate the buffer. - OS << '\0'; + 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) { - OutputStream OS = OutputStream::create(Buf, N, 1024); - - Demangler D(OS, StringView(MangledName)); - D.parse(); + Demangler D; + StringView Name{MangledName}; + Symbol *S = D.parse(Name); if (D.Error) *Status = llvm::demangle_invalid_mangled_name; else *Status = llvm::demangle_success; - D.output(); + OutputStream OS = OutputStream::create(Buf, N, 1024); + D.output(S, OS); + OS << '\0'; return OS.getBuffer(); } |