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 ®ex,
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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits