sgraenitz updated this revision to Diff 158044.
sgraenitz added a comment.

Moved forward decls


https://reviews.llvm.org/D49990

Files:
  include/lldb/Core/Mangled.h
  include/lldb/Symbol/Symtab.h
  include/lldb/Utility/ConstString.h
  include/lldb/lldb-forward.h
  source/Core/Mangled.cpp
  source/Symbol/Symtab.cpp
  unittests/Core/CMakeLists.txt
  unittests/Core/Inputs/mangled-function-names.yaml
  unittests/Core/MangledTest.cpp

Index: unittests/Core/MangledTest.cpp
===================================================================
--- unittests/Core/MangledTest.cpp
+++ unittests/Core/MangledTest.cpp
@@ -7,9 +7,21 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "gtest/gtest.h"
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "TestingSupport/TestUtilities.h"
 
 #include "lldb/Core/Mangled.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+
+#include "gtest/gtest.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -36,3 +48,123 @@
 
   EXPECT_STREQ("", TheDemangled.GetCString());
 }
+
+#define ASSERT_NO_ERROR(x)                                                     \
+  if (std::error_code ASSERT_NO_ERROR_ec = x) {                                \
+    llvm::SmallString<128> MessageStorage;                                     \
+    llvm::raw_svector_ostream Message(MessageStorage);                         \
+    Message << #x ": did not return errc::success.\n"                          \
+            << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n"          \
+            << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n";      \
+    GTEST_FATAL_FAILURE_(MessageStorage.c_str());                              \
+  } else {                                                                     \
+  }
+
+TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
+  HostInfo::Initialize();
+  ObjectFileELF::Initialize();
+  SymbolVendorELF::Initialize();
+
+  std::string Yaml = GetInputFilePath("mangled-function-names.yaml");
+  llvm::SmallString<128> Obj;
+  ASSERT_NO_ERROR(llvm::sys::fs::createTemporaryFile(
+      "mangled-function-names-%%%%%%", "obj", Obj));
+
+  llvm::FileRemover Deleter(Obj);
+  llvm::StringRef Args[] = {YAML2OBJ, Yaml};
+  llvm::StringRef ObjRef = Obj;
+  const llvm::Optional<llvm::StringRef> redirects[] = {llvm::None, ObjRef,
+                                                       llvm::None};
+  ASSERT_EQ(0,
+            llvm::sys::ExecuteAndWait(YAML2OBJ, Args, llvm::None, redirects));
+  uint64_t Size;
+  ASSERT_NO_ERROR(llvm::sys::fs::file_size(Obj, Size));
+  ASSERT_GT(Size, 0u);
+
+  ModuleSpec Spec{FileSpec(Obj, false)};
+  Spec.GetSymbolFileSpec().SetFile(Obj, false, FileSpec::Style::native);
+  auto M = std::make_shared<Module>(Spec);
+
+  auto Count = [M](const char *Name, FunctionNameType Type) -> int {
+    SymbolContextList SymList;
+    return M->FindFunctionSymbols(ConstString(Name), Type, SymList);
+  };
+
+  // Unmangled
+  EXPECT_EQ(1, Count("main", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("main", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("main", eFunctionNameTypeMethod));
+
+  // Itanium mangled
+  EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("foo", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("foo", eFunctionNameTypeMethod));
+
+  // Unmangled with linker annotation
+  EXPECT_EQ(1, Count("puts@GLIBC_2.5", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("puts@GLIBC_2.6", eFunctionNameTypeFull));
+  EXPECT_EQ(2, Count("puts", eFunctionNameTypeFull));
+  EXPECT_EQ(2, Count("puts", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("puts", eFunctionNameTypeMethod));
+
+  // Itanium mangled with linker annotation
+  EXPECT_EQ(1, Count("_Z5annotv@VERSION3", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("annot", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("annot", eFunctionNameTypeMethod));
+
+  // Itanium mangled ctor A::A()
+  EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("A", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("A", eFunctionNameTypeBase));
+
+  // Itanium mangled dtor A::~A()
+  EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("~A", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("~A", eFunctionNameTypeBase));
+
+  // Itanium mangled method A::bar()
+  EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("bar", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("bar", eFunctionNameTypeBase));
+
+  // Itanium mangled names that are explicitly excluded from parsing
+  EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("Decl", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("Decl", eFunctionNameTypeBase));
+
+  // ObjC mangled static
+  EXPECT_EQ(1, Count("-[objCfoo]", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("-[objCfoo]", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("objCfoo", eFunctionNameTypeMethod));
+
+  // ObjC mangled method with category
+  EXPECT_EQ(1, Count("+[B objCbar(WithCategory)]", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("+[B objCbar(WithCategory)]", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("objCbar", eFunctionNameTypeMethod));
+
+  // Invalid things: unable to decode but still possible to find by full name
+  EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("_Z12undemangableEvx42", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
+
+  SymbolVendorELF::Terminate();
+  ObjectFileELF::Terminate();
+  HostInfo::Terminate();
+}
Index: unittests/Core/Inputs/mangled-function-names.yaml
===================================================================
--- /dev/null
+++ unittests/Core/Inputs/mangled-function-names.yaml
@@ -0,0 +1,116 @@
+--- !ELF
+FileHeader:      
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+Sections:        
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         554889E58B0425A80000005DC30F1F00
+  - Name:            .anothertext
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x0000000000000010
+    AddressAlign:    0x0000000000000010
+    Content:         554889E54883EC20488D0425A8000000C745FC00000000488945F0488B45F08B08894DECE8C7FFFFFF8B4DEC01C189C84883C4205D746573742073747200C3
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0000000000000050
+    AddressAlign:    0x0000000000000008
+    Content:         1400000000000000017A5200017810011B0C0708900100001C0000001C00000090FFFFFF0D00000000410E108602430D06000000000000001C0000003C00000080FFFFFF3F00000000410E108602430D0600000000000000
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0x00000000000000A8
+    AddressAlign:    0x0000000000000004
+    Content:         '01000000'
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0000000000000001
+    Content:         5562756E747520636C616E672076657273696F6E20332E352D317562756E74753120287472756E6B2920286261736564206F6E204C4C564D20332E352900
+Symbols:         
+  Local:           
+    - Type:            STT_SECTION
+      Section:         .text
+    - Type:            STT_SECTION
+      Section:         .anothertext
+      Value:           0x0000000000000010
+    - Type:            STT_SECTION
+      Section:         .eh_frame
+      Value:           0x0000000000000050
+    - Type:            STT_SECTION
+      Section:         .data
+      Value:           0x00000000000000A8
+    - Type:            STT_SECTION
+      Section:         .comment
+    - Name:            /tmp/a.c
+      Type:            STT_FILE
+    - Type:            STT_FILE
+  Global:          
+    - Name:            somedata
+      Type:            STT_OBJECT
+      Section:         .anothertext
+      Value:           0x0000000000000045
+    - Name:            main
+      Type:            STT_FUNC
+      Section:         .anothertext
+      Value:           0x0000000000000010
+      Size:            0x000000000000003F
+    - Name:            _Z3foov
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            puts@GLIBC_2.5
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            puts@GLIBC_2.6
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            _Z5annotv@VERSION3
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            _ZN1AC2Ev
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            _ZN1AD2Ev
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            _ZN1A3barEv
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            _ZGVZN4llvm4dbgsEvE7thestrm
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            _ZZN4llvm4dbgsEvE7thestrm
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            _ZTVN5clang4DeclE
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            -[objCfoo]
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            +[B objCbar(WithCategory)]
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            _Z12undemangableEvx42
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+...
Index: unittests/Core/CMakeLists.txt
===================================================================
--- unittests/Core/CMakeLists.txt
+++ unittests/Core/CMakeLists.txt
@@ -11,7 +11,19 @@
   LINK_LIBS
     lldbCore
     lldbHost
+    lldbSymbol
+    lldbPluginObjectFileELF
+    lldbPluginSymbolVendorELF
+    lldbUtilityHelpers
     LLVMTestingSupport
   LINK_COMPONENTS
     Support
   )
+
+add_dependencies(LLDBCoreTests yaml2obj)
+add_definitions(-DYAML2OBJ="$<TARGET_FILE:yaml2obj>")
+
+set(test_inputs
+  mangled-function-names.yaml
+  )
+add_unittest_inputs(LLDBCoreTests "${test_inputs}")
Index: source/Symbol/Symtab.cpp
===================================================================
--- source/Symbol/Symtab.cpp
+++ source/Symbol/Symtab.cpp
@@ -22,6 +22,7 @@
 #include "lldb/Utility/RegularExpression.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/Timer.h"
+#include "llvm/Demangle/Demangle.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -212,9 +213,118 @@
   return nullptr;
 }
 
+//----------------------------------------------------------------------
+// RichManglingInfo
+//----------------------------------------------------------------------
+
+void RichManglingInfo::ResetProvider() {
+  // If we want to support parsers for other languages some day, we need a
+  // switch here to delete the correct parser type.
+  if (m_legacy_parser) {
+    assert(m_provider == RichManglingInfo::PluginCxxLanguage);
+    delete get<CPlusPlusLanguage::MethodName>();
+    m_legacy_parser = nullptr;
+  }
+}
+
+RichManglingInfo *RichManglingSpec::CreateItaniumInfo() {
+  m_info.ResetProvider();
+  m_info.m_provider = RichManglingInfo::ItaniumPartialDemangler;
+  m_info.m_IPD = &m_IPD;
+  return &m_info;
+}
+
+RichManglingInfo *
+RichManglingSpec::CreateLegacyCxxParserInfo(const ConstString &mangled) {
+  m_info.ResetProvider();
+  m_info.m_provider = RichManglingInfo::PluginCxxLanguage;
+  m_info.m_legacy_parser = new CPlusPlusLanguage::MethodName(mangled);
+  return &m_info;
+}
+
+RichManglingInfo::~RichManglingInfo() { 
+  ResetProvider();
+  delete m_IPD_buf;
+}
+
+bool RichManglingInfo::isCtorOrDtor() const {
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    return m_IPD->isCtorOrDtor();
+  case PluginCxxLanguage: {
+    // We can only check for destructors here.
+    auto base_name = get<CPlusPlusLanguage::MethodName>()->GetBasename();
+    return base_name.front() == '~';
+  }
+  }
+}
+
+bool RichManglingInfo::isFunction() const {
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    return m_IPD->isFunction();
+  case PluginCxxLanguage:
+    return get<CPlusPlusLanguage::MethodName>()->IsValid();
+  }
+}
+
+const char *RichManglingInfo::getFunctionBaseName() const {
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    m_IPD_buf = m_IPD->getFunctionBaseName(m_IPD_buf, &m_IPD_size);
+    return m_IPD_buf;
+  case PluginCxxLanguage:
+    return get<CPlusPlusLanguage::MethodName>()->GetBasename().data();
+  }
+}
+
+const char *RichManglingInfo::getFunctionDeclContextName() const {
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    m_IPD_buf = m_IPD->getFunctionDeclContextName(m_IPD_buf, &m_IPD_size);
+    return m_IPD_buf;
+  case PluginCxxLanguage:
+    return get<CPlusPlusLanguage::MethodName>()->GetContext().data();
+  }
+}
+
 //----------------------------------------------------------------------
 // InitNameIndexes
 //----------------------------------------------------------------------
+namespace {
+bool lldb_skip_name(llvm::StringRef mangled, Mangled::ManglingScheme scheme) {
+  switch (scheme) {
+  case Mangled::eManglingSchemeItanium: {
+    if (mangled.size() < 3 || !mangled.startswith("_Z"))
+      return true;
+
+    // Avoid the following types of symbols in the index.
+    switch (mangled[2]) {
+    case 'G': // guard variables
+    case 'T': // virtual tables, VTT structures, typeinfo structures + names
+    case 'Z': // named local entities (if we eventually handle
+              // eSymbolTypeData, we will want this back)
+      return true;
+
+    default:
+      break;
+    }
+
+    // Include this name in the index.
+    return false;
+  }
+
+  // No filters for this scheme yet. Include all names in indexing.
+  case Mangled::eManglingSchemeMSVC:
+    return false;
+
+  // Don't try and demangle things we can't categorize.
+  case Mangled::eManglingSchemeNone:
+    return true;
+  }
+}
+} // namespace
+
 void Symtab::InitNameIndexes() {
   // Protected function, no need to lock mutex...
   if (!m_name_indexes_computed) {
@@ -243,25 +353,30 @@
     m_name_to_index.Reserve(actual_count);
 #endif
 
-    NameToIndexMap::Entry entry;
-
     // The "const char *" in "class_contexts" must come from a
     // ConstString::GetCString()
     std::set<const char *> class_contexts;
     UniqueCStringMap<uint32_t> mangled_name_to_index;
     std::vector<const char *> symbol_contexts(num_symbols, nullptr);
 
+    // Instantiation of the demangler is expensive, so better use a single one
+    // for all entries during batch processing.
+    RichManglingSpec spec;
+    NameToIndexMap::Entry entry;
+
     for (entry.value = 0; entry.value < num_symbols; ++entry.value) {
-      const Symbol *symbol = &m_symbols[entry.value];
+      Symbol *symbol = &m_symbols[entry.value];
 
       // Don't let trampolines get into the lookup by name map If we ever need
       // the trampoline symbols to be searchable by name we can remove this and
       // then possibly add a new bool to any of the Symtab functions that
       // lookup symbols by name to indicate if they want trampolines.
       if (symbol->IsTrampoline())
         continue;
 
-      const Mangled &mangled = symbol->GetMangled();
+      // If the symbol's name string matched a Mangled::ManglingScheme, it is
+      // stored in the mangled field.
+      Mangled &mangled = symbol->GetMangled();
       entry.cstring = mangled.GetMangledName();
       if (entry.cstring) {
         m_name_to_index.Append(entry);
@@ -274,70 +389,18 @@
           m_name_to_index.Append(entry);
         }
 
-        const SymbolType symbol_type = symbol->GetType();
-        if (symbol_type == eSymbolTypeCode ||
-            symbol_type == eSymbolTypeResolver) {
-          llvm::StringRef entry_ref(entry.cstring.GetStringRef());
-          if (entry_ref[0] == '_' && entry_ref[1] == 'Z' &&
-              (entry_ref[2] != 'T' && // avoid virtual table, VTT structure,
-                                      // typeinfo structure, and typeinfo
-                                      // name
-               entry_ref[2] != 'G' && // avoid guard variables
-               entry_ref[2] != 'Z'))  // named local entities (if we
-                                          // eventually handle eSymbolTypeData,
-                                          // we will want this back)
-          {
-            CPlusPlusLanguage::MethodName cxx_method(
-                mangled.GetDemangledName(lldb::eLanguageTypeC_plus_plus));
-            entry.cstring = ConstString(cxx_method.GetBasename());
-            if (entry.cstring) {
-              // ConstString objects permanently store the string in the pool
-              // so calling GetCString() on the value gets us a const char *
-              // that will never go away
-              const char *const_context =
-                  ConstString(cxx_method.GetContext()).GetCString();
-
-              if (!const_context || const_context[0] == 0) {
-                // No context for this function so this has to be a basename
-                m_basename_to_index.Append(entry);
-                // If there is no context (no namespaces or class scopes that
-                // come before the function name) then this also could be a
-                // fullname.
-                m_name_to_index.Append(entry);
-              } else {
-                entry_ref = entry.cstring.GetStringRef();
-                if (entry_ref[0] == '~' ||
-                    !cxx_method.GetQualifiers().empty()) {
-                  // The first character of the demangled basename is '~' which
-                  // means we have a class destructor. We can use this
-                  // information to help us know what is a class and what
-                  // isn't.
-                  if (class_contexts.find(const_context) == class_contexts.end())
-                    class_contexts.insert(const_context);
-                  m_method_to_index.Append(entry);
-                } else {
-                  if (class_contexts.find(const_context) !=
-                      class_contexts.end()) {
-                    // The current decl context is in our "class_contexts"
-                    // which means this is a method on a class
-                    m_method_to_index.Append(entry);
-                  } else {
-                    // We don't know if this is a function basename or a
-                    // method, so put it into a temporary collection so once we
-                    // are done we can look in class_contexts to see if each
-                    // entry is a class or just a function and will put any
-                    // remaining items into m_method_to_index or
-                    // m_basename_to_index as needed
-                    mangled_name_to_index.Append(entry);
-                    symbol_contexts[entry.value] = const_context;
-                  }
-                }
-              }
-            }
-          }
+        const SymbolType type = symbol->GetType();
+        if (type == eSymbolTypeCode || type == eSymbolTypeResolver) {
+          if (const RichManglingInfo *info =
+                  mangled.DemangleWithRichManglingInfo(spec, lldb_skip_name))
+            RegisterMangledNameEntry(entry, class_contexts,
+                                     mangled_name_to_index, symbol_contexts,
+                                     *info);
         }
       }
 
+      // Symbol name strings that didn't match a Mangled::ManglingScheme, are
+      // stored in the demangled field.
       entry.cstring = mangled.GetDemangledName(symbol->GetLanguage());
       if (entry.cstring) {
         m_name_to_index.Append(entry);
@@ -379,7 +442,7 @@
             m_method_to_index.Append(entry);
           } else {
             // If we got here, we have something that had a context (was inside
-            // a namespace or class) yet we don't know if the entry
+            // a namespace or class) yet we don't know the entry
             m_method_to_index.Append(entry);
             m_basename_to_index.Append(entry);
           }
@@ -397,6 +460,53 @@
   }
 }
 
+void Symtab::RegisterMangledNameEntry(
+    NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+    UniqueCStringMap<uint32_t> &mangled_name_to_index,
+    std::vector<const char *> &symbol_contexts, const RichManglingInfo &info) {
+  // Only register functions that have a base name.
+  const char *base_name_cstr = info.getFunctionBaseName();
+  if (base_name_cstr == nullptr)
+    return;
+
+  // The base name will be our entry's name.
+  entry.cstring = ConstString(base_name_cstr);
+
+  // Register functions with no context.
+  ConstString decl_context(info.getFunctionDeclContextName());
+  if (decl_context.IsEmpty()) {
+    // This has to be a basename
+    m_basename_to_index.Append(entry);
+    // If there is no context (no namespaces or class scopes that come before
+    // the function name) then this also could be a fullname.
+    m_name_to_index.Append(entry);
+    return;
+  }
+
+  // See if we already know this context.
+  auto it = class_contexts.find(decl_context.GetCString());
+
+  // Register constructors and destructors. They are methods and create
+  // declaration contexts.
+  if (info.isCtorOrDtor()) {
+    m_method_to_index.Append(entry);
+    if (it == class_contexts.end())
+      class_contexts.insert(it, decl_context.GetCString());
+    return;
+  }
+
+  // Register regular methods with a known declaration context.
+  if (it != class_contexts.end()) {
+    m_method_to_index.Append(entry);
+    return;
+  }
+
+  // Regular methods in unknown declaration contexts are put to the backlog. We
+  // will revisit them once we processed all remaining symbols.
+  mangled_name_to_index.Append(entry);
+  symbol_contexts[entry.value] = decl_context.GetCString();
+}
+
 void Symtab::PreloadSymbols() {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   InitNameIndexes();
Index: source/Core/Mangled.cpp
===================================================================
--- source/Core/Mangled.cpp
+++ source/Core/Mangled.cpp
@@ -195,7 +195,7 @@
 int Mangled::Compare(const Mangled &a, const Mangled &b) {
   return ConstString::Compare(
       a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled),
-      a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled));
+      b.GetName(lldb::eLanguageTypeUnknown, ePreferMangled));
 }
 
 //----------------------------------------------------------------------
@@ -232,6 +232,127 @@
   }
 }
 
+//----------------------------------------------------------------------
+// Local helpers for different demangling implementations.
+//----------------------------------------------------------------------
+namespace {
+
+char *GetMSVCDemangledCStr(const char *M) {
+#if defined(_MSC_VER)
+  const size_t demangled_length = 2048;
+  char *demangled_cstr = static_cast<char *>(::malloc(demangled_length));
+  ::ZeroMemory(demangled_cstr, demangled_length);
+  DWORD result = safeUndecorateName(M, demangled_cstr, demangled_length);
+
+  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+    if (demangled_cstr && demangled_cstr[0])
+      log->Printf("demangled msvc: %s -> \"%s\"", M, demangled_cstr);
+    else
+      log->Printf("demangled msvc: %s -> error: 0x%lu", M, result);
+  }
+
+  if (result != 0) {
+    return demangled_cstr;
+  } else {
+    ::free(demangled_cstr);
+    return nullptr;
+  }
+#else
+  return nullptr;
+#endif
+}
+
+char *GetItaniumRichDemangleInfo(const char *M,
+                                 llvm::ItaniumPartialDemangler &IPD) {
+  char *demangled_cstr = nullptr;
+  bool err = IPD.partialDemangle(M);
+  if (!err) {
+    // Default buffer and size (will realloc in case it's too small).
+    size_t demangled_size = 80;
+    demangled_cstr = static_cast<char *>(std::malloc(demangled_size));
+    demangled_cstr = IPD.finishDemangle(demangled_cstr, &demangled_size);
+  }
+
+  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+    if (demangled_cstr)
+      log->Printf("demangled itanium: %s -> \"%s\"", M, demangled_cstr);
+    else
+      log->Printf("demangled itanium: %s -> error: failed to demangle", M);
+  }
+
+  return demangled_cstr;
+}
+} // namespace
+
+//----------------------------------------------------------------------
+// Explicit demangling for scheduled requests during batch processing. This
+// makes use of ItaniumPartialDemangler's rich demangle info
+//----------------------------------------------------------------------
+const RichManglingInfo *
+Mangled::DemangleWithRichManglingInfo(RichManglingSpec &spec,
+                                      SkipMangledNameFn *skip_mangled_name) {
+  // We need to generate and cache the demangled name.
+  static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+  Timer scoped_timer(func_cat,
+                     "Mangled::DemangleWithRichNameIndexInfo (m_mangled = %s)",
+                     m_mangled.GetCString());
+
+  // Others are not meant to arrive here. ObjC names or C's main() for example
+  // have their names stored in m_demangled, while m_mangled is empty.
+  assert(m_mangled);
+
+  // Check whether or not we are interested in this name at all.
+  llvm::StringRef M = m_mangled.GetStringRef();
+  ManglingScheme S = cstring_mangling_scheme(M.data());
+  if (skip_mangled_name && skip_mangled_name(M, S))
+    return nullptr;
+
+  switch (S) {
+  case eManglingSchemeNone:
+    // The current mangled_name_filter would allow llvm_unreachable here.
+    return nullptr;
+
+  case eManglingSchemeItanium:
+    // We want the rich mangling info here, so we don't care whether or not
+    // there is a demangled string in the pool already.
+    if (char *D = GetItaniumRichDemangleInfo(M.data(), spec.GetIPD())) {
+      // Connect the counterparts in the string pool to accelerate subsequent
+      // access in GetDemangledName().
+      m_demangled.SetCStringWithMangledCounterpart(D, m_mangled);
+      std::free(D);
+
+      return spec.CreateItaniumInfo();
+    } else {
+      m_demangled.SetCString("");
+      return nullptr;
+    }
+
+  case eManglingSchemeMSVC: {
+    // We have no rich mangling for MSVC-mangled names yet, so first try to
+    // demangle it if necessary.
+    if (!m_demangled && !m_mangled.GetMangledCounterpart(m_demangled)) {
+      if (char *D = GetMSVCDemangledCStr(M.data())) {
+        // Connect the counterparts in the string pool to accelerate
+        // subsequent access in GetDemangledName().
+        m_demangled.SetCStringWithMangledCounterpart(D, m_mangled);
+        ::free(D);
+      } else {
+        m_demangled.SetCString("");
+      }
+    }
+
+    if (m_demangled.IsEmpty()) {
+      // Cannot demangle it, so don't try parsing.
+      return nullptr;
+    } else {
+      // Demangled successfully, we can try and parse it with
+      // CPlusPlusLanguage::MethodName.
+      return spec.CreateLegacyCxxParserInfo(m_mangled);
+    }
+  }
+  }
+}
+
 //----------------------------------------------------------------------
 // Generate the demangled name on demand using this accessor. Code in this
 // class will need to use this accessor if it wishes to decode the demangled
