mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[demangler] Add a partial demangling API for LLDB.
This parses a mangled name into an AST (typically an intermediate stage in itaniumDemangle) and provides some functions to query certain properties or print certain parts of the demangled name. Differential revision: https://reviews.llvm.org/D44668 llvm-svn: 329951
This commit is contained in:
parent
3fbc0e3d51
commit
0491f0a0a5
@ -25,4 +25,57 @@ namespace llvm {
|
||||
|
||||
char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
|
||||
int *status);
|
||||
}
|
||||
|
||||
/// "Partial" demangler. This supports demangling a string into an AST
|
||||
/// (typically an intermediate stage in itaniumDemangle) and querying certain
|
||||
/// properties or partially printing the demangled name.
|
||||
struct ItaniumPartialDemangler {
|
||||
ItaniumPartialDemangler();
|
||||
|
||||
ItaniumPartialDemangler(ItaniumPartialDemangler &&Other);
|
||||
ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other);
|
||||
|
||||
/// Demangle into an AST. Subsequent calls to the rest of the member functions
|
||||
/// implicitly operate on the AST this produces.
|
||||
/// \return true on error, false otherwise
|
||||
bool partialDemangle(const char *MangledName);
|
||||
|
||||
/// Just print the entire mangled name into Buf. Buf and N behave like the
|
||||
/// second and third parameters to itaniumDemangle.
|
||||
char *finishDemangle(char *Buf, size_t *N) const;
|
||||
|
||||
/// Get the base name of a function. This doesn't include trailing template
|
||||
/// arguments, ie for "a::b<int>" this function returns "b".
|
||||
char *getFunctionBaseName(char *Buf, size_t *N) const;
|
||||
|
||||
/// Get the context name for a function. For "a::b::c", this function returns
|
||||
/// "a::b".
|
||||
char *getFunctionDeclContextName(char *Buf, size_t *N) const;
|
||||
|
||||
/// Get the entire name of this function.
|
||||
char *getFunctionName(char *Buf, size_t *N) const;
|
||||
|
||||
/// Get the parameters for this function.
|
||||
char *getFunctionParameters(char *Buf, size_t *N) const;
|
||||
char *getFunctionReturnType(char *Buf, size_t *N) const;
|
||||
|
||||
/// If this function has any any cv or reference qualifiers. These imply that
|
||||
/// the function is a non-static member function.
|
||||
bool hasFunctionQualifiers() const;
|
||||
|
||||
/// If this symbol describes a function.
|
||||
bool isFunction() const;
|
||||
|
||||
/// If this symbol describes a variable.
|
||||
bool isData() const;
|
||||
|
||||
/// If this symbol is a <special-name>. These are generally implicitly
|
||||
/// generated by the implementation, such as vtables and typeinfo names.
|
||||
bool isSpecialName() const;
|
||||
|
||||
~ItaniumPartialDemangler();
|
||||
private:
|
||||
void *RootNode;
|
||||
void *Context;
|
||||
};
|
||||
} // namespace llvm
|
||||
|
@ -5089,3 +5089,194 @@ char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
|
||||
*Status = InternalStatus;
|
||||
return InternalStatus == success ? Buf : nullptr;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
ItaniumPartialDemangler::ItaniumPartialDemangler()
|
||||
: RootNode(nullptr), Context(new Db{nullptr, nullptr}) {}
|
||||
|
||||
ItaniumPartialDemangler::~ItaniumPartialDemangler() {
|
||||
delete static_cast<Db *>(Context);
|
||||
}
|
||||
|
||||
ItaniumPartialDemangler::ItaniumPartialDemangler(
|
||||
ItaniumPartialDemangler &&Other)
|
||||
: RootNode(Other.RootNode), Context(Other.Context) {
|
||||
Other.Context = Other.RootNode = nullptr;
|
||||
}
|
||||
|
||||
ItaniumPartialDemangler &ItaniumPartialDemangler::
|
||||
operator=(ItaniumPartialDemangler &&Other) {
|
||||
std::swap(RootNode, Other.RootNode);
|
||||
std::swap(Context, Other.Context);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Demangle MangledName into an AST, storing it into this->RootNode.
|
||||
bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
|
||||
Db *Parser = static_cast<Db *>(Context);
|
||||
size_t Len = std::strlen(MangledName);
|
||||
Parser->reset(MangledName, MangledName + Len);
|
||||
RootNode = Parser->parse();
|
||||
return RootNode == nullptr;
|
||||
}
|
||||
|
||||
static char *printNode(Node *RootNode, char *Buf, size_t *N) {
|
||||
OutputStream S;
|
||||
if (initializeOutputStream(Buf, N, S, 128))
|
||||
return nullptr;
|
||||
RootNode->print(S);
|
||||
S += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
return S.getBuffer();
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
|
||||
if (!isFunction())
|
||||
return nullptr;
|
||||
|
||||
Node *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
|
||||
|
||||
while (true) {
|
||||
switch (Name->getKind()) {
|
||||
case Node::KAbiTagAttr:
|
||||
Name = static_cast<AbiTagAttr *>(Name)->Base;
|
||||
continue;
|
||||
case Node::KStdQualifiedName:
|
||||
Name = static_cast<StdQualifiedName *>(Name)->Child;
|
||||
continue;
|
||||
case Node::KNestedName:
|
||||
Name = static_cast<NestedName *>(Name)->Name;
|
||||
continue;
|
||||
case Node::KLocalName:
|
||||
Name = static_cast<LocalName *>(Name)->Entity;
|
||||
continue;
|
||||
case Node::KNameWithTemplateArgs:
|
||||
Name = static_cast<NameWithTemplateArgs *>(Name)->Name;
|
||||
continue;
|
||||
default:
|
||||
return printNode(Name, Buf, N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
|
||||
size_t *N) const {
|
||||
if (!isFunction())
|
||||
return nullptr;
|
||||
Node *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
|
||||
|
||||
OutputStream S;
|
||||
if (initializeOutputStream(Buf, N, S, 128))
|
||||
return nullptr;
|
||||
|
||||
KeepGoingLocalFunction:
|
||||
while (true) {
|
||||
if (Name->getKind() == Node::KAbiTagAttr) {
|
||||
Name = static_cast<AbiTagAttr *>(Name)->Base;
|
||||
continue;
|
||||
}
|
||||
if (Name->getKind() == Node::KNameWithTemplateArgs) {
|
||||
Name = static_cast<NameWithTemplateArgs *>(Name)->Name;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Name->getKind()) {
|
||||
case Node::KStdQualifiedName:
|
||||
S += "std";
|
||||
break;
|
||||
case Node::KNestedName:
|
||||
static_cast<NestedName *>(Name)->Qual->print(S);
|
||||
break;
|
||||
case Node::KLocalName: {
|
||||
auto *LN = static_cast<LocalName *>(Name);
|
||||
LN->Encoding->print(S);
|
||||
S += "::";
|
||||
Name = LN->Entity;
|
||||
goto KeepGoingLocalFunction;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
S += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
return S.getBuffer();
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
|
||||
if (!isFunction())
|
||||
return nullptr;
|
||||
auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
|
||||
return printNode(Name, Buf, N);
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
|
||||
size_t *N) const {
|
||||
if (!isFunction())
|
||||
return nullptr;
|
||||
NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
|
||||
|
||||
OutputStream S;
|
||||
if (initializeOutputStream(Buf, N, S, 128))
|
||||
return nullptr;
|
||||
|
||||
S += '(';
|
||||
Params.printWithComma(S);
|
||||
S += ')';
|
||||
S += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
return S.getBuffer();
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::getFunctionReturnType(
|
||||
char *Buf, size_t *N) const {
|
||||
if (!isFunction())
|
||||
return nullptr;
|
||||
|
||||
OutputStream S;
|
||||
if (initializeOutputStream(Buf, N, S, 128))
|
||||
return nullptr;
|
||||
|
||||
if (Node *Ret = static_cast<FunctionEncoding *>(RootNode)->getReturnType())
|
||||
Ret->print(S);
|
||||
|
||||
S += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
return S.getBuffer();
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
|
||||
assert(RootNode != nullptr && "must call partialDemangle()");
|
||||
return printNode(static_cast<Node *>(RootNode), Buf, N);
|
||||
}
|
||||
|
||||
bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
|
||||
assert(RootNode != nullptr && "must call partialDemangle()");
|
||||
if (!isFunction())
|
||||
return false;
|
||||
auto *E = static_cast<FunctionEncoding *>(RootNode);
|
||||
return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
|
||||
}
|
||||
|
||||
bool ItaniumPartialDemangler::isFunction() const {
|
||||
assert(RootNode != nullptr && "must call partialDemangle()");
|
||||
return static_cast<Node *>(RootNode)->getKind() == Node::KFunctionEncoding;
|
||||
}
|
||||
|
||||
bool ItaniumPartialDemangler::isSpecialName() const {
|
||||
assert(RootNode != nullptr && "must call partialDemangle()");
|
||||
auto K = static_cast<Node *>(RootNode)->getKind();
|
||||
return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
|
||||
}
|
||||
|
||||
bool ItaniumPartialDemangler::isData() const {
|
||||
return !isFunction() && !isSpecialName();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ add_subdirectory(AsmParser)
|
||||
add_subdirectory(Bitcode)
|
||||
add_subdirectory(CodeGen)
|
||||
add_subdirectory(DebugInfo)
|
||||
add_subdirectory(Demangle)
|
||||
add_subdirectory(ExecutionEngine)
|
||||
add_subdirectory(FuzzMutate)
|
||||
add_subdirectory(IR)
|
||||
|
7
unittests/Demangle/CMakeLists.txt
Normal file
7
unittests/Demangle/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
set(DemangleSources
|
||||
PartialDemangleTest.cpp
|
||||
)
|
||||
|
||||
add_llvm_unittest(DemangleTests
|
||||
${DemangleSources}
|
||||
)
|
121
unittests/Demangle/PartialDemangleTest.cpp
Normal file
121
unittests/Demangle/PartialDemangleTest.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
//===----------------------- PartialDemangleTest.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <cstdlib>
|
||||
#include "llvm/Demangle/Demangle.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
struct ChoppedName {
|
||||
const char *Mangled;
|
||||
const char *ContextName, *BaseName, *ReturnType, *Params;
|
||||
};
|
||||
|
||||
static ChoppedName NamesToTest[] = {
|
||||
{"_Z1fv", "", "f", "", "()"},
|
||||
{"_ZN1a1b1cIiiiEEvm", "a::b", "c", "void", "(unsigned long)"},
|
||||
{"_ZZ5OuterIiEivEN5Inner12inner_memberEv",
|
||||
"int Outer<int>()::Inner", "inner_member", "", "()"},
|
||||
{"_Z1fIiEPFvvEv", "", "f", "void (*)()", "()"},
|
||||
{"_ZN1S1fIiEEvv", "S", "f", "void", "()"},
|
||||
|
||||
// Call operator for a lambda in f().
|
||||
{"_ZZ1fvENK3$_0clEi", "f()::$_0", "operator()", "", "(int)"},
|
||||
|
||||
// A call operator for a lambda in a lambda in f().
|
||||
{"_ZZZ1fvENK3$_0clEvENKUlvE_clEv",
|
||||
"f()::$_0::operator()() const::'lambda'()", "operator()", "", "()"},
|
||||
|
||||
{"_ZZN1S1fEiiEd0_NKUlvE_clEv",
|
||||
"S::f(int, int)::'lambda'()", "operator()", "", "()"},
|
||||
|
||||
{"_ZN1Scv7MuncherIJDpPT_EEIJFivEA_iEEEv",
|
||||
"S", "operator Muncher<int (*)(), int (*) []>", "", "()"},
|
||||
|
||||
// Attributes.
|
||||
{"_ZN5test4IdE1fEUa9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEi",
|
||||
"test4<double>", "f", "", "(int)"},
|
||||
{"_ZN1SC2B8ctor_tagEv", "S", "S", "", "()"},
|
||||
{"_ZN1S1fB4MERPIiEEvv", "S", "f", "void", "()"},
|
||||
|
||||
{"_ZNSsC1EmcRKSaIcE",
|
||||
"std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
|
||||
"basic_string", "", "(unsigned long, char, std::allocator<char> const&)"},
|
||||
{"_ZNSsixEm", "std::string", "operator[]", "", "(unsigned long)"},
|
||||
{"_ZSt17__throw_bad_allocv", "std", "__throw_bad_alloc", "", "()"},
|
||||
|
||||
{"_ZN1AI1BEC2Ev", "A<B>", "A", "", "()"},
|
||||
{"_ZN1AI1BED2Ev", "A<B>", "~A", "", "()"},
|
||||
{"_ZN1AI1BECI24BaseEi", "A<B>", "A", "", "(int)"},
|
||||
{"_ZNKR1AI1BE1fIiEEiv", "A<B>", "f", "int", "()"},
|
||||
|
||||
{"_ZN1SIJicfEE3mfnIJjcdEEEvicfDpT_", "S<int, char, float>",
|
||||
"mfn", "void", "(int, char, float, unsigned int, char, double)"},
|
||||
};
|
||||
|
||||
TEST(PartialDemangleTest, TestNameChopping) {
|
||||
size_t Size = 1;
|
||||
char *Buf = static_cast<char *>(std::malloc(Size));
|
||||
|
||||
llvm::ItaniumPartialDemangler D;
|
||||
|
||||
for (ChoppedName &N : NamesToTest) {
|
||||
EXPECT_FALSE(D.partialDemangle(N.Mangled));
|
||||
EXPECT_TRUE(D.isFunction());
|
||||
EXPECT_FALSE(D.isData());
|
||||
EXPECT_FALSE(D.isSpecialName());
|
||||
|
||||
Buf = D.getFunctionDeclContextName(Buf, &Size);
|
||||
EXPECT_STREQ(Buf, N.ContextName);
|
||||
|
||||
Buf = D.getFunctionBaseName(Buf, &Size);
|
||||
EXPECT_STREQ(Buf, N.BaseName);
|
||||
|
||||
Buf = D.getFunctionReturnType(Buf, &Size);
|
||||
EXPECT_STREQ(Buf, N.ReturnType);
|
||||
|
||||
Buf = D.getFunctionParameters(Buf, &Size);
|
||||
EXPECT_STREQ(Buf, N.Params);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PartialDemangleTest, TestNameMeta) {
|
||||
llvm::ItaniumPartialDemangler Demangler;
|
||||
|
||||
EXPECT_FALSE(Demangler.partialDemangle("_ZNK1f1gEv"));
|
||||
EXPECT_TRUE(Demangler.isFunction());
|
||||
EXPECT_TRUE(Demangler.hasFunctionQualifiers());
|
||||
EXPECT_FALSE(Demangler.isSpecialName());
|
||||
EXPECT_FALSE(Demangler.isData());
|
||||
|
||||
EXPECT_FALSE(Demangler.partialDemangle("_Z1fv"));
|
||||
EXPECT_FALSE(Demangler.hasFunctionQualifiers());
|
||||
|
||||
EXPECT_FALSE(Demangler.partialDemangle("_ZTV1S"));
|
||||
EXPECT_TRUE(Demangler.isSpecialName());
|
||||
EXPECT_FALSE(Demangler.isData());
|
||||
EXPECT_FALSE(Demangler.isFunction());
|
||||
|
||||
EXPECT_FALSE(Demangler.partialDemangle("_ZN1aDC1a1b1cEE"));
|
||||
EXPECT_FALSE(Demangler.isFunction());
|
||||
EXPECT_FALSE(Demangler.isSpecialName());
|
||||
EXPECT_TRUE(Demangler.isData());
|
||||
}
|
||||
|
||||
TEST(PartialDemanglerTest, TestMisc) {
|
||||
llvm::ItaniumPartialDemangler D1, D2;
|
||||
|
||||
EXPECT_FALSE(D1.partialDemangle("_Z1fv"));
|
||||
EXPECT_FALSE(D2.partialDemangle("_Z1g"));
|
||||
std::swap(D1, D2);
|
||||
EXPECT_FALSE(D1.isFunction());
|
||||
EXPECT_TRUE(D2.isFunction());
|
||||
|
||||
EXPECT_TRUE(D1.partialDemangle("Not a mangled name!"));
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user