2018-07-21 01:27:48 +08:00
|
|
|
//===- 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>
|
2018-07-27 03:56:09 +08:00
|
|
|
#include <tuple>
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
// 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;
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
size_t Capacity = 0;
|
2018-07-21 01:27:48 +08:00
|
|
|
AllocatorNode *Next = nullptr;
|
|
|
|
};
|
|
|
|
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
public:
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
ArenaAllocator() { addNode(Unit); }
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
~ArenaAllocator() {
|
|
|
|
while (Head) {
|
|
|
|
assert(Head->Buf);
|
|
|
|
delete[] Head->Buf;
|
2018-07-24 02:21:43 +08:00
|
|
|
AllocatorNode *Next = Head->Next;
|
|
|
|
delete Head;
|
|
|
|
Head = Next;
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
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(Unit, Length));
|
|
|
|
Head->Used = Length;
|
|
|
|
Buf = Head->Buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
return reinterpret_cast<char *>(Buf);
|
|
|
|
}
|
|
|
|
|
2018-07-21 02:35:06 +08:00
|
|
|
template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {
|
|
|
|
|
|
|
|
size_t Size = sizeof(T);
|
2018-07-21 01:27:48 +08:00
|
|
|
assert(Head && Head->Buf);
|
|
|
|
|
2018-07-21 02:35:06 +08:00
|
|
|
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;
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
if (Head->Used < Head->Capacity)
|
2018-07-21 02:35:06 +08:00
|
|
|
return new (PP) T(std::forward<Args>(ConstructorArgs)...);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
addNode(ArenaAllocator::Unit);
|
|
|
|
Head->Used = Size;
|
|
|
|
return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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 << " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 };
|
2018-07-27 03:56:09 +08:00
|
|
|
|
|
|
|
enum class PointerAffinity { Pointer, Reference };
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
// 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,
|
2018-07-27 03:56:09 +08:00
|
|
|
MemberPtr,
|
2018-07-21 01:27:48 +08:00
|
|
|
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,
|
2018-07-21 02:07:33 +08:00
|
|
|
Far = 1 << 6,
|
2018-07-21 01:27:48 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct Type;
|
|
|
|
|
|
|
|
// Represents a list of parameters (template params or function arguments.
|
|
|
|
// It's represented as a linked list.
|
|
|
|
struct ParamList {
|
2018-07-27 04:20:10 +08:00
|
|
|
bool IsVariadic = false;
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
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;
|
2018-07-21 02:22:12 +08:00
|
|
|
void outputPre(OutputStream &OS) override;
|
2018-07-21 01:27:48 +08:00
|
|
|
void outputPost(OutputStream &OS) override;
|
|
|
|
|
2018-07-27 03:56:09 +08:00
|
|
|
// 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;
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
// 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;
|
2018-07-21 02:22:12 +08:00
|
|
|
void outputPre(OutputStream &OS) override;
|
|
|
|
void outputPost(OutputStream &OS) override;
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-27 04:33:48 +08:00
|
|
|
// True if this FunctionType instance is the Pointee of a PointerType or
|
|
|
|
// MemberPointerType.
|
|
|
|
bool IsFunctionPointer = false;
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
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
|
|
|
|
|
2018-07-27 03:56:09 +08:00
|
|
|
static bool isMemberPointer(StringView MangledName) {
|
|
|
|
switch (MangledName.popFront()) {
|
|
|
|
case 'A':
|
|
|
|
// 'A' indicates a reference, and you cannot have a reference to a member
|
|
|
|
// function or member variable.
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
// Write a function or template parameter list.
|
|
|
|
static void outputParameterList(OutputStream &OS, const ParamList &Params) {
|
2018-07-27 04:20:10 +08:00
|
|
|
if (!Params.Current) {
|
|
|
|
OS << "void";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
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);
|
|
|
|
|
2018-07-29 06:10:42 +08:00
|
|
|
const Name *Previous = nullptr;
|
2018-07-21 01:27:48 +08:00
|
|
|
// Print out namespaces or outer class BackReferences.
|
|
|
|
for (; TheName->Next; TheName = TheName->Next) {
|
2018-07-29 06:10:42 +08:00
|
|
|
Previous = TheName;
|
2018-07-21 01:27:48 +08:00
|
|
|
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.
|
2018-07-29 06:10:42 +08:00
|
|
|
if (TheName->Operator == "dtor")
|
|
|
|
OS << "~";
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
if (TheName->Operator == "ctor" || TheName->Operator == "dtor") {
|
2018-07-29 06:10:42 +08:00
|
|
|
OS << Previous->Str;
|
|
|
|
outputTemplateParams(OS, *Previous);
|
2018-07-21 01:27:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print out an overloaded operator.
|
|
|
|
if (!TheName->Str.empty())
|
|
|
|
OS << TheName->Str << "::";
|
|
|
|
OS << "operator" << TheName->Operator;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
Type *Type::clone(ArenaAllocator &Arena) const {
|
2018-07-21 02:35:06 +08:00
|
|
|
return Arena.alloc<Type>(*this);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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";
|
|
|
|
}
|
2018-07-27 04:25:35 +08:00
|
|
|
|
|
|
|
if (Ty.Quals & Q_Restrict) {
|
|
|
|
outputSpaceIfNecessary(OS);
|
|
|
|
OS << "__restrict";
|
|
|
|
}
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2018-07-21 02:35:06 +08:00
|
|
|
return Arena.alloc<PointerType>(*this);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
2018-07-27 04:33:48 +08:00
|
|
|
static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity,
|
|
|
|
const Name *MemberName,
|
|
|
|
const Type *Pointee) {
|
2018-07-21 01:27:48 +08:00
|
|
|
// "[]" 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)".)
|
2018-07-27 04:33:48 +08:00
|
|
|
if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array) {
|
2018-07-21 01:27:48 +08:00
|
|
|
OS << "(";
|
2018-07-27 04:33:48 +08:00
|
|
|
if (Pointee->Prim == PrimTy::Function) {
|
|
|
|
const FunctionType *FTy = static_cast<const FunctionType *>(Pointee);
|
|
|
|
assert(FTy->IsFunctionPointer);
|
|
|
|
outputCallingConvention(OS, FTy->CallConvention);
|
|
|
|
OS << " ";
|
|
|
|
}
|
|
|
|
}
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-27 04:33:48 +08:00
|
|
|
if (MemberName) {
|
|
|
|
outputName(OS, MemberName);
|
|
|
|
OS << "::";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Affinity == PointerAffinity::Pointer)
|
2018-07-21 01:27:48 +08:00
|
|
|
OS << "*";
|
|
|
|
else
|
|
|
|
OS << "&";
|
2018-07-27 04:33:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PointerType::outputPre(OutputStream &OS) {
|
|
|
|
Type::outputPre(OS, *Pointee);
|
|
|
|
|
|
|
|
outputSpaceIfNecessary(OS);
|
|
|
|
|
|
|
|
if (Quals & Q_Unaligned)
|
|
|
|
OS << "__unaligned ";
|
|
|
|
|
|
|
|
PointerAffinity Affinity = (Prim == PrimTy::Ptr) ? PointerAffinity::Pointer
|
|
|
|
: PointerAffinity::Reference;
|
|
|
|
|
|
|
|
outputPointerIndicator(OS, Affinity, nullptr, Pointee);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-21 02:07:33 +08:00
|
|
|
// FIXME: We should output this, but it requires updating lots of tests.
|
2018-07-21 01:27:48 +08:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2018-07-27 03:56:09 +08:00
|
|
|
Type *MemberPointerType::clone(ArenaAllocator &Arena) const {
|
|
|
|
return Arena.alloc<MemberPointerType>(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MemberPointerType::outputPre(OutputStream &OS) {
|
|
|
|
Type::outputPre(OS, *Pointee);
|
|
|
|
|
|
|
|
outputSpaceIfNecessary(OS);
|
|
|
|
|
2018-07-27 04:33:48 +08:00
|
|
|
outputPointerIndicator(OS, PointerAffinity::Pointer, MemberName, Pointee);
|
2018-07-27 03:56:09 +08:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
Type *FunctionType::clone(ArenaAllocator &Arena) const {
|
2018-07-21 02:35:06 +08:00
|
|
|
return Arena.alloc<FunctionType>(*this);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionType::outputPre(OutputStream &OS) {
|
|
|
|
if (!(FunctionClass & Global)) {
|
|
|
|
if (FunctionClass & Static)
|
|
|
|
OS << "static ";
|
|
|
|
}
|
|
|
|
|
2018-07-27 04:20:10 +08:00
|
|
|
if (ReturnType) {
|
2018-07-21 01:27:48 +08:00
|
|
|
Type::outputPre(OS, *ReturnType);
|
2018-07-27 04:20:10 +08:00
|
|
|
OS << " ";
|
|
|
|
}
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-27 04:33:48 +08:00
|
|
|
// 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);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionType::outputPost(OutputStream &OS) {
|
|
|
|
OS << "(";
|
|
|
|
outputParameterList(OS, Params);
|
|
|
|
OS << ")";
|
|
|
|
if (Quals & Q_Const)
|
|
|
|
OS << " const";
|
|
|
|
if (Quals & Q_Volatile)
|
|
|
|
OS << " volatile";
|
2018-07-27 04:20:10 +08:00
|
|
|
|
|
|
|
if (ReturnType)
|
|
|
|
Type::outputPost(OS, *ReturnType);
|
2018-07-21 01:27:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type *UdtType::clone(ArenaAllocator &Arena) const {
|
2018-07-21 02:35:06 +08:00
|
|
|
return Arena.alloc<UdtType>(*this);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2018-07-21 02:35:06 +08:00
|
|
|
return Arena.alloc<ArrayType>(*this);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
struct Symbol {
|
|
|
|
Name *SymbolName = nullptr;
|
|
|
|
Type *SymbolType = nullptr;
|
|
|
|
};
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
} // 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:
|
2018-07-30 00:38:02 +08:00
|
|
|
Demangler() = default;
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
// 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.
|
2018-07-30 00:38:02 +08:00
|
|
|
Symbol *parse(StringView &MangledName);
|
|
|
|
void output(const Symbol *S, OutputStream &OS);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
// True if an error occurred.
|
|
|
|
bool Error = false;
|
|
|
|
|
|
|
|
private:
|
2018-07-30 00:38:02 +08:00
|
|
|
Type *demangleVariableEncoding(StringView &MangledName);
|
|
|
|
Type *demangleFunctionEncoding(StringView &MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Qualifiers demanglePointerExtQualifiers(StringView &MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
// Parser functions. This is a recursive-descent parser.
|
2018-07-30 00:38:02 +08:00
|
|
|
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);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
ArrayType *demangleArrayType(StringView &MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
ParamList demangleTemplateParameterList(StringView &MangledName);
|
|
|
|
ParamList demangleFunctionParameterList(StringView &MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
int demangleNumber(StringView &MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
void memorizeString(StringView s);
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
|
|
|
|
/// Allocate a copy of \p Borrowed into memory that we own.
|
|
|
|
StringView copyString(StringView Borrowed);
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *demangleFullyQualifiedTypeName(StringView &MangledName);
|
|
|
|
Name *demangleFullyQualifiedSymbolName(StringView &MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *demangleUnqualifiedTypeName(StringView &MangledName);
|
|
|
|
Name *demangleUnqualifiedSymbolName(StringView &MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *demangleNameScopeChain(StringView &MangledName, Name *UnqualifiedName);
|
|
|
|
Name *demangleNameScopePiece(StringView &MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *demangleBackRefName(StringView &MangledName);
|
|
|
|
Name *demangleClassTemplateName(StringView &MangledName);
|
|
|
|
Name *demangleOperatorName(StringView &MangledName);
|
|
|
|
Name *demangleSimpleName(StringView &MangledName, bool Memorize);
|
|
|
|
Name *demangleAnonymousNamespaceName(StringView &MangledName);
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
Name *demangleLocallyScopedNamePiece(StringView &MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
void demangleOperator(StringView &MangledName, Name *);
|
|
|
|
FuncClass demangleFunctionClass(StringView &MangledName);
|
|
|
|
CallingConv demangleCallingConvention(StringView &MangledName);
|
|
|
|
StorageClass demangleVariableStorageClass(StringView &MangledName);
|
|
|
|
ReferenceKind demangleReferenceKind(StringView &MangledName);
|
|
|
|
void demangleThrowSpecification(StringView &MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
std::pair<Qualifiers, bool> demangleQualifiers(StringView &MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
// Memory allocator.
|
|
|
|
ArenaAllocator Arena;
|
|
|
|
|
2018-07-27 06:13:39 +08:00
|
|
|
// 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;
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
// 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
|
|
|
|
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
StringView Demangler::copyString(StringView Borrowed) {
|
|
|
|
char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1);
|
|
|
|
std::strcpy(Stable, Borrowed.begin());
|
|
|
|
|
|
|
|
return {Stable, Borrowed.size()};
|
|
|
|
}
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
// Parser entry point.
|
2018-07-30 00:38:02 +08:00
|
|
|
Symbol *Demangler::parse(StringView &MangledName) {
|
|
|
|
Symbol *S = Arena.alloc<Symbol>();
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
// MSVC-style mangled symbols must start with '?'.
|
|
|
|
if (!MangledName.consumeFront("?")) {
|
2018-07-30 00:38:02 +08:00
|
|
|
S->SymbolName = Arena.alloc<Name>();
|
|
|
|
S->SymbolName->Str = MangledName;
|
|
|
|
S->SymbolType = Arena.alloc<Type>();
|
|
|
|
S->SymbolType->Prim = PrimTy::Unknown;
|
|
|
|
return S;
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// What follows is a main symbol name. This may include
|
|
|
|
// namespaces or class BackReferences.
|
2018-07-30 00:38:02 +08:00
|
|
|
S->SymbolName = demangleFullyQualifiedSymbolName(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
// Read a variable.
|
2018-07-30 00:38:02 +08:00
|
|
|
S->SymbolType = startsWithDigit(MangledName)
|
|
|
|
? demangleVariableEncoding(MangledName)
|
|
|
|
: demangleFunctionEncoding(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
return S;
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// <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
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Type *Demangler::demangleVariableEncoding(StringView &MangledName) {
|
|
|
|
StorageClass SC = demangleVariableStorageClass(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Type *Ty = demangleType(MangledName, QualifierMangleMode::Drop);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
Ty->Storage = SC;
|
|
|
|
|
|
|
|
// <variable-type> ::= <type> <cvr-qualifiers>
|
|
|
|
// ::= <type> <pointee-cvr-qualifiers> # pointers, references
|
|
|
|
switch (Ty->Prim) {
|
|
|
|
case PrimTy::Ptr:
|
2018-07-27 03:56:09 +08:00
|
|
|
case PrimTy::Ref:
|
|
|
|
case PrimTy::MemberPtr: {
|
2018-07-21 01:27:48 +08:00
|
|
|
Qualifiers ExtraChildQuals = Q_None;
|
2018-07-30 00:38:02 +08:00
|
|
|
Ty->Quals =
|
|
|
|
Qualifiers(Ty->Quals | demanglePointerExtQualifiers(MangledName));
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-27 03:56:09 +08:00
|
|
|
bool IsMember = false;
|
2018-07-30 00:38:02 +08:00
|
|
|
std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-27 03:56:09 +08:00
|
|
|
if (Ty->Prim == PrimTy::MemberPtr) {
|
|
|
|
assert(IsMember);
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *BackRefName = demangleFullyQualifiedTypeName(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
(void)BackRefName;
|
2018-07-27 03:56:09 +08:00
|
|
|
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);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2018-07-30 00:38:02 +08:00
|
|
|
Ty->Quals = demangleQualifiers(MangledName).first;
|
2018-07-21 01:27:48 +08:00
|
|
|
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, ...
|
2018-07-30 00:38:02 +08:00
|
|
|
int Demangler::demangleNumber(StringView &MangledName) {
|
2018-07-21 01:27:48 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleBackRefName(StringView &MangledName) {
|
2018-07-29 06:10:42 +08:00
|
|
|
assert(startsWithDigit(MangledName));
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-29 06:10:42 +08:00
|
|
|
size_t I = MangledName[0] - '0';
|
|
|
|
if (I >= BackRefCount) {
|
|
|
|
Error = true;
|
|
|
|
return nullptr;
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
2018-07-29 06:10:42 +08:00
|
|
|
MangledName = MangledName.dropFront();
|
|
|
|
Name *Node = Arena.alloc<Name>();
|
|
|
|
Node->Str = BackReferences[I];
|
|
|
|
return Node;
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleClassTemplateName(StringView &MangledName) {
|
2018-07-29 06:10:42 +08:00
|
|
|
assert(MangledName.startsWith("?$"));
|
|
|
|
MangledName.consumeFront("?$");
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Node = demangleSimpleName(MangledName, false);
|
|
|
|
Node->TemplateParams = demangleTemplateParameterList(MangledName);
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2018-07-29 06:10:42 +08:00
|
|
|
return Node;
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleOperatorName(StringView &MangledName) {
|
2018-07-29 06:10:42 +08:00
|
|
|
assert(MangledName.startsWith('?'));
|
|
|
|
MangledName.consumeFront('?');
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
auto NameString = [this, &MangledName]() -> StringView {
|
2018-07-21 01:27:48 +08:00
|
|
|
switch (MangledName.popFront()) {
|
|
|
|
case '0':
|
2018-07-29 06:10:42 +08:00
|
|
|
return "ctor";
|
2018-07-21 01:27:48 +08:00
|
|
|
case '1':
|
2018-07-29 06:10:42 +08:00
|
|
|
return "dtor";
|
2018-07-21 01:27:48 +08:00
|
|
|
case '2':
|
2018-07-29 06:10:42 +08:00
|
|
|
return " new";
|
2018-07-21 01:27:48 +08:00
|
|
|
case '3':
|
2018-07-29 06:10:42 +08:00
|
|
|
return " delete";
|
2018-07-21 01:27:48 +08:00
|
|
|
case '4':
|
2018-07-29 06:10:42 +08:00
|
|
|
return "=";
|
2018-07-21 01:27:48 +08:00
|
|
|
case '5':
|
2018-07-29 06:10:42 +08:00
|
|
|
return ">>";
|
2018-07-21 01:27:48 +08:00
|
|
|
case '6':
|
2018-07-29 06:10:42 +08:00
|
|
|
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 "^";
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'U':
|
2018-07-29 06:10:42 +08:00
|
|
|
return "|";
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'V':
|
2018-07-29 06:10:42 +08:00
|
|
|
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";
|
|
|
|
}
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
2018-07-29 06:10:42 +08:00
|
|
|
}
|
|
|
|
Error = true;
|
|
|
|
return "";
|
|
|
|
};
|
|
|
|
|
|
|
|
Name *Node = Arena.alloc<Name>();
|
|
|
|
Node->Operator = NameString();
|
|
|
|
return Node;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) {
|
2018-07-29 06:10:42 +08:00
|
|
|
Name *Node = Arena.alloc<Name>();
|
|
|
|
for (size_t i = 0; i < MangledName.size(); ++i) {
|
|
|
|
if (MangledName[i] != '@')
|
|
|
|
continue;
|
|
|
|
Node->Str = MangledName.substr(0, i);
|
|
|
|
MangledName = MangledName.dropFront(i + 1);
|
|
|
|
|
|
|
|
if (Memorize)
|
|
|
|
memorizeString(Node->Str);
|
|
|
|
return Node;
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Error = true;
|
2018-07-29 06:10:42 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleAnonymousNamespaceName(StringView &MangledName) {
|
2018-07-29 06:10:42 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-07-29 06:10:42 +08:00
|
|
|
// Parses a type name in the form of A@B@C@@ which represents C::B::A.
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {
|
|
|
|
Name *TypeName = demangleUnqualifiedTypeName(MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
assert(TypeName);
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *QualName = demangleNameScopeChain(MangledName, TypeName);
|
2018-07-29 06:10:42 +08:00
|
|
|
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.
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) {
|
|
|
|
Name *SymbolName = demangleUnqualifiedSymbolName(MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
assert(SymbolName);
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *QualName = demangleNameScopeChain(MangledName, SymbolName);
|
2018-07-29 06:10:42 +08:00
|
|
|
assert(QualName);
|
|
|
|
return QualName;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleUnqualifiedTypeName(StringView &MangledName) {
|
2018-07-29 06:10:42 +08:00
|
|
|
// 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))
|
2018-07-30 00:38:02 +08:00
|
|
|
return demangleBackRefName(MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
|
|
|
|
if (MangledName.startsWith("?$"))
|
2018-07-30 00:38:02 +08:00
|
|
|
return demangleClassTemplateName(MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
return demangleSimpleName(MangledName, true);
|
2018-07-29 06:10:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleUnqualifiedSymbolName(StringView &MangledName) {
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
if (startsWithDigit(MangledName))
|
|
|
|
return demangleBackRefName(MangledName);
|
|
|
|
if (MangledName.startsWith("?$"))
|
|
|
|
return demangleClassTemplateName(MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
if (MangledName.startsWith('?'))
|
2018-07-30 00:38:02 +08:00
|
|
|
return demangleOperatorName(MangledName);
|
|
|
|
return demangleSimpleName(MangledName, true);
|
2018-07-29 06:10:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleNameScopePiece(StringView &MangledName) {
|
2018-07-29 06:10:42 +08:00
|
|
|
if (startsWithDigit(MangledName))
|
2018-07-30 00:38:02 +08:00
|
|
|
return demangleBackRefName(MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
|
|
|
|
if (MangledName.startsWith("?$"))
|
2018-07-30 00:38:02 +08:00
|
|
|
return demangleClassTemplateName(MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
|
|
|
|
if (MangledName.startsWith("?A"))
|
2018-07-30 00:38:02 +08:00
|
|
|
return demangleAnonymousNamespaceName(MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
if (startsWithLocalScopePattern(MangledName))
|
|
|
|
return demangleLocallyScopedNamePiece(MangledName);
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
return demangleSimpleName(MangledName, true);
|
2018-07-29 06:10:42 +08:00
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Demangler::demangleNameScopeChain(StringView &MangledName,
|
|
|
|
Name *UnqualifiedName) {
|
2018-07-29 06:10:42 +08:00
|
|
|
Name *Head = UnqualifiedName;
|
|
|
|
|
|
|
|
while (!MangledName.consumeFront("@")) {
|
|
|
|
if (MangledName.empty()) {
|
|
|
|
Error = true;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!Error);
|
2018-07-30 00:38:02 +08:00
|
|
|
Name *Elem = demangleNameScopePiece(MangledName);
|
2018-07-29 06:10:42 +08:00
|
|
|
if (Error)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
Elem->Next = Head;
|
|
|
|
Head = Elem;
|
|
|
|
}
|
|
|
|
return Head;
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {
|
2018-07-21 01:27:48 +08:00
|
|
|
SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
|
|
|
|
RestoreOnError.shouldRestore(false);
|
|
|
|
|
|
|
|
switch (MangledName.popFront()) {
|
|
|
|
case 'A':
|
|
|
|
return Private;
|
|
|
|
case 'B':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Private | Far);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'C':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Private | Static);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'D':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Private | Static);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'E':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Private | Virtual);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'F':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Private | Virtual);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'I':
|
|
|
|
return Protected;
|
|
|
|
case 'J':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Protected | Far);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'K':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Protected | Static);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'L':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Protected | Static | Far);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'M':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Protected | Virtual);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'N':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Protected | Virtual | Far);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'Q':
|
|
|
|
return Public;
|
|
|
|
case 'R':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Public | Far);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'S':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Public | Static);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'T':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Public | Static | Far);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'U':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Public | Virtual);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'V':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Public | Virtual | Far);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'Y':
|
|
|
|
return Global;
|
|
|
|
case 'Z':
|
2018-07-27 04:20:10 +08:00
|
|
|
return FuncClass(Global | Far);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Error = true;
|
|
|
|
RestoreOnError.shouldRestore(true);
|
2018-07-27 04:20:10 +08:00
|
|
|
return Public;
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
CallingConv Demangler::demangleCallingConvention(StringView &MangledName) {
|
2018-07-21 01:27:48 +08:00
|
|
|
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;
|
2018-07-21 02:43:42 +08:00
|
|
|
}
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {
|
2018-07-21 01:27:48 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
std::pair<Qualifiers, bool>
|
|
|
|
Demangler::demangleQualifiers(StringView &MangledName) {
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
switch (MangledName.popFront()) {
|
2018-07-27 03:56:09 +08:00
|
|
|
// 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
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'A':
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Q_None, false);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'B':
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Q_Const, false);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'C':
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Q_Volatile, false);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'D':
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
Error = true;
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Q_None, false);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// <variable-type> ::= <type> <cvr-qualifiers>
|
|
|
|
// ::= <type> <pointee-cvr-qualifiers> # pointers, references
|
2018-07-30 00:38:02 +08:00
|
|
|
Type *Demangler::demangleType(StringView &MangledName,
|
|
|
|
QualifierMangleMode QMM) {
|
2018-07-21 01:27:48 +08:00
|
|
|
Qualifiers Quals = Q_None;
|
2018-07-27 03:56:09 +08:00
|
|
|
bool IsMember = false;
|
|
|
|
bool IsMemberKnown = false;
|
|
|
|
if (QMM == QualifierMangleMode::Mangle) {
|
2018-07-30 00:38:02 +08:00
|
|
|
std::tie(Quals, IsMember) = demangleQualifiers(MangledName);
|
2018-07-27 03:56:09 +08:00
|
|
|
IsMemberKnown = true;
|
|
|
|
} else if (QMM == QualifierMangleMode::Result) {
|
|
|
|
if (MangledName.consumeFront('?')) {
|
2018-07-30 00:38:02 +08:00
|
|
|
std::tie(Quals, IsMember) = demangleQualifiers(MangledName);
|
2018-07-27 03:56:09 +08:00
|
|
|
IsMemberKnown = true;
|
|
|
|
}
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Type *Ty = nullptr;
|
|
|
|
switch (MangledName.front()) {
|
|
|
|
case 'T': // union
|
|
|
|
case 'U': // struct
|
|
|
|
case 'V': // class
|
|
|
|
case 'W': // enum
|
2018-07-30 00:38:02 +08:00
|
|
|
Ty = demangleClassType(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
break;
|
|
|
|
case 'A': // foo &
|
|
|
|
case 'P': // foo *
|
|
|
|
case 'Q': // foo *const
|
|
|
|
case 'R': // foo *volatile
|
|
|
|
case 'S': // foo *const volatile
|
2018-07-27 03:56:09 +08:00
|
|
|
if (!IsMemberKnown)
|
|
|
|
IsMember = isMemberPointer(MangledName);
|
|
|
|
if (IsMember)
|
2018-07-30 00:38:02 +08:00
|
|
|
Ty = demangleMemberPointerType(MangledName);
|
2018-07-27 03:56:09 +08:00
|
|
|
else
|
2018-07-30 00:38:02 +08:00
|
|
|
Ty = demanglePointerType(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
break;
|
|
|
|
case 'Y':
|
2018-07-30 00:38:02 +08:00
|
|
|
Ty = demangleArrayType(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
break;
|
|
|
|
default:
|
2018-07-30 00:38:02 +08:00
|
|
|
Ty = demangleBasicType(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Ty->Quals = Qualifiers(Ty->Quals | Quals);
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
ReferenceKind Demangler::demangleReferenceKind(StringView &MangledName) {
|
2018-07-21 01:27:48 +08:00
|
|
|
if (MangledName.consumeFront('G'))
|
|
|
|
return ReferenceKind::LValueRef;
|
|
|
|
else if (MangledName.consumeFront('H'))
|
|
|
|
return ReferenceKind::RValueRef;
|
|
|
|
return ReferenceKind::None;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
void Demangler::demangleThrowSpecification(StringView &MangledName) {
|
2018-07-27 04:20:10 +08:00
|
|
|
if (MangledName.consumeFront('Z'))
|
|
|
|
return;
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-27 04:20:10 +08:00
|
|
|
Error = true;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
FunctionType *Demangler::demangleFunctionType(StringView &MangledName,
|
|
|
|
bool HasThisQuals,
|
2018-07-27 04:33:48 +08:00
|
|
|
bool IsFunctionPointer) {
|
2018-07-27 04:20:10 +08:00
|
|
|
FunctionType *FTy = Arena.alloc<FunctionType>();
|
2018-07-21 01:27:48 +08:00
|
|
|
FTy->Prim = PrimTy::Function;
|
2018-07-27 04:33:48 +08:00
|
|
|
FTy->IsFunctionPointer = IsFunctionPointer;
|
2018-07-27 04:20:10 +08:00
|
|
|
|
|
|
|
if (HasThisQuals) {
|
2018-07-30 00:38:02 +08:00
|
|
|
FTy->Quals = demanglePointerExtQualifiers(MangledName);
|
|
|
|
FTy->RefKind = demangleReferenceKind(MangledName);
|
|
|
|
FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers(MangledName).first);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fields that appear on both member and non-member functions.
|
2018-07-30 00:38:02 +08:00
|
|
|
FTy->CallConvention = demangleCallingConvention(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
// <return-type> ::= <type>
|
|
|
|
// ::= @ # structors (they have no declared return type)
|
|
|
|
bool IsStructor = MangledName.consumeFront('@');
|
|
|
|
if (!IsStructor)
|
2018-07-30 00:38:02 +08:00
|
|
|
FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
FTy->Params = demangleFunctionParameterList(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
demangleThrowSpecification(MangledName);
|
2018-07-27 04:20:10 +08:00
|
|
|
|
|
|
|
return FTy;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Type *Demangler::demangleFunctionEncoding(StringView &MangledName) {
|
|
|
|
FuncClass FC = demangleFunctionClass(MangledName);
|
2018-07-27 04:20:10 +08:00
|
|
|
|
|
|
|
bool HasThisQuals = !(FC & (Global | Static));
|
2018-07-30 00:38:02 +08:00
|
|
|
FunctionType *FTy = demangleFunctionType(MangledName, HasThisQuals, false);
|
2018-07-27 04:20:10 +08:00
|
|
|
FTy->FunctionClass = FC;
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
return FTy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reads a primitive type.
|
2018-07-30 00:38:02 +08:00
|
|
|
Type *Demangler::demangleBasicType(StringView &MangledName) {
|
2018-07-21 02:35:06 +08:00
|
|
|
Type *Ty = Arena.alloc<Type>();
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
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 '_': {
|
2018-07-21 02:07:33 +08:00
|
|
|
if (MangledName.empty()) {
|
|
|
|
Error = true;
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-07-21 01:27:48 +08:00
|
|
|
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;
|
2018-07-21 02:07:33 +08:00
|
|
|
default:
|
|
|
|
assert(false);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
UdtType *Demangler::demangleClassType(StringView &MangledName) {
|
2018-07-21 02:35:06 +08:00
|
|
|
UdtType *UTy = Arena.alloc<UdtType>();
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
UTy->UdtName = demangleFullyQualifiedTypeName(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
return UTy;
|
|
|
|
}
|
|
|
|
|
2018-07-27 03:56:09 +08:00
|
|
|
static std::pair<Qualifiers, PointerAffinity>
|
|
|
|
demanglePointerCVQualifiers(StringView &MangledName) {
|
2018-07-21 01:27:48 +08:00
|
|
|
switch (MangledName.popFront()) {
|
|
|
|
case 'A':
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Q_None, PointerAffinity::Reference);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'P':
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Q_None, PointerAffinity::Pointer);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'Q':
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Q_Const, PointerAffinity::Pointer);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'R':
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Q_Volatile, PointerAffinity::Pointer);
|
2018-07-21 01:27:48 +08:00
|
|
|
case 'S':
|
2018-07-27 03:56:09 +08:00
|
|
|
return std::make_pair(Qualifiers(Q_Const | Q_Volatile),
|
|
|
|
PointerAffinity::Pointer);
|
2018-07-21 01:27:48 +08:00
|
|
|
default:
|
|
|
|
assert(false && "Ty is not a pointer type!");
|
|
|
|
}
|
2018-07-27 03:56:09 +08:00
|
|
|
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
|
2018-07-30 00:38:02 +08:00
|
|
|
PointerType *Demangler::demanglePointerType(StringView &MangledName) {
|
2018-07-27 03:56:09 +08:00
|
|
|
PointerType *Pointer = Arena.alloc<PointerType>();
|
|
|
|
|
|
|
|
PointerAffinity Affinity;
|
|
|
|
std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-27 03:56:09 +08:00
|
|
|
Pointer->Prim =
|
|
|
|
(Affinity == PointerAffinity::Pointer) ? PrimTy::Ptr : PrimTy::Ref;
|
2018-07-21 01:27:48 +08:00
|
|
|
if (MangledName.consumeFront("6")) {
|
2018-07-30 00:38:02 +08:00
|
|
|
Pointer->Pointee = demangleFunctionType(MangledName, false, true);
|
2018-07-21 01:27:48 +08:00
|
|
|
return Pointer;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle);
|
2018-07-21 01:27:48 +08:00
|
|
|
return Pointer;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
MemberPointerType *
|
|
|
|
Demangler::demangleMemberPointerType(StringView &MangledName) {
|
2018-07-27 03:56:09 +08:00
|
|
|
MemberPointerType *Pointer = Arena.alloc<MemberPointerType>();
|
|
|
|
Pointer->Prim = PrimTy::MemberPtr;
|
|
|
|
|
|
|
|
PointerAffinity Affinity;
|
|
|
|
std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName);
|
|
|
|
assert(Affinity == PointerAffinity::Pointer);
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);
|
2018-07-27 03:56:09 +08:00
|
|
|
Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
|
|
|
|
|
2018-07-27 04:20:10 +08:00
|
|
|
if (MangledName.consumeFront("8")) {
|
2018-07-30 00:38:02 +08:00
|
|
|
Pointer->MemberName = demangleFullyQualifiedSymbolName(MangledName);
|
|
|
|
Pointer->Pointee = demangleFunctionType(MangledName, true, true);
|
2018-07-27 04:20:10 +08:00
|
|
|
} else {
|
|
|
|
Qualifiers PointeeQuals = Q_None;
|
|
|
|
bool IsMember = false;
|
2018-07-30 00:38:02 +08:00
|
|
|
std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName);
|
2018-07-27 04:20:10 +08:00
|
|
|
assert(IsMember);
|
2018-07-30 00:38:02 +08:00
|
|
|
Pointer->MemberName = demangleFullyQualifiedSymbolName(MangledName);
|
2018-07-27 04:20:10 +08:00
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop);
|
2018-07-27 04:20:10 +08:00
|
|
|
Pointer->Pointee->Quals = PointeeQuals;
|
|
|
|
}
|
2018-07-27 03:56:09 +08:00
|
|
|
|
|
|
|
return Pointer;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
Qualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) {
|
2018-07-21 01:27:48 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
ArrayType *Demangler::demangleArrayType(StringView &MangledName) {
|
2018-07-21 01:27:48 +08:00
|
|
|
assert(MangledName.front() == 'Y');
|
|
|
|
MangledName.popFront();
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
int Dimension = demangleNumber(MangledName);
|
2018-07-21 01:27:48 +08:00
|
|
|
if (Dimension <= 0) {
|
|
|
|
Error = true;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-07-21 02:35:06 +08:00
|
|
|
ArrayType *ATy = Arena.alloc<ArrayType>();
|
2018-07-21 01:27:48 +08:00
|
|
|
ArrayType *Dim = ATy;
|
|
|
|
for (int I = 0; I < Dimension; ++I) {
|
|
|
|
Dim->Prim = PrimTy::Array;
|
2018-07-30 00:38:02 +08:00
|
|
|
Dim->ArrayDimension = demangleNumber(MangledName);
|
2018-07-21 02:35:06 +08:00
|
|
|
Dim->NextDimension = Arena.alloc<ArrayType>();
|
2018-07-21 01:27:48 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop);
|
2018-07-21 01:27:48 +08:00
|
|
|
Dim->ElementType = ATy->ElementType;
|
|
|
|
return ATy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reads a function or a template parameters.
|
2018-07-30 00:38:02 +08:00
|
|
|
ParamList Demangler::demangleFunctionParameterList(StringView &MangledName) {
|
2018-07-27 04:20:10 +08:00
|
|
|
// Empty parameter list.
|
|
|
|
if (MangledName.consumeFront('X'))
|
|
|
|
return {};
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
ParamList *Head;
|
|
|
|
ParamList **Current = &Head;
|
|
|
|
while (!Error && !MangledName.startsWith('@') &&
|
|
|
|
!MangledName.startsWith('Z')) {
|
2018-07-27 06:13:39 +08:00
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
if (startsWithDigit(MangledName)) {
|
2018-07-27 06:24:01 +08:00
|
|
|
size_t N = MangledName[0] - '0';
|
2018-07-27 06:13:39 +08:00
|
|
|
if (N >= FunctionParamBackRefCount) {
|
2018-07-21 01:27:48 +08:00
|
|
|
Error = true;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
MangledName = MangledName.dropFront();
|
|
|
|
|
2018-07-21 02:35:06 +08:00
|
|
|
*Current = Arena.alloc<ParamList>();
|
2018-07-27 06:13:39 +08:00
|
|
|
(*Current)->Current = FunctionParamBackRefs[N]->clone(Arena);
|
2018-07-21 01:27:48 +08:00
|
|
|
Current = &(*Current)->Next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-07-27 06:13:39 +08:00
|
|
|
size_t OldSize = MangledName.size();
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-21 02:35:06 +08:00
|
|
|
*Current = Arena.alloc<ParamList>();
|
2018-07-30 00:38:02 +08:00
|
|
|
(*Current)->Current = demangleType(MangledName, QualifierMangleMode::Drop);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
2018-07-27 06:13:39 +08:00
|
|
|
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;
|
|
|
|
|
2018-07-21 01:27:48 +08:00
|
|
|
Current = &(*Current)->Next;
|
|
|
|
}
|
|
|
|
|
2018-07-27 04:20:10 +08:00
|
|
|
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 {};
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
ParamList Demangler::demangleTemplateParameterList(StringView &MangledName) {
|
2018-07-27 06:13:39 +08:00
|
|
|
ParamList *Head;
|
|
|
|
ParamList **Current = &Head;
|
|
|
|
while (!Error && !MangledName.startsWith('@')) {
|
|
|
|
|
|
|
|
// Template parameter lists don't participate in back-referencing.
|
|
|
|
*Current = Arena.alloc<ParamList>();
|
2018-07-30 00:38:02 +08:00
|
|
|
(*Current)->Current = demangleType(MangledName, QualifierMangleMode::Drop);
|
2018-07-27 06:13:39 +08:00
|
|
|
|
|
|
|
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 {};
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
void Demangler::output(const Symbol *S, OutputStream &OS) {
|
2018-07-21 01:27:48 +08:00
|
|
|
// 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.
|
2018-07-30 00:38:02 +08:00
|
|
|
Type::outputPre(OS, *S->SymbolType);
|
|
|
|
outputName(OS, S->SymbolName);
|
|
|
|
Type::outputPost(OS, *S->SymbolType);
|
2018-07-21 01:27:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N,
|
|
|
|
int *Status) {
|
2018-07-30 00:38:02 +08:00
|
|
|
Demangler D;
|
|
|
|
StringView Name{MangledName};
|
|
|
|
Symbol *S = D.parse(Name);
|
2018-07-21 01:27:48 +08:00
|
|
|
|
|
|
|
if (D.Error)
|
|
|
|
*Status = llvm::demangle_invalid_mangled_name;
|
|
|
|
else
|
|
|
|
*Status = llvm::demangle_success;
|
|
|
|
|
2018-07-30 00:38:02 +08:00
|
|
|
OutputStream OS = OutputStream::create(Buf, N, 1024);
|
|
|
|
D.output(S, OS);
|
[MS Demangler] Demangle symbols in function scopes.
There are a couple of issues you run into when you start getting into
more complex names, especially with regards to function local statics.
When you've got something like:
int x() {
static int n = 0;
return n;
}
Then this needs to demangle to something like
int `int __cdecl x()'::`1'::n
The nested mangled symbols (e.g. `int __cdecl x()` in the above
example) also share state with regards to back-referencing, so
we need to be able to re-use the demangler in the middle of
demangling a symbol while sharing back-ref state.
To make matters more complicated, there are a lot of ambiguities
when demangling a symbol's qualified name, because a function local
scope pattern (usually something like `?1??name?`) looks suspiciously
like many other possible things that can occur, such as `?1` meaning
the second back-ref and disambiguating these cases is rather
interesting. The `?1?` in a local scope pattern is actually a special
case of the more general pattern of `? + <encoded number> + ?`, where
"encoded number" can itself have embedded `@` symbols, which is a
common delimeter in mangled names. So we have to take care during the
disambiguation, which is the reason for the overly complicated
`isLocalScopePattern` function in this patch.
I've added some pretty obnoxious tests to exercise all of this, which
exposed several other problems related to back-referencing, so those
are fixed here as well. Finally, I've uncommented some tests that were
previously marked as `FIXME`, since now these work.
Differential Revision: https://reviews.llvm.org/D49965
llvm-svn: 338226
2018-07-30 11:12:34 +08:00
|
|
|
OS << '\0';
|
2018-07-21 01:27:48 +08:00
|
|
|
return OS.getBuffer();
|
|
|
|
}
|