@@ -242,14 +363,12 @@
 Mangled::GetDemangledName(lldb::LanguageType language) const {
   // Check to make sure we have a valid mangled name and that we haven't
   // already decoded our mangled name.
-  if (m_mangled && !m_demangled) {
+  if (m_mangled && m_demangled.IsNull()) {
     // We need to generate and cache the demangled name.
     static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
     Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)",
                        m_mangled.GetCString());
 
-    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE);
-
     // Don't bother running anything that isn't mangled
     const char *mangled_name = m_mangled.GetCString();
     ManglingScheme mangling_scheme{cstring_mangling_scheme(mangled_name)};
@@ -259,60 +378,23 @@
       // add it to our map.
       char *demangled_name = nullptr;
       switch (mangling_scheme) {
-      case eManglingSchemeMSVC: {
-#if defined(_MSC_VER)
-        if (log)
-          log->Printf("demangle msvc: %s", mangled_name);
-        const size_t demangled_length = 2048;
-        demangled_name = static_cast<char *>(::malloc(demangled_length));
-        ::ZeroMemory(demangled_name, demangled_length);
-        DWORD result =
-            safeUndecorateName(mangled_name, demangled_name, demangled_length);
-        if (log) {
-          if (demangled_name && demangled_name[0])
-            log->Printf("demangled msvc: %s -> \"%s\"", mangled_name,
-                        demangled_name);
-          else
-            log->Printf("demangled msvc: %s -> error: 0x%lu", mangled_name,
-                        result);
-        }
-
-        if (result == 0) {
-          free(demangled_name);
-          demangled_name = nullptr;
-        }
-#endif
+      case eManglingSchemeMSVC:
+        demangled_name = GetMSVCDemangledCStr(mangled_name);
         break;
-      }
       case eManglingSchemeItanium: {
         llvm::ItaniumPartialDemangler IPD;
-        bool demangle_err = IPD.partialDemangle(mangled_name);
-        if (!demangle_err) {
-          // Default buffer and size (realloc is used in case it's too small).
-          size_t demangled_size = 80;
-          demangled_name = static_cast<char *>(::malloc(demangled_size));
-          demangled_name = IPD.finishDemangle(demangled_name, &demangled_size);
-        }
-
-        if (log) {
-          if (demangled_name)
-            log->Printf("demangled itanium: %s -> \"%s\"", mangled_name,
-                        demangled_name);
-          else
-            log->Printf("demangled itanium: %s -> error: failed to demangle",
-                        mangled_name);
-        }
+        demangled_name = GetItaniumRichDemangleInfo(mangled_name, IPD);
         break;
       }
       case eManglingSchemeNone:
-        break;
+        llvm_unreachable("eManglingSchemeNone was handled already");
       }
       if (demangled_name) {
         m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled);
         free(demangled_name);
       }
     }
