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