[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