-    if (!m_demangled) {
+    if (m_demangled.IsNull()) {
       // Set the demangled string to the empty string to indicate we tried to
       // parse it once and failed.
       m_demangled.SetCString("");
Index: include/lldb/lldb-forward.h
===================================================================
--- include/lldb/lldb-forward.h
+++ include/lldb/lldb-forward.h
@@ -191,6 +191,8 @@
 class RegisterValue;
 class RegularExpression;
 class REPL;
+class RichManglingInfo;
+class RichManglingSpec;
 class Scalar;
 class ScriptInterpreter;
 class ScriptInterpreterLocker;
@@ -492,5 +494,14 @@
 
 } // namespace lldb
 
+//----------------------------------------------------------------------
+// llvm forward declarations
+//----------------------------------------------------------------------
+namespace llvm {
+
+struct ItaniumPartialDemangler;
+
+} // namespace llvm
+
 #endif // #if defined(__cplusplus)
 #endif // LLDB_lldb_forward_h_
Index: include/lldb/Utility/ConstString.h
===================================================================
--- include/lldb/Utility/ConstString.h
+++ include/lldb/Utility/ConstString.h
@@ -345,6 +345,15 @@
   //------------------------------------------------------------------
   bool IsEmpty() const { return m_string == nullptr || m_string[0] == '\0'; }
 
+  //------------------------------------------------------------------
+  /// Test for null string.
+  ///
+  /// @return
+  ///     @li \b true if there is no string associated with this instance.
+  ///     @li \b false if there is a string associated with this instance.
+  //------------------------------------------------------------------
+  bool IsNull() const { return m_string == nullptr; }
+
   //------------------------------------------------------------------
   /// Set the C string value.
   ///
Index: include/lldb/Symbol/Symtab.h
===================================================================
--- include/lldb/Symbol/Symtab.h
+++ include/lldb/Symbol/Symtab.h
@@ -17,9 +17,93 @@
 #include "lldb/Core/UniqueCStringMap.h"
 #include "lldb/Symbol/Symbol.h"
 #include "lldb/lldb-private.h"
+#include "llvm/Demangle/Demangle.h"
 
 namespace lldb_private {
 
+/// Uniform wrapper for access to rich mangling information from different
+/// providers. See Mangled::DemangleWithRichManglingInfo()
+class RichManglingInfo {
+public:
+  /// If this symbol describes a constructor or destructor.
+  bool isCtorOrDtor() const;
+
+  /// If this symbol describes a function.
+  bool isFunction() const;
+
+  /// Get the base name of a function. This doesn't include trailing template
+  /// arguments, ie for "a::b<int>" this function returns "b".
+  const char *getFunctionBaseName() const;
+
+  /// Get the context name for a function. For "a::b::c", this function returns
+  /// "a::b".
+  const char *getFunctionDeclContextName() const;
+
+private:
+  enum InfoProvider { ItaniumPartialDemangler, PluginCxxLanguage };
+
+  /// Selects the rich mangling info provider. Initially undefined, but
+  /// initialized in RichManglingSpec::CreateX (instance not accessible before).
+  InfoProvider m_provider;
+
+  /// Members for ItaniumPartialDemangler
+  llvm::ItaniumPartialDemangler *m_IPD = nullptr;
+  mutable size_t m_IPD_size = 0;
+  mutable char *m_IPD_buf = nullptr;
+
+  /// Members for PluginCxxLanguage
+  /// Cannot forward declare inner class CPlusPlusLanguage::MethodName. The
+  /// respective header is in Plugins and including it from here causes cyclic
+  /// dependency. Keep a void* here instead and cast it on-demand on the cpp.
+  void *m_legacy_parser = nullptr;
+
+  /// Obtain the legacy parser casted to the given type. Ideally we had a type
+  /// trait to deduce \a ParserT from a given InfoProvider, but unfortunately we
+  /// can't access CPlusPlusLanguage::MethodName from within the header.
+  template <class ParserT> ParserT *get() const {
+    assert(m_legacy_parser);
+    return reinterpret_cast<ParserT *>(m_legacy_parser);
+  }
+
+  /// Reset the provider and clean up memory before reassigning/destroying.
+  void ResetProvider();
+
+  // Default construction in undefined state from RichManglingSpec.
+  RichManglingInfo() = default;
+
+  // Destruction from RichManglingSpec.
+  ~RichManglingInfo();
+
+  // No copy
+  RichManglingInfo(const RichManglingInfo &) = delete;
+  RichManglingInfo &operator=(const RichManglingInfo &) = delete;
+
+  // No move
+  RichManglingInfo(RichManglingInfo &&) = delete;
+  RichManglingInfo &operator=(RichManglingInfo &&) = delete;
+
+  // Declare RichManglingSpec as friend so it can access the default ctor and
+  // assign to members in its CreateX methods.
+  friend class RichManglingSpec;
+};
+
+//----------------------------------------------------------------------
+
+/// Unique owner of RichManglingInfo. Handles initialization and lifetime.
+class RichManglingSpec {
+public:
+  RichManglingInfo *CreateItaniumInfo();
+  RichManglingInfo *CreateLegacyCxxParserInfo(const ConstString &mangled);
+
+  llvm::ItaniumPartialDemangler &GetIPD() { return m_IPD; }
+
+private:
+  RichManglingInfo m_info;
+  llvm::ItaniumPartialDemangler m_IPD;
+};
+
+//----------------------------------------------------------------------
+
 class Symtab {
 public:
   typedef std::vector<uint32_t> IndexCollection;
@@ -197,6 +281,11 @@
   void SymbolIndicesToSymbolContextList(std::vector<uint32_t> &symbol_indexes,
                                         SymbolContextList &sc_list);
 
+  void RegisterMangledNameEntry(
+      NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+      UniqueCStringMap<uint32_t> &mangled_name_to_index,
+      std::vector<const char *> &symbol_contexts, const RichManglingInfo &info);
+
   DISALLOW_COPY_AND_ASSIGN(Symtab);
 };
 
Index: include/lldb/Core/Mangled.h
===================================================================
--- include/lldb/Core/Mangled.h
+++ include/lldb/Core/Mangled.h
@@ -12,17 +12,11 @@
 #if defined(__cplusplus)
 
 #include "lldb/Utility/ConstString.h"
-#include "lldb/lldb-enumerations.h" // for LanguageType
-#include "llvm/ADT/StringRef.h"     // for StringRef
+#include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/StringRef.h"
 
-#include <stddef.h> // for size_t
-
-namespace lldb_private {
-class RegularExpression;
-}
-namespace lldb_private {
-class Stream;
-}
+#include <memory>
+#include <stddef.h>
 
 namespace lldb_private {
 
@@ -238,7 +232,6 @@
       return true;
     return GetDemangledName(language) == name;
   }
-
   bool NameMatches(const RegularExpression &regex,
                    lldb::LanguageType language) const;
 
@@ -300,6 +293,35 @@
   //----------------------------------------------------------------------
   lldb::LanguageType GuessLanguage() const;
 
+  /// Function signature for filtering mangled names.
+  using SkipMangledNameFn = bool(llvm::StringRef, ManglingScheme);
+
+  //----------------------------------------------------------------------
+  /// Trigger explicit demangling to obtain rich mangling information. This is
+  /// optimized for batch processing while populating a name index. To get the
+  /// pure demangled name string for a single entity, use GetDemangledName()
+  /// instead.
+  ///
+  /// For names that match the Itanium mangling scheme, this uses LLVM's
+  /// ItaniumPartialDemangler. All other names fall back to LLDB's builtin
+  /// parser currently.
+  ///
+  /// @param[in] spec
+  ///     The RichManglingSpec that provides the context for this function. One
+  ///     instance can be used for multiple calls. Should be stack-allocated in
+  ///     the caller's frame.
+  ///
+  /// @param[in] skip_mangled_name
+  ///     A filtering function for skipping entities based on name and mangling
+  ///     scheme. This can be null if unused.
+  ///
+  /// @return
+  ///     The rich mangling info on success, null otherwise.
+  //----------------------------------------------------------------------
+  const RichManglingInfo *
+  DemangleWithRichManglingInfo(RichManglingSpec &spec,
+                               SkipMangledNameFn *skip_mangled_name);
+
 private:
   //----------------------------------------------------------------------
   /// Mangled member variables.
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to