[llvm] r337584 - Add a Microsoft Demangler.
Zachary Turner via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 20 10:27:48 PDT 2018
Author: zturner
Date: Fri Jul 20 10:27:48 2018
New Revision: 337584
URL: http://llvm.org/viewvc/llvm-project?rev=337584&view=rev
Log:
Add a Microsoft Demangler.
This adds initial support for a demangling library (LLVMDemangle)
and tool (llvm-undname) for demangling Microsoft names. This
doesn't cover 100% of cases and there are some known limitations
which I intend to address in followup patches, at least until such
time that we have (near) 100% test coverage matching up with all
of the test cases in clang/test/CodeGenCXX/mangle-ms-*.
Differential Revision: https://reviews.llvm.org/D49552
Added:
llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
llvm/trunk/test/Demangle/ms-basic.test
llvm/trunk/test/Demangle/ms-mangle.test
llvm/trunk/test/Demangle/ms-windows.test
llvm/trunk/tools/llvm-undname/
llvm/trunk/tools/llvm-undname/CMakeLists.txt
llvm/trunk/tools/llvm-undname/LLVMBuild.txt
llvm/trunk/tools/llvm-undname/llvm-undname.cpp
Modified:
llvm/trunk/include/llvm/Demangle/Demangle.h
llvm/trunk/lib/Demangle/CMakeLists.txt
llvm/trunk/tools/LLVMBuild.txt
Modified: llvm/trunk/include/llvm/Demangle/Demangle.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Demangle/Demangle.h?rev=337584&r1=337583&r2=337584&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Demangle/Demangle.h (original)
+++ llvm/trunk/include/llvm/Demangle/Demangle.h Fri Jul 20 10:27:48 2018
@@ -16,7 +16,7 @@ namespace llvm {
/// The mangled_name is demangled into buf and returned. If the buffer is not
/// large enough, realloc is used to expand it.
///
-/// The *status will be set to a value from the enumeration
+/// The *status will be set to a value from the following enumeration
enum : int {
demangle_unknown_error = -4,
demangle_invalid_args = -3,
@@ -27,6 +27,8 @@ enum : int {
char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
int *status);
+char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,
+ int *status);
/// "Partial" demangler. This supports demangling a string into an AST
/// (typically an intermediate stage in itaniumDemangle) and querying certain
Modified: llvm/trunk/lib/Demangle/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/CMakeLists.txt?rev=337584&r1=337583&r2=337584&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/CMakeLists.txt (original)
+++ llvm/trunk/lib/Demangle/CMakeLists.txt Fri Jul 20 10:27:48 2018
@@ -1,6 +1,7 @@
add_llvm_library(LLVMDemangle
ItaniumDemangle.cpp
-
+ MicrosoftDemangle.cpp
+
ADDITIONAL_HEADER_DIRS
"${LLVM_MAIN_INCLUDE_DIR}/llvm/Demangle"
)
Added: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=337584&view=auto
==============================================================================
--- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (added)
+++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Fri Jul 20 10:27:48 2018
@@ -0,0 +1,1533 @@
+//===- 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>
+
+// 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 {
+class ArenaAllocator {
+ struct AllocatorNode {
+ uint8_t *Buf = nullptr;
+ size_t Used = 0;
+ AllocatorNode *Next = nullptr;
+ };
+
+public:
+ ArenaAllocator() : Head(new AllocatorNode) { Head->Buf = new uint8_t[Unit]; }
+
+ ~ArenaAllocator() {
+ while (Head) {
+ assert(Head->Buf);
+ delete[] Head->Buf;
+ Head = Head->Next;
+ }
+ }
+
+ void *alloc(size_t Size) {
+ assert(Size < Unit);
+ assert(Head && Head->Buf);
+
+ uint8_t *P = Head->Buf + Head->Used;
+ Head->Used += Size;
+ if (Head->Used < Unit)
+ return P;
+
+ AllocatorNode *NewHead = new AllocatorNode;
+ NewHead->Buf = new uint8_t[ArenaAllocator::Unit];
+ NewHead->Next = Head;
+ Head = NewHead;
+ NewHead->Used = Size;
+ return NewHead->Buf;
+ }
+
+private:
+ static constexpr size_t Unit = 4096;
+
+ 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 << " ";
+}
+
+void *operator new(size_t Size, ArenaAllocator &A) { return A.alloc(Size); }
+
+// 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 QualifierMangleLocation { Member, NonMember, Detect };
+
+// 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,
+ Ref,
+ Array,
+
+ Struct,
+ Union,
+ Class,
+ Enum,
+
+ Void,
+ Bool,
+ Char,
+ Schar,
+ Uchar,
+ Short,
+ Ushort,
+ Int,
+ Uint,
+ Long,
+ Ulong,
+ Int64,
+ Uint64,
+ Wchar,
+ Float,
+ Double,
+ Ldouble,
+};
+
+// Function classes
+enum FuncClass : uint8_t {
+ Public = 1 << 0,
+ Protected = 1 << 1,
+ Private = 1 << 2,
+ Global = 1 << 3,
+ Static = 1 << 4,
+ Virtual = 1 << 5,
+ FFar = 1 << 6,
+};
+
+namespace {
+
+struct Type;
+
+// Represents a list of parameters (template params or function arguments.
+// It's represented as a linked list.
+struct ParamList {
+ Type *Current = nullptr;
+
+ ParamList *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.
+ ParamList TemplateParams;
+
+ // 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);
+ void outputPost(OutputStream &OS) override;
+
+ bool isMemberPointer() const { return false; }
+
+ // 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);
+ void outputPost(OutputStream &OS);
+
+ Type *ReturnType = nullptr;
+ // If this is a reference, the type of reference.
+ ReferenceKind RefKind;
+
+ CallingConv CallConvention;
+ FuncClass FunctionClass;
+
+ ParamList 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 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;
+ }
+}
+
+// Write a function or template parameter list.
+static void outputParameterList(OutputStream &OS, const ParamList &Params) {
+ const ParamList *Head = &Params;
+ while (Head) {
+ Type::outputPre(OS, *Head->Current);
+ Type::outputPost(OS, *Head->Current);
+
+ Head = Head->Next;
+
+ if (Head)
+ OS << ", ";
+ }
+}
+
+static void outputTemplateParams(OutputStream &OS, const Name &TheName) {
+ if (!TheName.TemplateParams.Current)
+ return;
+
+ OS << "<";
+ outputParameterList(OS, TheName.TemplateParams);
+ OS << ">";
+}
+
+static void outputName(OutputStream &OS, const Name *TheName) {
+ if (!TheName)
+ return;
+
+ outputSpaceIfNecessary(OS);
+
+ // Print out namespaces or outer class BackReferences.
+ for (; TheName->Next; TheName = TheName->Next) {
+ OS << TheName->Str;
+ outputTemplateParams(OS, *TheName);
+ OS << "::";
+ }
+
+ // Print out a regular name.
+ if (TheName->Operator.empty()) {
+ OS << TheName->Str;
+ outputTemplateParams(OS, *TheName);
+ return;
+ }
+
+ // Print out ctor or dtor.
+ 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);
+ 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 new (Arena) 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";
+ }
+}
+
+// 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::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;
+ default:
+ assert(false && "Invalid primitive type!");
+ }
+}
+void Type::outputPost(OutputStream &OS) {}
+
+Type *PointerType::clone(ArenaAllocator &Arena) const {
+ return new (Arena) PointerType(*this);
+}
+
+void PointerType::outputPre(OutputStream &OS) {
+ Type::outputPre(OS, *Pointee);
+
+ outputSpaceIfNecessary(OS);
+
+ if (Quals & Q_Unaligned)
+ OS << "__unaligned ";
+
+ // "[]" 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 (Prim == PrimTy::Ptr)
+ OS << "*";
+ else
+ OS << "&";
+
+ // if (Ty.Quals & Q_Pointer64)
+ // OS << " __ptr64";
+ if (Quals & Q_Restrict)
+ OS << " __restrict";
+}
+
+void PointerType::outputPost(OutputStream &OS) {
+ if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array)
+ OS << ")";
+
+ Type::outputPost(OS, *Pointee);
+}
+
+Type *FunctionType::clone(ArenaAllocator &Arena) const {
+ return new (Arena) FunctionType(*this);
+}
+
+void FunctionType::outputPre(OutputStream &OS) {
+ if (!(FunctionClass & Global)) {
+ if (FunctionClass & Static)
+ OS << "static ";
+ }
+
+ if (ReturnType)
+ Type::outputPre(OS, *ReturnType);
+
+ 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";
+ return;
+}
+
+Type *UdtType::clone(ArenaAllocator &Arena) const {
+ return new (Arena) 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 new (Arena) 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);
+}
+
+} // 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(OutputStream &OS, StringView s) : OS(OS), MangledName(s) {}
+
+ // 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();
+
+ // True if an error occurred.
+ bool Error = false;
+
+private:
+ Type *demangleVariableEncoding();
+ Type *demangleFunctionEncoding();
+
+ Qualifiers demanglePointerExtQualifiers();
+
+ // Parser functions. This is a recursive-descent parser.
+ Type *demangleType(QualifierMangleMode QMM);
+ Type *demangleBasicType();
+ UdtType *demangleClassType();
+ PointerType *demanglePointerType();
+
+ ArrayType *demangleArrayType();
+
+ ParamList demangleParameterList();
+
+ int demangleNumber();
+ void demangleNamePiece(Name &Node, bool IsHead);
+
+ StringView demangleString(bool memorize);
+ void memorizeString(StringView s);
+ Name *demangleName();
+ void demangleOperator(Name *);
+ StringView demangleOperatorName();
+ int demangleFunctionClass();
+ CallingConv demangleCallingConvention();
+ StorageClass demangleVariableStorageClass();
+ ReferenceKind demangleReferenceKind();
+
+ Qualifiers demangleFunctionQualifiers();
+ Qualifiers demangleVariablQ_ifiers();
+ Qualifiers demangleReturnTypQ_ifiers();
+
+ Qualifiers demangleQualifiers(
+ QualifierMangleLocation Location = QualifierMangleLocation::Detect);
+
+ // Mangled symbol. demangle* functions shorten this string
+ // as they parse it.
+ StringView MangledName;
+
+ // A parsed mangled symbol.
+ Type *SymbolType;
+
+ // The main symbol name. (e.g. "ns::foo" in "int ns::foo()".)
+ Name *SymbolName = nullptr;
+
+ // Memory allocator.
+ ArenaAllocator Arena;
+
+ // 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;
+
+ // The result is written to this stream.
+ OutputStream OS;
+};
+} // namespace
+
+// Parser entry point.
+void Demangler::parse() {
+ // MSVC-style mangled symbols must start with '?'.
+ if (!MangledName.consumeFront("?")) {
+ SymbolName = new (Arena) Name;
+ SymbolName->Str = MangledName;
+ SymbolType = new (Arena) Type;
+ SymbolType->Prim = PrimTy::Unknown;
+ }
+
+ // What follows is a main symbol name. This may include
+ // namespaces or class BackReferences.
+ SymbolName = demangleName();
+
+ // Read a variable.
+ if (startsWithDigit(MangledName)) {
+ SymbolType = demangleVariableEncoding();
+ return;
+ }
+
+ // Read a function.
+ SymbolType = demangleFunctionEncoding();
+}
+
+// <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() {
+ StorageClass SC = demangleVariableStorageClass();
+
+ Type *Ty = demangleType(QualifierMangleMode::Drop);
+
+ Ty->Storage = SC;
+
+ // <variable-type> ::= <type> <cvr-qualifiers>
+ // ::= <type> <pointee-cvr-qualifiers> # pointers, references
+ switch (Ty->Prim) {
+ case PrimTy::Ptr:
+ case PrimTy::Ref: {
+ Qualifiers ExtraChildQuals = Q_None;
+ Ty->Quals = Qualifiers(Ty->Quals | demanglePointerExtQualifiers());
+
+ PointerType *PTy = static_cast<PointerType *>(Ty);
+ QualifierMangleLocation Location = PTy->isMemberPointer()
+ ? QualifierMangleLocation::Member
+ : QualifierMangleLocation::NonMember;
+
+ ExtraChildQuals = demangleQualifiers(Location);
+
+ if (PTy->isMemberPointer()) {
+ Name *BackRefName = demangleName();
+ (void)BackRefName;
+ }
+
+ PTy->Pointee->Quals = Qualifiers(PTy->Pointee->Quals | ExtraChildQuals);
+ break;
+ }
+ default:
+ Ty->Quals = demangleQualifiers();
+ 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() {
+ 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;
+}
+
+// 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) {
+ if (BackRefCount >= sizeof(BackReferences) / sizeof(*BackReferences))
+ return;
+ for (size_t i = 0; i < BackRefCount; ++i)
+ if (S == BackReferences[i])
+ return;
+ 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 = demangleParameterList();
+ if (!MangledName.consumeFront('@')) {
+ Error = true;
+ return;
+ }
+ } 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);
+ }
+}
+
+// Parses a name in the form of A at B@C@@ which represents C::B::A.
+Name *Demangler::demangleName() {
+ Name *Head = nullptr;
+
+ while (!MangledName.consumeFront("@")) {
+ Name *Elem = new (Arena) Name;
+
+ assert(!Error);
+ demangleNamePiece(*Elem, Head == nullptr);
+ if (Error)
+ return nullptr;
+
+ Elem->Next = Head;
+ Head = Elem;
+ }
+
+ return Head;
+}
+
+void Demangler::demangleOperator(Name *OpName) {
+ OpName->Operator = demangleOperatorName();
+ if (!Error && !MangledName.empty() && MangledName.front() != '@')
+ demangleNamePiece(*OpName, false);
+}
+
+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;
+
+ 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";
+ }
+ }
+ }
+
+ Error = true;
+ RestoreOnError.shouldRestore(true);
+ return "";
+}
+
+int Demangler::demangleFunctionClass() {
+ SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
+ RestoreOnError.shouldRestore(false);
+
+ switch (MangledName.popFront()) {
+ case 'A':
+ return Private;
+ case 'B':
+ return Private | FFar;
+ case 'C':
+ return Private | Static;
+ case 'D':
+ return Private | Static;
+ case 'E':
+ return Private | Virtual;
+ case 'F':
+ return Private | Virtual;
+ case 'I':
+ return Protected;
+ case 'J':
+ return Protected | FFar;
+ case 'K':
+ return Protected | Static;
+ case 'L':
+ return Protected | Static | FFar;
+ case 'M':
+ return Protected | Virtual;
+ case 'N':
+ return Protected | Virtual | FFar;
+ case 'Q':
+ return Public;
+ case 'R':
+ return Public | FFar;
+ case 'S':
+ return Public | Static;
+ case 'T':
+ return Public | Static | FFar;
+ case 'U':
+ return Public | Virtual;
+ case 'V':
+ return Public | Virtual | FFar;
+ case 'Y':
+ return Global;
+ case 'Z':
+ return Global | FFar;
+ }
+
+ Error = true;
+ RestoreOnError.shouldRestore(true);
+ return 0;
+}
+
+Qualifiers Demangler::demangleFunctionQualifiers() {
+ SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
+ RestoreOnError.shouldRestore(false);
+
+ switch (MangledName.popFront()) {
+ case 'A':
+ return Q_None;
+ case 'B':
+ return Q_Const;
+ case 'C':
+ return Q_Volatile;
+ case 'D':
+ return Qualifiers(Q_Const | Q_Volatile);
+ }
+
+ Error = true;
+ RestoreOnError.shouldRestore(true);
+ return Q_None;
+}
+
+CallingConv Demangler::demangleCallingConvention() {
+ 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() {
+ 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;
+}
+
+Qualifiers Demangler::demangleVariablQ_ifiers() {
+ SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
+ RestoreOnError.shouldRestore(false);
+
+ switch (MangledName.popFront()) {
+ case 'A':
+ return Q_None;
+ case 'B':
+ return Q_Const;
+ case 'C':
+ return Q_Volatile;
+ case 'D':
+ return Qualifiers(Q_Const | Q_Volatile);
+ case 'E':
+ return Q_Far;
+ case 'F':
+ return Qualifiers(Q_Const | Q_Far);
+ case 'G':
+ return Qualifiers(Q_Volatile | Q_Far);
+ case 'H':
+ return Qualifiers(Q_Const | Q_Volatile | Q_Far);
+ }
+
+ Error = true;
+ RestoreOnError.shouldRestore(true);
+ return Q_None;
+}
+
+Qualifiers Demangler::demangleReturnTypQ_ifiers() {
+ if (!MangledName.consumeFront("?"))
+ return Q_None;
+
+ SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
+ RestoreOnError.shouldRestore(false);
+
+ switch (MangledName.popFront()) {
+ case 'A':
+ return Q_None;
+ case 'B':
+ return Q_Const;
+ case 'C':
+ return Q_Volatile;
+ case 'D':
+ return Qualifiers(Q_Const | Q_Volatile);
+ }
+
+ Error = true;
+ RestoreOnError.shouldRestore(true);
+ return Q_None;
+}
+
+Qualifiers Demangler::demangleQualifiers(QualifierMangleLocation Location) {
+ if (Location == QualifierMangleLocation::Detect) {
+ switch (MangledName.front()) {
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ Location = QualifierMangleLocation::Member;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ Location = QualifierMangleLocation::NonMember;
+ break;
+ default:
+ Error = true;
+ return Q_None;
+ }
+ }
+
+ if (Location == QualifierMangleLocation::Member) {
+ switch (MangledName.popFront()) {
+ // Member qualifiers
+ case 'Q':
+ return Q_None;
+ case 'R':
+ return Q_Const;
+ case 'S':
+ return Q_Volatile;
+ case 'T':
+ return Qualifiers(Q_Const | Q_Volatile);
+ }
+ } else {
+ switch (MangledName.popFront()) {
+ // Non-Member qualifiers
+ case 'A':
+ return Q_None;
+ case 'B':
+ return Q_Const;
+ case 'C':
+ return Q_Volatile;
+ case 'D':
+ return Qualifiers(Q_Const | Q_Volatile);
+ }
+ }
+ Error = true;
+ return Q_None;
+}
+
+// <variable-type> ::= <type> <cvr-qualifiers>
+// ::= <type> <pointee-cvr-qualifiers> # pointers, references
+Type *Demangler::demangleType(QualifierMangleMode QMM) {
+ Qualifiers Quals = Q_None;
+ if (QMM == QualifierMangleMode::Mangle)
+ Quals = Qualifiers(Quals | demangleQualifiers());
+ else if (QMM == QualifierMangleMode::Result) {
+ if (MangledName.consumeFront('?'))
+ Quals = Qualifiers(Quals | demangleQualifiers());
+ }
+
+ 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
+ Ty = demanglePointerType();
+ break;
+ case 'Y':
+ Ty = demangleArrayType();
+ break;
+ default:
+ Ty = demangleBasicType();
+ break;
+ }
+ Ty->Quals = Qualifiers(Ty->Quals | Quals);
+ return Ty;
+}
+
+static bool functionHasThisPtr(const FunctionType &Ty) {
+ assert(Ty.Prim == PrimTy::Function);
+ if (Ty.FunctionClass & Global)
+ return false;
+ if (Ty.FunctionClass & Static)
+ return false;
+ return true;
+}
+
+ReferenceKind Demangler::demangleReferenceKind() {
+ if (MangledName.consumeFront('G'))
+ return ReferenceKind::LValueRef;
+ else if (MangledName.consumeFront('H'))
+ return ReferenceKind::RValueRef;
+ return ReferenceKind::None;
+}
+
+Type *Demangler::demangleFunctionEncoding() {
+ FunctionType *FTy = new (Arena) FunctionType;
+
+ FTy->Prim = PrimTy::Function;
+ FTy->FunctionClass = (FuncClass)demangleFunctionClass();
+ if (functionHasThisPtr(*FTy)) {
+ FTy->Quals = demanglePointerExtQualifiers();
+ FTy->RefKind = demangleReferenceKind();
+ FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers());
+ }
+
+ // Fields that appear on both member and non-member functions.
+ FTy->CallConvention = demangleCallingConvention();
+
+ // <return-type> ::= <type>
+ // ::= @ # structors (they have no declared return type)
+ bool IsStructor = MangledName.consumeFront('@');
+ if (!IsStructor)
+ FTy->ReturnType = demangleType(QualifierMangleMode::Result);
+
+ FTy->Params = demangleParameterList();
+
+ return FTy;
+}
+
+// Reads a primitive type.
+Type *Demangler::demangleBasicType() {
+ Type *Ty = new (Arena) Type;
+
+ 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 '_': {
+ 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;
+ }
+ break;
+ }
+ }
+ return Ty;
+}
+
+UdtType *Demangler::demangleClassType() {
+ UdtType *UTy = new (Arena) 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 = demangleName();
+ return UTy;
+}
+
+// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>
+// # the E is required for 64-bit non-static pointers
+PointerType *Demangler::demanglePointerType() {
+ PointerType *Pointer = new (Arena) PointerType;
+
+ Pointer->Quals = Q_None;
+ switch (MangledName.popFront()) {
+ case 'A':
+ Pointer->Prim = PrimTy::Ref;
+ break;
+ case 'P':
+ Pointer->Prim = PrimTy::Ptr;
+ break;
+ case 'Q':
+ Pointer->Prim = PrimTy::Ptr;
+ Pointer->Quals = Q_Const;
+ break;
+ case 'R':
+ Pointer->Quals = Q_Volatile;
+ Pointer->Prim = PrimTy::Ptr;
+ break;
+ case 'S':
+ Pointer->Quals = Qualifiers(Q_Const | Q_Volatile);
+ Pointer->Prim = PrimTy::Ptr;
+ break;
+ default:
+ assert(false && "Ty is not a pointer type!");
+ }
+
+ if (MangledName.consumeFront("6")) {
+ FunctionType *FTy = new (Arena) FunctionType;
+ FTy->Prim = PrimTy::Function;
+ FTy->CallConvention = demangleCallingConvention();
+
+ FTy->ReturnType = demangleType(QualifierMangleMode::Drop);
+ FTy->Params = demangleParameterList();
+
+ if (!MangledName.consumeFront("@Z"))
+ MangledName.consumeFront("Z");
+
+ Pointer->Pointee = FTy;
+ return Pointer;
+ }
+
+ Qualifiers ExtQuals = demanglePointerExtQualifiers();
+ Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
+
+ Pointer->Pointee = demangleType(QualifierMangleMode::Mangle);
+ return Pointer;
+}
+
+Qualifiers Demangler::demanglePointerExtQualifiers() {
+ 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() {
+ assert(MangledName.front() == 'Y');
+ MangledName.popFront();
+
+ int Dimension = demangleNumber();
+ if (Dimension <= 0) {
+ Error = true;
+ return nullptr;
+ }
+
+ ArrayType *ATy = new (Arena) ArrayType;
+ ArrayType *Dim = ATy;
+ for (int I = 0; I < Dimension; ++I) {
+ Dim->Prim = PrimTy::Array;
+ Dim->ArrayDimension = demangleNumber();
+ Dim->NextDimension = new (Arena) 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(QualifierMangleMode::Drop);
+ Dim->ElementType = ATy->ElementType;
+ return ATy;
+}
+
+// Reads a function or a template parameters.
+ParamList Demangler::demangleParameterList() {
+ // Within the same parameter list, you can backreference the first 10 types.
+ Type *BackRef[10];
+ int Idx = 0;
+
+ ParamList *Head;
+ ParamList **Current = &Head;
+ while (!Error && !MangledName.startsWith('@') &&
+ !MangledName.startsWith('Z')) {
+ if (startsWithDigit(MangledName)) {
+ int N = MangledName[0] - '0';
+ if (N >= Idx) {
+ Error = true;
+ return {};
+ }
+ MangledName = MangledName.dropFront();
+
+ *Current = new (Arena) ParamList;
+ (*Current)->Current = BackRef[N]->clone(Arena);
+ Current = &(*Current)->Next;
+ continue;
+ }
+
+ size_t ArrayDimension = MangledName.size();
+
+ *Current = new (Arena) ParamList;
+ (*Current)->Current = demangleType(QualifierMangleMode::Drop);
+
+ // Single-letter types are ignored for backreferences because
+ // memorizing them doesn't save anything.
+ if (Idx <= 9 && ArrayDimension - MangledName.size() > 1)
+ BackRef[Idx++] = (*Current)->Current;
+ Current = &(*Current)->Next;
+ }
+
+ return *Head;
+}
+
+void Demangler::output() {
+ // 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, *SymbolType);
+ outputName(OS, SymbolName);
+ Type::outputPost(OS, *SymbolType);
+
+ // Null terminate the buffer.
+ OS << '\0';
+}
+
+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();
+
+ if (D.Error)
+ *Status = llvm::demangle_invalid_mangled_name;
+ else
+ *Status = llvm::demangle_success;
+
+ D.output();
+ return OS.getBuffer();
+}
Added: llvm/trunk/test/Demangle/ms-basic.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-basic.test?rev=337584&view=auto
==============================================================================
--- llvm/trunk/test/Demangle/ms-basic.test (added)
+++ llvm/trunk/test/Demangle/ms-basic.test Fri Jul 20 10:27:48 2018
@@ -0,0 +1,230 @@
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+?x@@3HA
+; CHECK: int x
+
+?x@@3PEAHEA
+; CHECK: int *x
+
+?x@@3PEAPEAHEA
+; CHECK: int **x
+
+?x@@3PEAY02HEA
+; CHECK: int (*x)[3]
+
+?x@@3PEAY124HEA
+; CHECK: int (*x)[3][5]
+
+?x@@3PEAY02$$CBHEA
+; CHECK: int const (*x)[3]
+
+?x@@3PEAEEA
+; CHECK: unsigned char *x
+
+?x@@3PEAY1NKM at 5HEA
+; CHECK: int (*x)[3500][6]
+
+?x@@YAXMH at Z
+; CHECK: void __cdecl x(float, int)
+
+?x@@3P6AHMNH at ZEA
+; CHECK: int __cdecl (*x)(float, double, int)
+
+?x@@3P6AHP6AHM at ZN@ZEA
+; CHECK: int __cdecl (*x)(int __cdecl (*)(float), double)
+
+?x@@3P6AHP6AHM at Z0@ZEA
+; CHECK: int __cdecl (*x)(int __cdecl (*)(float), int __cdecl (*)(float))
+
+?x at ns@@3HA
+; CHECK: int ns::x
+
+; Microsoft's undname doesn't handle Q correctly or the multiple occurrences
+; of the const modifier. So the results here differ, but ours are correct.
+?x@@3PEAHEA
+; CHECK: int *x
+
+?x@@3PEBHEB
+; CHECK: int const *x
+
+?x@@3QEAHEA
+; CHECK: int *const x
+
+?x@@3QEBHEB
+; CHECK: int const *const x
+
+
+?x@@3AEBHEB
+; CHECK: int const &x
+
+?x@@3PEAUty@@EA
+; CHECK: struct ty *x
+
+?x@@3PEATty@@EA
+; CHECK: union ty *x
+
+?x@@3PEAUty@@EA
+; CHECK: struct ty *x
+
+?x@@3PEAW4ty@@EA
+; CHECK: enum ty *x
+
+?x@@3PEAVty@@EA
+; CHECK: class ty *x
+
+?x@@3PEAV?$tmpl at H@@EA
+; CHECK: class tmpl<int> *x
+
+?x@@3PEAU?$tmpl at H@@EA
+; CHECK: struct tmpl<int> *x
+
+?x@@3PEAT?$tmpl at H@@EA
+; CHECK: union tmpl<int> *x
+
+?instance@@3Vklass@@A
+; CHECK: class klass instance
+
+?instance$initializer$@@3P6AXXZEA
+; CHECK: void __cdecl (*instance$initializer$)(void)
+
+??0klass@@QEAA at XZ
+; CHECK: __cdecl klass::klass(void)
+
+??1klass@@QEAA at XZ
+; CHECK: __cdecl klass::~klass(void)
+
+?x@@YAHPEAVklass@@AEAV1@@Z
+; CHECK: int __cdecl x(class klass *, class klass &)
+
+?x at ns@@3PEAV?$klass at HH@1 at EA
+; CHECK: class ns::klass<int, int> *ns::x
+
+?fn@?$klass at H@ns@@QEBAIXZ
+; CHECK: unsigned int __cdecl ns::klass<int>::fn(void) const
+
+
+??4klass@@QEAAAEBV0 at AEBV0@@Z
+; CHECK: class klass const &__cdecl klass::operator=(class klass const &)
+
+??7klass@@QEAA_NXZ
+; CHECK: bool __cdecl klass::operator!(void)
+
+??8klass@@QEAA_NAEBV0@@Z
+; CHECK: bool __cdecl klass::operator==(class klass const &)
+
+??9klass@@QEAA_NAEBV0@@Z
+; CHECK: bool __cdecl klass::operator!=(class klass const &)
+
+??Aklass@@QEAAH_K at Z
+; CHECK: int __cdecl klass::operator[](unsigned __int64)
+
+??Cklass@@QEAAHXZ
+; CHECK: int __cdecl klass::operator->(void)
+
+??Dklass@@QEAAHXZ
+; CHECK: int __cdecl klass::operator*(void)
+
+??Eklass@@QEAAHXZ
+; CHECK: int __cdecl klass::operator++(void)
+
+??Eklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator++(int)
+
+??Fklass@@QEAAHXZ
+; CHECK: int __cdecl klass::operator--(void)
+
+??Fklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator--(int)
+
+??Hklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator+(int)
+
+??Gklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator-(int)
+
+??Iklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator&(int)
+
+??Jklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator->*(int)
+
+??Kklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator/(int)
+
+??Mklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator<(int)
+
+??Nklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator<=(int)
+
+??Oklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator>(int)
+
+??Pklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator>=(int)
+
+??Qklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator,(int)
+
+??Rklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator()(int)
+
+??Sklass@@QEAAHXZ
+; CHECK: int __cdecl klass::operator~(void)
+
+??Tklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator^(int)
+
+??Uklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator|(int)
+
+??Vklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator&&(int)
+
+??Wklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator||(int)
+
+??Xklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator*=(int)
+
+??Yklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator+=(int)
+
+??Zklass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator-=(int)
+
+??_0klass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator/=(int)
+
+??_1klass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator%=(int)
+
+??_2klass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator>>=(int)
+
+??_3klass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator<<=(int)
+
+??_6klass@@QEAAHH at Z
+; CHECK: int __cdecl klass::operator^=(int)
+
+??6 at YAAEBVklass@@AEBV0 at H@Z
+; CHECK: class klass const &__cdecl operator<<(class klass const &, int)
+
+??5 at YAAEBVklass@@AEBV0 at _K@Z
+; CHECK: class klass const &__cdecl operator>>(class klass const &, unsigned __int64)
+
+??2 at YAPEAX_KAEAVklass@@@Z
+; CHECK: void *__cdecl operator new(unsigned __int64, class klass &)
+
+??_U at YAPEAX_KAEAVklass@@@Z
+; CHECK: void *__cdecl operator new[](unsigned __int64, class klass &)
+
+??3 at YAXPEAXAEAVklass@@@Z
+; CHECK: void __cdecl operator delete(void *, class klass &)
+
+??_V at YAXPEAXAEAVklass@@@Z
+; CHECK: void __cdecl operator delete[](void *, class klass &)
+
Added: llvm/trunk/test/Demangle/ms-mangle.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-mangle.test?rev=337584&view=auto
==============================================================================
--- llvm/trunk/test/Demangle/ms-mangle.test (added)
+++ llvm/trunk/test/Demangle/ms-mangle.test Fri Jul 20 10:27:48 2018
@@ -0,0 +1,363 @@
+; These tests are based on clang/test/CodeGenCXX/mangle-ms.cpp
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+?k@@3PTfoo@@DT1
+
+
+?a@@3HA
+; CHECK: int a
+
+?b at N@@3HA
+; CHECK: int N::b
+
+?anonymous@?A at N@@3HA
+; CHECK: int N::`anonymous namespace'::anonymous
+
+?_c@@YAHXZ
+; CHECK: int __cdecl _c(void)
+
+?d at foo@@0FB
+; CHECK: static short const foo::d
+
+?e at foo@@1JC
+; CHECK: static long volatile foo::e
+
+?f at foo@@2DD
+; CHECK: static char const volatile foo::f
+
+??0foo@@QAE at XZ
+; CHECK: __thiscall foo::foo(void)
+
+??0foo@@QEAA at XZ
+; CHECK: __cdecl foo::foo(void)
+
+??1foo@@QAE at XZ
+; CHECK: __thiscall foo::~foo(void)
+
+??1foo@@QEAA at XZ
+; CHECK: __cdecl foo::~foo(void)
+
+??0foo@@QAE at H@Z
+; CHECK: __thiscall foo::foo(int)
+
+??0foo@@QEAA at H@Z
+; CHECK: __cdecl foo::foo(int)
+
+??0foo@@QAE at PAD@Z
+; CHECK: __thiscall foo::foo(char *)
+
+??0foo@@QEAA at PEAD@Z
+; CHECK: __cdecl foo::foo(char *)
+
+?bar@@YA?AVfoo@@XZ
+; CHECK: class foo __cdecl bar(void)
+
+?bar@@YA?AVfoo@@XZ
+; CHECK: class foo __cdecl bar(void)
+
+??Hfoo@@QAEHH at Z
+; CHECK: int __thiscall foo::operator+(int)
+
+??Hfoo@@QEAAHH at Z
+; CHECK: int __cdecl foo::operator+(int)
+
+?static_method at foo@@SAPAV1 at XZ
+; CHECK: static class foo *__cdecl foo::static_method(void)
+
+?static_method at foo@@SAPEAV1 at XZ
+; CHECK: static class foo *__cdecl foo::static_method(void)
+
+?g at bar@@2HA
+; CHECK: static int bar::g
+
+; undname returns `int *h1`, but it is a bug in their demangler. Their mangler
+; correctly mangles `int *h1` as ?h1 at 3PAHA and `int * const h1` as ?h1 at 3QAHA
+?h1@@3QAHA
+; CHECK: int *const h1
+
+?h2@@3QBHB
+; CHECK: int const *const h2
+
+?h3@@3QIAHIA
+; CHECK: int * __restrict const h3
+
+?h3@@3QEIAHEIA
+; CHECK: int * __restrict const h3
+
+?i@@3PAY0BE at HA
+; CHECK: int (*i)[20]
+
+?FunArr@@3PAY0BE at P6AHHH@ZA
+; CHECK: int __cdecl (*(*FunArr)[20])(int, int)
+
+?j@@3P6GHCE at ZA
+; CHECK: int __stdcall (*j)(signed char, unsigned char)
+
+
+; FIXME: We don't handle member pointers yet.
+; ?k@@3PTfoo@@DT1
+; FIXME: char const volatile foo::*k
+
+; ?k@@3PETfoo@@DET1
+; FIXME: char const volatile foo::*k
+
+; ?l@@3P8foo@@AEHH at ZQ1
+; FIXME: int __thiscall (foo::*l)(int)
+
+?g_cInt@@3HB
+; CHECK: int const g_cInt
+
+?g_vInt@@3HC
+; CHECK: int volatile g_vInt
+
+?g_cvInt@@3HD
+; CHECK: int const volatile g_cvInt
+
+?beta@@YI_N_J_W at Z
+; CHECK: bool __fastcall beta(__int64, wchar_t)
+
+?beta@@YA_N_J_W at Z
+; CHECK: bool __cdecl beta(__int64, wchar_t)
+
+?alpha@@YGXMN at Z
+; CHECK: void __stdcall alpha(float, double)
+
+?alpha@@YAXMN at Z
+; CHECK: void __cdecl alpha(float, double)
+
+?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z
+; CHECK: void __cdecl gamma(class foo, struct bar, union baz, enum quux)
+
+?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z
+; CHECK: void __cdecl gamma(class foo, struct bar, union baz, enum quux)
+
+?delta@@YAXQAHABJ at Z
+; CHECK: void __cdecl delta(int *const, long const &)
+
+?delta@@YAXQEAHAEBJ at Z
+; CHECK: void __cdecl delta(int *const, long const &)
+
+?epsilon@@YAXQAY19BE at H@Z
+; CHECK: void __cdecl epsilon(int (*const)[10][20])
+
+?epsilon@@YAXQEAY19BE at H@Z
+; CHECK: void __cdecl epsilon(int (*const)[10][20])
+
+?zeta@@YAXP6AHHH at Z@Z
+; CHECK: void __cdecl zeta(int __cdecl (*)(int, int))
+
+?zeta@@YAXP6AHHH at Z@Z
+; CHECK: void __cdecl zeta(int __cdecl (*)(int, int))
+
+??2 at YAPAXI@Z
+; CHECK: void *__cdecl operator new(unsigned int)
+
+??3 at YAXPAX@Z
+; CHECK: void __cdecl operator delete(void *)
+
+??_U at YAPAXI@Z
+; CHECK: void *__cdecl operator new[](unsigned int)
+
+??_V at YAXPAX@Z
+; CHECK: void __cdecl operator delete[](void *)
+
+?color1@@3PANA
+; CHECK: double *color1
+
+?color2@@3QBNB
+; CHECK: double const *const color2
+
+; FIXME-EXTRACONST: These tests fails because we print an extra const inside the parens.
+; ?color3@@3QAY02$$CBNA
+; FIXME-EXTRACONST: double const (*color3)[3]
+
+; ?color4@@3QAY02$$CBNA
+; FIXME-EXTRACONST: double const (*color4)[3]
+
+; FIXME-MEMBERPTR: We don't support member pointers yet.
+; ?memptr1@@3RESB@@HES1
+; FIXME-MEMBERPTR: volatile int B::*memptr2
+
+; ?memptr2@@3PESB@@HES1
+; FIXME: volatile int B::*memptr2
+
+; ?memptr3@@3REQB@@HEQ1
+; FIXME-MEMBERPTR: int B::* volatile memptr3
+
+; ?funmemptr1@@3RESB@@R6AHXZES1
+; FIXME-MEMBERPTR: int __cdecl (* volatile B::* volatile funmemptr1)(void)
+
+; ?funmemptr2@@3PESB@@R6AHXZES1
+; FIXME-MEMBERPTR: int __cdecl (* volatile B::*funmemptr2)(void)
+
+; ?funmemptr3@@3REQB@@P6AHXZEQ1
+; FIXME-MEMBERPTR: int __cdecl (* B::*volatile funmemptr3)(void)
+
+; ?memptrtofun1@@3R8B@@EAAXXZEQ1
+; FIXME-MEMBERPTR: void __cdecl (B::*volatile memptrtofun1)(void)
+
+; ?memptrtofun2@@3P8B@@EAAXXZEQ1
+; FIXME-MEMBERPTR: void __cdecl (B::*memptrtofun2)(void)
+
+; ?memptrtofun3@@3P8B@@EAAXXZEQ1
+; FIXME-MEMBERPTR: void __cdecl (B::*memptrtofun3)(void)
+
+; ?memptrtofun4@@3R8B@@EAAHXZEQ1
+; FIXME-MEMBERPTR: int __cdecl (B::* volatile memptrtofun4)(void)
+
+; ?memptrtofun5@@3P8B@@EAA?CHXZEQ1
+; FIXME-MEMBERPTR: int volatile __cdecl (B::*memptrtofun5)(void)
+
+; ?memptrtofun6@@3P8B@@EAA?BHXZEQ1
+; FIXME-MEMBERPTR: int const __cdecl (B::*memptrtofun6)(void)
+
+; ?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1
+; FIXME-MEMBERPTR: int __cdecl (*(__cdecl B::*volatile memptrtofun7)(void))(void)
+
+; ?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1
+; FIXME-MEMBERPTR: int __cdecl (*(__cdecl B::*memptrtofun8)(void))(void)
+
+; ?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1
+; FIXME-MEMBERPTR: int __cdecl(*(__cdecl B::*memptrtofun9)(void))(void)
+
+
+?fooE@@YA?AW4E@@XZ
+; CHECK: enum E __cdecl fooE(void)
+
+?fooE@@YA?AW4E@@XZ
+; CHECK: enum E __cdecl fooE(void)
+
+?fooX@@YA?AVX@@XZ
+; CHECK: class X __cdecl fooX(void)
+
+?fooX@@YA?AVX@@XZ
+; CHECK: class X __cdecl fooX(void)
+
+?s0 at PR13182@@3PADA
+; CHECK: char *PR13182::s0
+
+?s1 at PR13182@@3PADA
+; CHECK: char *PR13182::s1
+
+?s2 at PR13182@@3QBDB
+; CHECK: char const *const PR13182::s2
+
+?s3 at PR13182@@3QBDB
+; CHECK: char const *const PR13182::s3
+
+?s4 at PR13182@@3RCDC
+; CHECK: char volatile *volatile PR13182::s4
+
+?s5 at PR13182@@3SDDD
+; CHECK: char const volatile *const volatile PR13182::s5
+
+; undname adds an extra const in here, but it seems like their bug.
+?s6 at PR13182@@3PBQBDB
+; CHECK: char const *const *PR13182::s6
+
+; FIXME-EXTERNC: We don't properly support static locals in extern c functions yet.
+; ?local@?1??extern_c_func@@9 at 4HA
+; FIXME-EXTERNC: int `extern_c_func'::`2'::local
+
+; ?local@?1??extern_c_func@@9 at 4HA
+; FIXME-EXTERNC: int `extern_c_func'::`2'::local
+
+??2OverloadedNewDelete@@SAPAXI at Z
+; CHECK: static void *__cdecl OverloadedNewDelete::operator new(unsigned int)
+
+
+??_UOverloadedNewDelete@@SAPAXI at Z
+; CHECK: static void *__cdecl OverloadedNewDelete::operator new[](unsigned int)
+
+??3OverloadedNewDelete@@SAXPAX at Z
+; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *)
+
+
+??_VOverloadedNewDelete@@SAXPAX at Z
+; CHECK: static void __cdecl OverloadedNewDelete::operator delete[](void *)
+
+??HOverloadedNewDelete@@QAEHH at Z
+; CHECK: int __thiscall OverloadedNewDelete::operator+(int)
+
+??2OverloadedNewDelete@@SAPEAX_K at Z
+; CHECK: static void *__cdecl OverloadedNewDelete::operator new(unsigned __int64)
+
+??_UOverloadedNewDelete@@SAPEAX_K at Z
+; CHECK: static void *__cdecl OverloadedNewDelete::operator new[](unsigned __int64)
+
+??3OverloadedNewDelete@@SAXPEAX at Z
+; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *)
+
+
+??_VOverloadedNewDelete@@SAXPEAX at Z
+; CHECK: static void __cdecl OverloadedNewDelete::operator delete[](void *)
+
+??HOverloadedNewDelete@@QEAAHH at Z
+; CHECK: int __cdecl OverloadedNewDelete::operator+(int)
+
+
+??2TypedefNewDelete@@SAPAXI at Z
+; CHECK: static void *__cdecl TypedefNewDelete::operator new(unsigned int)
+
+
+??_UTypedefNewDelete@@SAPAXI at Z
+; CHECK: static void *__cdecl TypedefNewDelete::operator new[](unsigned int)
+
+??3TypedefNewDelete@@SAXPAX at Z
+; CHECK: static void __cdecl TypedefNewDelete::operator delete(void *)
+
+??_VTypedefNewDelete@@SAXPAX at Z
+; CHECK: static void __cdecl TypedefNewDelete::operator delete[](void *)
+
+?vector_func@@YQXXZ
+; CHECK: void __vectorcall vector_func(void)
+
+; FIXME-EXTERNC: We don't support extern C funcs currently.
+; ??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ
+; FIXME-EXTERNC: void __cdecl fn_tmpl<&void __cdecl extern_c_func(void)>(void)
+
+; ?overloaded_fn@@$$J0YAXXZ
+; FIXME-EXTERNC: extern \"C\" void __cdecl overloaded_fn(void)
+
+
+?f at UnnamedType@@YAXUT2 at S@1@@Z
+; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T2)
+
+?f at UnnamedType@@YAXPAUT4 at S@1@@Z
+; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T4 *)
+
+?f at UnnamedType@@YAXUT4 at S@1@@Z
+; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T4)
+
+?f at UnnamedType@@YAXUT5 at S@1@@Z
+; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T5)
+
+?f at UnnamedType@@YAXUT2 at S@1@@Z
+; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T2)
+
+?f at UnnamedType@@YAXUT4 at S@1@@Z
+; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T4)
+
+?f at UnnamedType@@YAXUT5 at S@1@@Z
+; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T5)
+
+?f at Atomic@@YAXU?$_Atomic at H@__clang@@@Z
+; CHECK: void __cdecl Atomic::f(struct __clang::_Atomic<int>)
+
+?f at Complex@@YAXU?$_Complex at H@__clang@@@Z
+; CHECK: void __cdecl Complex::f(struct __clang::_Complex<int>)
+
+?f at Float16@@YAXU_Float16 at __clang@@@Z
+; CHECK: void __cdecl Float16::f(struct __clang::_Float16)
+
+
+??0?$L at H@NS@@QEAA at XZ
+; CHECK: __cdecl NS::L<int>::L<int>(void)
+
+??0Bar at Foo@@QEAA at XZ
+; CHECK: __cdecl Foo::Bar::Bar(void)
+
+??0?$L at V?$H at PAH@PR26029@@@PR26029@@QAE at XZ
+; CHECK: __thiscall PR26029::L<class PR26029::H<int *>>::L<class PR26029::H<int *>>(void)
Added: llvm/trunk/test/Demangle/ms-windows.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-windows.test?rev=337584&view=auto
==============================================================================
--- llvm/trunk/test/Demangle/ms-windows.test (added)
+++ llvm/trunk/test/Demangle/ms-windows.test Fri Jul 20 10:27:48 2018
@@ -0,0 +1,17 @@
+; See clang/test/CodeGenCXX/mangle-windows.cpp
+; These tests are based on clang/test/CodeGenCXX/mangle-ms.cpp
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+?bar at Foo@@SGXXZ
+; CHECK: static void __stdcall Foo::bar(void)
+
+?bar at Foo@@QAGXXZ
+; CHECK: void __stdcall Foo::bar(void)
+
+?f2@@YIXXZ
+; CHECK: void __fastcall f2(void)
+
+?f1@@YGXXZ
+; CHECK: void __stdcall f1(void)
Modified: llvm/trunk/tools/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/LLVMBuild.txt?rev=337584&r1=337583&r2=337584&view=diff
==============================================================================
--- llvm/trunk/tools/LLVMBuild.txt (original)
+++ llvm/trunk/tools/LLVMBuild.txt Fri Jul 20 10:27:48 2018
@@ -50,6 +50,7 @@ subdirectories =
llvm-rtdyld
llvm-size
llvm-split
+ llvm-undname
opt
verify-uselistorder
Added: llvm/trunk/tools/llvm-undname/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-undname/CMakeLists.txt?rev=337584&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-undname/CMakeLists.txt (added)
+++ llvm/trunk/tools/llvm-undname/CMakeLists.txt Fri Jul 20 10:27:48 2018
@@ -0,0 +1,8 @@
+set(LLVM_LINK_COMPONENTS
+ Demangle
+ Support
+ )
+
+add_llvm_tool(llvm-undname
+ llvm-undname.cpp
+ )
Added: llvm/trunk/tools/llvm-undname/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-undname/LLVMBuild.txt?rev=337584&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-undname/LLVMBuild.txt (added)
+++ llvm/trunk/tools/llvm-undname/LLVMBuild.txt Fri Jul 20 10:27:48 2018
@@ -0,0 +1,23 @@
+;===- ./tools/llvm-undname/LLVMBuild.txt -----------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Tool
+name = llvm-undname
+parent = Tools
+required_libraries = Demangle Support
+
Added: llvm/trunk/tools/llvm-undname/llvm-undname.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-undname/llvm-undname.cpp?rev=337584&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-undname/llvm-undname.cpp (added)
+++ llvm/trunk/tools/llvm-undname/llvm-undname.cpp Fri Jul 20 10:27:48 2018
@@ -0,0 +1,79 @@
+//===-- llvm-undname.cpp - Microsoft ABI name undecorator
+//------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This utility works like the windows undname utility. It converts mangled
+// Microsoft symbol names into pretty C/C++ human-readable names.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+#include <string>
+
+using namespace llvm;
+
+cl::list<std::string> Symbols(cl::Positional, cl::desc("<input symbols>"),
+ cl::ZeroOrMore);
+
+static void demangle(const std::string &S) {
+ int Status;
+ char *ResultBuf = microsoftDemangle(S.c_str(), nullptr, nullptr, &Status);
+ if (Status == llvm::demangle_success) {
+ outs() << ResultBuf << "\n";
+ outs().flush();
+ } else {
+ errs() << "Error: Invalid mangled name\n";
+ }
+ std::free(ResultBuf);
+};
+
+int main(int argc, char **argv) {
+ InitLLVM X(argc, argv);
+
+ cl::ParseCommandLineOptions(argc, argv, "llvm-undname\n");
+
+ if (Symbols.empty()) {
+ while (true) {
+ std::string LineStr;
+ std::getline(std::cin, LineStr);
+ if (std::cin.eof())
+ break;
+
+ StringRef Line(LineStr);
+ Line = Line.trim();
+ if (Line.empty() || Line.startswith("#") || Line.startswith(";"))
+ continue;
+
+ // If the user is manually typing in these decorated names, don't echo
+ // them to the terminal a second time. If they're coming from redirected
+ // input, however, then we should display the input line so that the
+ // mangled and demangled name can be easily correlated in the output.
+ if (!sys::Process::StandardInIsUserInput())
+ outs() << Line << "\n";
+ demangle(Line);
+ outs() << "\n";
+ }
+ } else {
+ for (StringRef S : Symbols) {
+ outs() << S << "\n";
+ demangle(S);
+ outs() << "\n";
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
More information about the llvm-commits
mailing list