[llvm] r329951 - [demangler] Add a partial demangling API for LLDB.
Erik Pilkington via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 12 13:41:38 PDT 2018
Author: epilk
Date: Thu Apr 12 13:41:38 2018
New Revision: 329951
URL: http://llvm.org/viewvc/llvm-project?rev=329951&view=rev
Log:
[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
Added:
llvm/trunk/unittests/Demangle/
llvm/trunk/unittests/Demangle/CMakeLists.txt
llvm/trunk/unittests/Demangle/PartialDemangleTest.cpp
Modified:
llvm/trunk/include/llvm/Demangle/Demangle.h
llvm/trunk/lib/Demangle/ItaniumDemangle.cpp
llvm/trunk/unittests/CMakeLists.txt
Modified: llvm/trunk/include/llvm/Demangle/Demangle.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Demangle/Demangle.h?rev=329951&r1=329950&r2=329951&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Demangle/Demangle.h (original)
+++ llvm/trunk/include/llvm/Demangle/Demangle.h Thu Apr 12 13:41:38 2018
@@ -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
Modified: llvm/trunk/lib/Demangle/ItaniumDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/ItaniumDemangle.cpp?rev=329951&r1=329950&r2=329951&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/ItaniumDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/ItaniumDemangle.cpp Thu Apr 12 13:41:38 2018
@@ -5089,3 +5089,194 @@ char *llvm::itaniumDemangle(const char *
*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();
+}
+
+}
Modified: llvm/trunk/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CMakeLists.txt?rev=329951&r1=329950&r2=329951&view=diff
==============================================================================
--- llvm/trunk/unittests/CMakeLists.txt (original)
+++ llvm/trunk/unittests/CMakeLists.txt Thu Apr 12 13:41:38 2018
@@ -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)
Added: llvm/trunk/unittests/Demangle/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Demangle/CMakeLists.txt?rev=329951&view=auto
==============================================================================
--- llvm/trunk/unittests/Demangle/CMakeLists.txt (added)
+++ llvm/trunk/unittests/Demangle/CMakeLists.txt Thu Apr 12 13:41:38 2018
@@ -0,0 +1,7 @@
+set(DemangleSources
+ PartialDemangleTest.cpp
+)
+
+add_llvm_unittest(DemangleTests
+ ${DemangleSources}
+)
Added: llvm/trunk/unittests/Demangle/PartialDemangleTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Demangle/PartialDemangleTest.cpp?rev=329951&view=auto
==============================================================================
--- llvm/trunk/unittests/Demangle/PartialDemangleTest.cpp (added)
+++ llvm/trunk/unittests/Demangle/PartialDemangleTest.cpp Thu Apr 12 13:41:38 2018
@@ -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!"));
+
+}
More information about the llvm-commits
mailing list