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