diff options
Diffstat (limited to 'lldb')
-rw-r--r-- | lldb/include/lldb/Breakpoint/BreakpointResolverName.h | 26 | ||||
-rw-r--r-- | lldb/include/lldb/Core/Module.h | 50 | ||||
-rw-r--r-- | lldb/include/lldb/Symbol/SymbolContext.h | 13 | ||||
-rw-r--r-- | lldb/include/lldb/Symbol/Symtab.h | 2 | ||||
-rw-r--r-- | lldb/include/lldb/Target/CPPLanguageRuntime.h | 87 | ||||
-rw-r--r-- | lldb/source/Breakpoint/BreakpointResolverName.cpp | 154 | ||||
-rw-r--r-- | lldb/source/Core/Module.cpp | 164 | ||||
-rw-r--r-- | lldb/source/Core/ModuleList.cpp | 62 | ||||
-rw-r--r-- | lldb/source/Expression/ClangExpressionDeclMap.cpp | 2 | ||||
-rw-r--r-- | lldb/source/Interpreter/CommandObjectRegexCommand.cpp | 4 | ||||
-rw-r--r-- | lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 263 | ||||
-rw-r--r-- | lldb/source/Symbol/SymbolContext.cpp | 11 | ||||
-rw-r--r-- | lldb/source/Symbol/Symtab.cpp | 172 | ||||
-rw-r--r-- | lldb/source/Target/CPPLanguageRuntime.cpp | 211 |
14 files changed, 952 insertions, 269 deletions
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h index 8a76233b47b..f481aa9c533 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h @@ -86,13 +86,33 @@ public: } protected: - std::vector<ConstString> m_func_names; - uint32_t m_func_name_type_mask; // See FunctionNameType - ConstString m_class_name; // FIXME: Not used yet. The idea would be to stop on methods of this class. + struct LookupInfo + { + ConstString name; + ConstString lookup_name; + uint32_t name_type_mask; // See FunctionNameType + bool match_name_after_lookup; + + LookupInfo () : + name(), + lookup_name(), + name_type_mask (0), + match_name_after_lookup (false) + { + } + + void + Prune (SymbolContextList &sc_list, + size_t start_idx) const; + }; + std::vector<LookupInfo> m_lookups; + ConstString m_class_name; RegularExpression m_regex; Breakpoint::MatchType m_match_type; bool m_skip_prologue; + void + AddNameLookup (const ConstString &name, uint32_t name_type_mask); private: DISALLOW_COPY_AND_ASSIGN(BreakpointResolverName); }; diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 3f98e815bb1..3759b28a3f0 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -882,6 +882,56 @@ public: bool RemapSourceFile (const char *path, std::string &new_path) const; + + //------------------------------------------------------------------ + /// Prepare to do a function name lookup. + /// + /// Looking up functions by name can be a tricky thing. LLDB requires + /// that accelerator tables contain full names for functions as well + /// as function basenames which include functions, class methods and + /// class functions. When the user requests that an action use a + /// function by name, we are sometimes asked to automatically figure + /// out what a name could possibly map to. A user might request a + /// breakpoint be set on "count". If no options are supplied to limit + /// the scope of where to search for count, we will by default match + /// any function names named "count", all class and instance methods + /// named "count" (no matter what the namespace or contained context) + /// and any selectors named "count". If a user specifies "a::b" we + /// will search for the basename "b", and then prune the results that + /// don't match "a::b" (note that "c::a::b" and "d::e::a::b" will + /// match a query of "a::b". + /// + /// @param[in] name + /// The user supplied name to use in the lookup + /// + /// @param[in] name_type_mask + /// The mask of bits from lldb::FunctionNameType enumerations + /// that tell us what kind of name we are looking for. + /// + /// @param[out] lookup_name + /// The actual name that will be used when calling + /// SymbolVendor::FindFunctions() or Symtab::FindFunctionSymbols() + /// + /// @param[out] lookup_name_type_mask + /// The actual name mask that should be used in the calls to + /// SymbolVendor::FindFunctions() or Symtab::FindFunctionSymbols() + /// + /// @param[out] match_name_after_lookup + /// A boolean that indicates if we need to iterate through any + /// match results obtained from SymbolVendor::FindFunctions() or + /// Symtab::FindFunctionSymbols() to see if the name contains + /// \a name. For example if \a name is "a::b", this function will + /// return a \a lookup_name of "b", with \a match_name_after_lookup + /// set to true to indicate any matches will need to be checked + /// to make sure they contain \a name. + //------------------------------------------------------------------ + static void + PrepareForFunctionNameLookup (const ConstString &name, + uint32_t name_type_mask, + ConstString &lookup_name, + uint32_t &lookup_name_type_mask, + bool &match_name_after_lookup); + protected: //------------------------------------------------------------------ // Member Variables diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h index 719fac162c7..c1086af9fea 100644 --- a/lldb/include/lldb/Symbol/SymbolContext.h +++ b/lldb/include/lldb/Symbol/SymbolContext.h @@ -461,6 +461,19 @@ public: bool GetContextAtIndex(size_t idx, SymbolContext& sc) const; + //------------------------------------------------------------------ + /// Get accessor for the last symbol context in the list. + /// + /// @param[out] sc + /// A reference to the symbol context to fill in. + /// + /// @return + /// Returns \b true if \a sc was filled in, \b false if the + /// list is empty. + //------------------------------------------------------------------ + bool + GetLastContext(SymbolContext& sc) const; + bool RemoveContextAtIndex (size_t idx); //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Symbol/Symtab.h b/lldb/include/lldb/Symbol/Symtab.h index 54c9b83639d..868b0150489 100644 --- a/lldb/include/lldb/Symbol/Symtab.h +++ b/lldb/include/lldb/Symbol/Symtab.h @@ -107,6 +107,8 @@ protected: collection m_symbols; std::vector<uint32_t> m_addr_indexes; UniqueCStringMap<uint32_t> m_name_to_index; + UniqueCStringMap<uint32_t> m_basename_to_index; + UniqueCStringMap<uint32_t> m_method_to_index; UniqueCStringMap<uint32_t> m_selector_to_index; mutable Mutex m_mutex; // Provide thread safety for this symbol table bool m_addr_indexes_computed:1, diff --git a/lldb/include/lldb/Target/CPPLanguageRuntime.h b/lldb/include/lldb/Target/CPPLanguageRuntime.h index 5a59b44b5a0..bfa08e19b23 100644 --- a/lldb/include/lldb/Target/CPPLanguageRuntime.h +++ b/lldb/include/lldb/Target/CPPLanguageRuntime.h @@ -25,6 +25,93 @@ class CPPLanguageRuntime : public LanguageRuntime { public: + + class MethodName + { + public: + enum Type + { + eTypeInvalid, + eTypeUnknownMethod, + eTypeClassMethod, + eTypeInstanceMethod + }; + + MethodName () : + m_full(), + m_basename(), + m_context(), + m_arguments(), + m_qualifiers(), + m_type (eTypeInvalid), + m_parsed (false), + m_parse_error (false) + { + } + + MethodName (const ConstString &s) : + m_full(s), + m_basename(), + m_context(), + m_arguments(), + m_qualifiers(), + m_type (eTypeInvalid), + m_parsed (false), + m_parse_error (false) + { + } + + void + Clear(); + + bool + IsValid () const + { + if (m_parse_error) + return false; + if (m_type == eTypeInvalid) + return false; + return (bool)m_full; + } + + Type + GetType () const + { + return m_type; + } + + const ConstString & + GetFullName () const + { + return m_full; + } + + const ConstString & + GetBasename (); + + llvm::StringRef + GetContext (); + + llvm::StringRef + GetArguments (); + + llvm::StringRef + GetQualifiers (); + + protected: + void + Parse(); + + ConstString m_full; // Full name: "lldb::SBTarget::GetBreakpointAtIndex(unsigned int) const" + ConstString m_basename; // Basename: "GetBreakpointAtIndex" + llvm::StringRef m_context; // Decl context: "lldb::SBTarget" + llvm::StringRef m_arguments; // Arguments: "(unsigned int)" + llvm::StringRef m_qualifiers; // Qualifiers: "const" + Type m_type; + bool m_parsed; + bool m_parse_error; + }; + virtual ~CPPLanguageRuntime(); diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp index 2848abfa62f..4557abb37a7 100644 --- a/lldb/source/Breakpoint/BreakpointResolverName.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -27,16 +27,12 @@ using namespace lldb; using namespace lldb_private; -BreakpointResolverName::BreakpointResolverName -( - Breakpoint *bkpt, - const char *func_name, - uint32_t func_name_type_mask, - Breakpoint::MatchType type, - bool skip_prologue -) : +BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt, + const char *name_cstr, + uint32_t name_type_mask, + Breakpoint::MatchType type, + bool skip_prologue) : BreakpointResolver (bkpt, BreakpointResolver::NameResolver), - m_func_name_type_mask (func_name_type_mask), m_class_name (), m_regex (), m_match_type (type), @@ -45,22 +41,17 @@ BreakpointResolverName::BreakpointResolverName if (m_match_type == Breakpoint::Regexp) { - if (!m_regex.Compile (func_name)) + if (!m_regex.Compile (name_cstr)) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); if (log) - log->Warning ("function name regexp: \"%s\" did not compile.", func_name); + log->Warning ("function name regexp: \"%s\" did not compile.", name_cstr); } } else { - const bool append = true; - ObjCLanguageRuntime::MethodName objc_name(func_name, false); - if (objc_name.IsValid(false)) - objc_name.GetFullNames(m_func_names, append); - else - m_func_names.push_back(ConstString(func_name)); + AddNameLookup (ConstString(name_cstr), name_type_mask); } } @@ -70,18 +61,12 @@ BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt, uint32_t name_type_mask, bool skip_prologue) : BreakpointResolver (bkpt, BreakpointResolver::NameResolver), - m_func_name_type_mask (name_type_mask), m_match_type (Breakpoint::Exact), m_skip_prologue (skip_prologue) { - const bool append = true; for (size_t i = 0; i < num_names; i++) { - ObjCLanguageRuntime::MethodName objc_name(names[i], false); - if (objc_name.IsValid(false)) - objc_name.GetFullNames(m_func_names, append); - else - m_func_names.push_back (ConstString (names[i])); + AddNameLookup (ConstString (names[i]), name_type_mask); } } @@ -90,28 +75,18 @@ BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt, uint32_t name_type_mask, bool skip_prologue) : BreakpointResolver (bkpt, BreakpointResolver::NameResolver), - m_func_name_type_mask (name_type_mask), m_match_type (Breakpoint::Exact), m_skip_prologue (skip_prologue) { - size_t num_names = names.size(); - const bool append = true; - for (size_t i = 0; i < num_names; i++) + for (const std::string& name : names) { - ObjCLanguageRuntime::MethodName objc_name(names[i].c_str(), false); - if (objc_name.IsValid(false)) - objc_name.GetFullNames(m_func_names, append); - else - m_func_names.push_back (ConstString (names[i].c_str())); + AddNameLookup (ConstString (name.c_str(), name.size()), name_type_mask); } } -BreakpointResolverName::BreakpointResolverName -( - Breakpoint *bkpt, - RegularExpression &func_regex, - bool skip_prologue -) : +BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt, + RegularExpression &func_regex, + bool skip_prologue) : BreakpointResolver (bkpt, BreakpointResolver::NameResolver), m_class_name (NULL), m_regex (func_regex), @@ -134,13 +109,71 @@ BreakpointResolverName::BreakpointResolverName m_match_type (type), m_skip_prologue (skip_prologue) { - m_func_names.push_back(ConstString(method)); + LookupInfo lookup; + lookup.name.SetCString(method); + lookup.lookup_name = lookup.name; + lookup.name_type_mask = eFunctionNameTypeMethod; + lookup.match_name_after_lookup = false; + m_lookups.push_back (lookup); } BreakpointResolverName::~BreakpointResolverName () { } +void +BreakpointResolverName::AddNameLookup (const ConstString &name, uint32_t name_type_mask) +{ + ObjCLanguageRuntime::MethodName objc_method(name.GetCString(), false); + if (objc_method.IsValid(false)) + { + std::vector<ConstString> objc_names; + objc_method.GetFullNames(objc_names, true); + for (ConstString objc_name : objc_names) + { + LookupInfo lookup; + lookup.name = name; + lookup.lookup_name = objc_name; + lookup.name_type_mask = eFunctionNameTypeFull; + lookup.match_name_after_lookup = false; + m_lookups.push_back (lookup); + } + } + else + { + LookupInfo lookup; + lookup.name = name; + Module::PrepareForFunctionNameLookup(lookup.name, name_type_mask, lookup.lookup_name, lookup.name_type_mask, lookup.match_name_after_lookup); + m_lookups.push_back (lookup); + } +} + + +void +BreakpointResolverName::LookupInfo::Prune (SymbolContextList &sc_list, size_t start_idx) const +{ + if (match_name_after_lookup && name) + { + SymbolContext sc; + size_t i = start_idx; + while (i < sc_list.GetSize()) + { + if (!sc_list.GetContextAtIndex(i, sc)) + break; + ConstString full_name (sc.GetFunctionName()); + if (full_name && ::strstr(full_name.GetCString(), name.GetCString()) == NULL) + { + sc_list.RemoveContextAtIndex(i); + } + else + { + ++i; + } + } + } +} + + // FIXME: Right now we look at the module level, and call the module's "FindFunctions". // Greg says he will add function tables, maybe at the CompileUnit level to accelerate function // lookup. At that point, we should switch the depth to CompileUnit, and look in these tables. @@ -159,7 +192,6 @@ BreakpointResolverName::SearchCallback uint32_t i; bool new_location; - SymbolContext sc; Address break_addr; assert (m_breakpoint != NULL); @@ -182,22 +214,29 @@ BreakpointResolverName::SearchCallback case Breakpoint::Exact: if (context.module_sp) { - size_t num_names = m_func_names.size(); - for (int j = 0; j < num_names; j++) + for (const LookupInfo &lookup : m_lookups) { - size_t num_functions = context.module_sp->FindFunctions (m_func_names[j], - NULL, - m_func_name_type_mask, - include_symbols, - include_inlines, - append, - func_list); + const size_t start_func_idx = func_list.GetSize(); + context.module_sp->FindFunctions (lookup.lookup_name, + NULL, + lookup.name_type_mask, + include_symbols, + include_inlines, + append, + func_list); + const size_t end_func_idx = func_list.GetSize(); + + if (start_func_idx < end_func_idx) + lookup.Prune (func_list, start_func_idx); // If the search filter specifies a Compilation Unit, then we don't need to bother to look in plain // symbols, since all the ones from a set compilation unit will have been found above already. - - if (num_functions == 0 && !filter_by_cu) + else if (!filter_by_cu) { - context.module_sp->FindFunctionSymbols (m_func_names[j], m_func_name_type_mask, sym_list); + const size_t start_symbol_idx = sym_list.GetSize(); + context.module_sp->FindFunctionSymbols (lookup.lookup_name, lookup.name_type_mask, sym_list); + const size_t end_symbol_idx = sym_list.GetSize(); + if (start_symbol_idx < end_symbol_idx) + lookup.Prune (func_list, start_symbol_idx); } } } @@ -239,6 +278,7 @@ BreakpointResolverName::SearchCallback } // Remove any duplicates between the funcion list and the symbol list + SymbolContext sc; if (func_list.GetSize()) { for (i = 0; i < func_list.GetSize(); i++) @@ -356,17 +396,17 @@ BreakpointResolverName::GetDescription (Stream *s) s->Printf("regex = '%s'", m_regex.GetText()); else { - size_t num_names = m_func_names.size(); + size_t num_names = m_lookups.size(); if (num_names == 1) - s->Printf("name = '%s'", m_func_names[0].AsCString()); + s->Printf("name = '%s'", m_lookups[0].name.GetCString()); else { s->Printf("names = {"); for (size_t i = 0; i < num_names - 1; i++) { - s->Printf ("'%s', ", m_func_names[i].AsCString()); + s->Printf ("'%s', ", m_lookups[i].name.GetCString()); } - s->Printf ("'%s'}", m_func_names[num_names - 1].AsCString()); + s->Printf ("'%s'}", m_lookups[num_names - 1].name.GetCString()); } } } diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 671d6e4c125..151e611b71b 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -29,6 +29,8 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Target/CPPLanguageRuntime.h" +#include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -589,42 +591,83 @@ Module::FindFunctions (const ConstString &name, if (!append) sc_list.Clear(); - const size_t start_size = sc_list.GetSize(); + const size_t old_size = sc_list.GetSize(); // Find all the functions (not symbols, but debug information functions... SymbolVendor *symbols = GetSymbolVendor (); - if (symbols) - symbols->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, append, sc_list); - - // Now check our symbol table for symbols that are code symbols if requested - if (include_symbols) + + if (name_type_mask & eFunctionNameTypeAuto) { - ObjectFile *objfile = GetObjectFile(); - if (objfile) + ConstString lookup_name; + uint32_t lookup_name_type_mask = 0; + bool match_name_after_lookup = false; + Module::PrepareForFunctionNameLookup (name, + name_type_mask, + lookup_name, + lookup_name_type_mask, + match_name_after_lookup); + + if (symbols) + symbols->FindFunctions(lookup_name, + namespace_decl, + lookup_name_type_mask, + include_inlines, + append, + sc_list); + + // Now check our symbol table for symbols that are code symbols if requested + if (include_symbols) { - Symtab *symtab = objfile->GetSymtab(); - if (symtab) + ObjectFile *objfile = GetObjectFile(); + if (objfile) { - std::vector<uint32_t> symbol_indexes; - symtab->FindAllSymbolsWithNameAndType (name, eSymbolTypeAny, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes); - const size_t num_matches = symbol_indexes.size(); - if (num_matches) + Symtab *symtab = objfile->GetSymtab(); + if (symtab) + symtab->FindFunctionSymbols(lookup_name, lookup_name_type_mask, sc_list); + } + } + + if (match_name_after_lookup) + { + SymbolContext sc; + size_t i = old_size; + while (i<sc_list.GetSize()) + { + if (sc_list.GetContextAtIndex(i, sc)) { - const bool merge_symbol_into_function = true; - SymbolContext sc(this); - for (size_t i=0; i<num_matches; i++) + const char *func_name = sc.GetFunctionName().GetCString(); + if (func_name && strstr (func_name, name.GetCString()) == NULL) { - sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]); - SymbolType sym_type = sc.symbol->GetType(); - if (sc.symbol && (sym_type == eSymbolTypeCode || - sym_type == eSymbolTypeResolver)) - sc_list.AppendIfUnique (sc, merge_symbol_into_function); + // Remove the current context + sc_list.RemoveContextAtIndex(i); + // Don't increment i and continue in the loop + continue; } } + ++i; } } + } - return sc_list.GetSize() - start_size; + else + { + if (symbols) + symbols->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, append, sc_list); + + // Now check our symbol table for symbols that are code symbols if requested + if (include_symbols) + { + ObjectFile *objfile = GetObjectFile(); + if (objfile) + { + Symtab *symtab = objfile->GetSymtab(); + if (symtab) + symtab->FindFunctionSymbols(name, name_type_mask, sc_list); + } + } + } + + return sc_list.GetSize() - old_size; } size_t @@ -1347,3 +1390,78 @@ Module::GetVersion (uint32_t *versions, uint32_t num_versions) } return 0; } + +void +Module::PrepareForFunctionNameLookup (const ConstString &name, + uint32_t name_type_mask, + ConstString &lookup_name, + uint32_t &lookup_name_type_mask, + bool &match_name_after_lookup) +{ + const char *name_cstr = name.GetCString(); + lookup_name_type_mask = eFunctionNameTypeNone; + match_name_after_lookup = false; + const char *base_name_start = NULL; + const char *base_name_end = NULL; + + if (name_type_mask & eFunctionNameTypeAuto) + { + if (CPPLanguageRuntime::IsCPPMangledName (name_cstr)) + lookup_name_type_mask = eFunctionNameTypeFull; + else if (ObjCLanguageRuntime::IsPossibleObjCMethodName (name_cstr)) + lookup_name_type_mask = eFunctionNameTypeFull; + else + { + if (ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr)) + lookup_name_type_mask |= eFunctionNameTypeSelector; + + if (CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end)) + lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase); + } + } + else + { + lookup_name_type_mask = name_type_mask; + if (lookup_name_type_mask & eFunctionNameTypeMethod || name_type_mask & eFunctionNameTypeBase) + { + // If they've asked for a CPP method or function name and it can't be that, we don't + // even need to search for CPP methods or names. + if (!CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end)) + { + lookup_name_type_mask &= ~(eFunctionNameTypeMethod | eFunctionNameTypeBase); + if (lookup_name_type_mask == eFunctionNameTypeNone) + return; + } + } + + if (lookup_name_type_mask & eFunctionNameTypeSelector) + { + if (!ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr)) + { + lookup_name_type_mask &= ~(eFunctionNameTypeSelector); + if (lookup_name_type_mask == eFunctionNameTypeNone) + return; + } + } + } + + if (base_name_start && + base_name_end && + base_name_start != name_cstr && + base_name_start < base_name_end) + { + // The name supplied was a partial C++ path like "a::count". In this case we want to do a + // lookup on the basename "count" and then make sure any matching results contain "a::count" + // so that it would match "b::a::count" and "a::count". This is why we set "match_name_after_lookup" + // to true + lookup_name.SetCStringWithLength(base_name_start, base_name_end - base_name_start); + match_name_after_lookup = true; + } + else + { + // The name is already correct, just use the exact name as supplied, and we won't need + // to check if any matches contain "name" + lookup_name = name; + match_name_after_lookup = false; + } +}
\ No newline at end of file diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 8e79a455182..23cad43ff67 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -337,14 +337,64 @@ ModuleList::FindFunctions (const ConstString &name, if (!append) sc_list.Clear(); - Mutex::Locker locker(m_modules_mutex); - collection::const_iterator pos, end = m_modules.end(); - for (pos = m_modules.begin(); pos != end; ++pos) - { - (*pos)->FindFunctions (name, NULL, name_type_mask, include_symbols, include_inlines, true, sc_list); + const size_t old_size = sc_list.GetSize(); + + if (name_type_mask & eFunctionNameTypeAuto) + { + ConstString lookup_name; + uint32_t lookup_name_type_mask = 0; + bool match_name_after_lookup = false; + Module::PrepareForFunctionNameLookup (name, name_type_mask, + lookup_name, + lookup_name_type_mask, + match_name_after_lookup); + + Mutex::Locker locker(m_modules_mutex); + collection::const_iterator pos, end = m_modules.end(); + for (pos = m_modules.begin(); pos != end; ++pos) + { + (*pos)->FindFunctions (lookup_name, + NULL, + lookup_name_type_mask, + include_symbols, + include_inlines, + true, + sc_list); + } + + if (match_name_after_lookup) + { + SymbolContext sc; + size_t i = old_size; + while (i<sc_list.GetSize()) + { + if (sc_list.GetContextAtIndex(i, sc)) + { + const char *func_name = sc.GetFunctionName().GetCString(); + if (func_name && strstr (func_name, name.GetCString()) == NULL) + { + // Remove the current context + sc_list.RemoveContextAtIndex(i); + // Don't increment i and continue in the loop + continue; + } + } + ++i; + } + } + } + else + { - return sc_list.GetSize(); + Mutex::Locker locker(m_modules_mutex); + collection::const_iterator pos, end = m_modules.end(); + for (pos = m_modules.begin(); pos != end; ++pos) + { + (*pos)->FindFunctions (name, NULL, name_type_mask, include_symbols, include_inlines, true, sc_list); + } + } + return sc_list.GetSize() - old_size; } size_t diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp index 5bbe06de3ba..04ab1660a07 100644 --- a/lldb/source/Expression/ClangExpressionDeclMap.cpp +++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp @@ -3116,7 +3116,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, // instance methods for eFunctionNameTypeBase. target->GetImages().FindFunctions(name, - eFunctionNameTypeBase, + eFunctionNameTypeFull, include_symbols, include_inlines, append, diff --git a/lldb/source/Interpreter/CommandObjectRegexCommand.cpp b/lldb/source/Interpreter/CommandObjectRegexCommand.cpp index 25b02baf54a..0fc454eb4da 100644 --- a/lldb/source/Interpreter/CommandObjectRegexCommand.cpp +++ b/lldb/source/Interpreter/CommandObjectRegexCommand.cpp @@ -35,8 +35,8 @@ CommandObjectRegexCommand::CommandObjectRegexCommand ) : CommandObjectRaw (interpreter, name, help, syntax), m_max_matches (max_matches), - m_entries (), - m_completion_type_mask (completion_type_mask) + m_completion_type_mask (completion_type_mask), + m_entries () { } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 3c0624dd68c..35cd1296a4a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3322,6 +3322,9 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, "SymbolFileDWARF::FindFunctions (name = '%s')", name.AsCString()); + // eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup() + assert ((name_type_mask & eFunctionNameTypeAuto) == 0); + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); if (log) @@ -3347,59 +3350,16 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, // Remember how many sc_list are in the list before we search in case // we are appending the results to a variable list. - const uint32_t original_size = sc_list.GetSize(); - const char *name_cstr = name.GetCString(); - uint32_t effective_name_type_mask = eFunctionNameTypeNone; - const char *base_name_start = name_cstr; - const char *base_name_end = name_cstr + strlen(name_cstr); - - if (name_type_mask & eFunctionNameTypeAuto) - { - if (CPPLanguageRuntime::IsCPPMangledName (name_cstr)) - effective_name_type_mask = eFunctionNameTypeFull; - else if (ObjCLanguageRuntime::IsPossibleObjCMethodName (name_cstr)) - effective_name_type_mask = eFunctionNameTypeFull; - else - { - if (ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr)) - effective_name_type_mask |= eFunctionNameTypeSelector; - - if (CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end)) - effective_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase); - } - } - else - { - effective_name_type_mask = name_type_mask; - if (effective_name_type_mask & eFunctionNameTypeMethod || name_type_mask & eFunctionNameTypeBase) - { - // If they've asked for a CPP method or function name and it can't be that, we don't - // even need to search for CPP methods or names. - if (!CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end)) - { - effective_name_type_mask &= ~(eFunctionNameTypeMethod | eFunctionNameTypeBase); - if (effective_name_type_mask == eFunctionNameTypeNone) - return 0; - } - } - - if (effective_name_type_mask & eFunctionNameTypeSelector) - { - if (!ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr)) - { - effective_name_type_mask &= ~(eFunctionNameTypeSelector); - if (effective_name_type_mask == eFunctionNameTypeNone) - return 0; - } - } - } - + + const uint32_t original_size = sc_list.GetSize(); + DWARFDebugInfo* info = DebugInfo(); if (info == NULL) return 0; DWARFCompileUnit *dwarf_cu = NULL; + std::set<const DWARFDebugInfoEntry *> resolved_dies; if (m_using_apple_tables) { if (m_apple_names_ap.get()) @@ -3409,7 +3369,7 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, uint32_t num_matches = 0; - if (effective_name_type_mask & eFunctionNameTypeFull) + if (name_type_mask & eFunctionNameTypeFull) { // If they asked for the full name, match what they typed. At some point we may // want to canonicalize this (strip double spaces, etc. For now, we just add all the @@ -3427,7 +3387,11 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) continue; - ResolveFunction (dwarf_cu, die, sc_list); + if (resolved_dies.find(die) == resolved_dies.end()) + { + if (ResolveFunction (dwarf_cu, die, sc_list)) + resolved_dies.insert(die); + } } else { @@ -3436,87 +3400,116 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, } } } - else - { - if (effective_name_type_mask & eFunctionNameTypeSelector) - { - if (namespace_decl && *namespace_decl) - return 0; // no selectors in namespaces - - num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); - // Now make sure these are actually ObjC methods. In this case we can simply look up the name, - // and if it is an ObjC method name, we're good. + + if (name_type_mask & eFunctionNameTypeSelector) + { + if (namespace_decl && *namespace_decl) + return 0; // no selectors in namespaces - for (uint32_t i = 0; i < num_matches; i++) + num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); + // Now make sure these are actually ObjC methods. In this case we can simply look up the name, + // and if it is an ObjC method name, we're good. + + for (uint32_t i = 0; i < num_matches; i++) + { + const dw_offset_t die_offset = die_offsets[i]; + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + if (die) { - const dw_offset_t die_offset = die_offsets[i]; - const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); - if (die) + const char *die_name = die->GetName(this, dwarf_cu); + if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name)) { - const char *die_name = die->GetName(this, dwarf_cu); - if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name)) + if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) + continue; + + if (resolved_dies.find(die) == resolved_dies.end()) { - if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) - continue; - - ResolveFunction (dwarf_cu, die, sc_list); + if (ResolveFunction (dwarf_cu, die, sc_list)) + resolved_dies.insert(die); } } - else - { - GetObjectFile()->GetModule()->ReportError ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", - die_offset, name_cstr); - } } - die_offsets.clear(); + else + { + GetObjectFile()->GetModule()->ReportError ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", + die_offset, name_cstr); + } } + die_offsets.clear(); + } + + if (((name_type_mask & eFunctionNameTypeMethod) && !namespace_decl) || name_type_mask & eFunctionNameTypeBase) + { + // The apple_names table stores just the "base name" of C++ methods in the table. So we have to + // extract the base name, look that up, and if there is any other information in the name we were + // passed in we have to post-filter based on that. - if (effective_name_type_mask & eFunctionNameTypeMethod - || effective_name_type_mask & eFunctionNameTypeBase) + // FIXME: Arrange the logic above so that we don't calculate the base name twice: + num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); + + for (uint32_t i = 0; i < num_matches; i++) { - if ((effective_name_type_mask & eFunctionNameTypeMethod) && - (namespace_decl && *namespace_decl)) - return 0; // no methods in namespaces - - // The apple_names table stores just the "base name" of C++ methods in the table. So we have to - // extract the base name, look that up, and if there is any other information in the name we were - // passed in we have to post-filter based on that. - - // FIXME: Arrange the logic above so that we don't calculate the base name twice: - std::string base_name(base_name_start, base_name_end - base_name_start); - num_matches = m_apple_names_ap->FindByName (base_name.c_str(), die_offsets); - - for (uint32_t i = 0; i < num_matches; i++) + const dw_offset_t die_offset = die_offsets[i]; + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + if (die) { - const dw_offset_t die_offset = die_offsets[i]; - const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); - if (die) + if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) + continue; + + if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) + continue; + + // If we get to here, the die is good, and we should add it: + if (resolved_dies.find(die) == resolved_dies.end()) + if (ResolveFunction (dwarf_cu, die, sc_list)) { - if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) - continue; - - if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) - continue; - - if (!FunctionDieMatchesPartialName(die, - dwarf_cu, - effective_name_type_mask, - name_cstr, - base_name_start, - base_name_end)) - continue; - - // If we get to here, the die is good, and we should add it: - ResolveFunction (dwarf_cu, die, sc_list); + bool keep_die = true; + if ((name_type_mask & (eFunctionNameTypeBase|eFunctionNameTypeMethod)) != (eFunctionNameTypeBase|eFunctionNameTypeMethod)) + { + // We are looking for either basenames or methods, so we need to + // trim out the ones we won't want by looking at the type + SymbolContext sc; + if (sc_list.GetLastContext(sc)) + { + if (sc.block) + { + // We have an inlined function + } + else if (sc.function) + { + Type *type = sc.function->GetType(); + + clang::DeclContext* decl_ctx = GetClangDeclContextContainingTypeUID (type->GetID()); + if (decl_ctx->isRecord()) + { + if (name_type_mask & eFunctionNameTypeBase) + { + sc_list.RemoveContextAtIndex(sc_list.GetSize()-1); + keep_die = false; + } + } + else + { + if (name_type_mask & eFunctionNameTypeMethod) + { + sc_list.RemoveContextAtIndex(sc_list.GetSize()-1); + keep_die = false; + } + } + } + } + } + if (keep_die) + resolved_dies.insert(die); } - else - { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", - die_offset, name_cstr); - } } - die_offsets.clear(); + else + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", + die_offset, name_cstr); + } } + die_offsets.clear(); } } } @@ -3530,14 +3523,12 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, if (name_type_mask & eFunctionNameTypeFull) FindFunctions (name, m_function_fullname_index, sc_list); - std::string base_name(base_name_start, base_name_end - base_name_start); - ConstString base_name_const(base_name.c_str()); DIEArray die_offsets; DWARFCompileUnit *dwarf_cu = NULL; - if (effective_name_type_mask & eFunctionNameTypeBase) + if (name_type_mask & eFunctionNameTypeBase) { - uint32_t num_base = m_function_basename_index.Find(base_name_const, die_offsets); + uint32_t num_base = m_function_basename_index.Find(name, die_offsets); for (uint32_t i = 0; i < num_base; i++) { const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu); @@ -3549,27 +3540,23 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) continue; - if (!FunctionDieMatchesPartialName(die, - dwarf_cu, - eFunctionNameTypeBase, - name_cstr, - base_name_start, - base_name_end)) - continue; - // If we get to here, the die is good, and we should add it: - ResolveFunction (dwarf_cu, die, sc_list); + if (resolved_dies.find(die) == resolved_dies.end()) + { + if (ResolveFunction (dwarf_cu, die, sc_list)) + resolved_dies.insert(die); + } } } die_offsets.clear(); } - if (effective_name_type_mask & eFunctionNameTypeMethod) + if (name_type_mask & eFunctionNameTypeMethod) { if (namespace_decl && *namespace_decl) return 0; // no methods in namespaces - uint32_t num_base = m_function_method_index.Find(base_name_const, die_offsets); + uint32_t num_base = m_function_method_index.Find(name, die_offsets); { for (uint32_t i = 0; i < num_base; i++) { @@ -3579,23 +3566,19 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) continue; - if (!FunctionDieMatchesPartialName(die, - dwarf_cu, - eFunctionNameTypeMethod, - name_cstr, - base_name_start, - base_name_end)) - continue; - // If we get to here, the die is good, and we should add it: - ResolveFunction (dwarf_cu, die, sc_list); + if (resolved_dies.find(die) == resolved_dies.end()) + { + if (ResolveFunction (dwarf_cu, die, sc_list)) + resolved_dies.insert(die); + } } } } die_offsets.clear(); } - if ((effective_name_type_mask & eFunctionNameTypeSelector) && (!namespace_decl || !*namespace_decl)) + if ((name_type_mask & eFunctionNameTypeSelector) && (!namespace_decl || !*namespace_decl)) { FindFunctions (name, m_function_selector_index, sc_list); } diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp index 97fe9061a21..49cb1c4f3fc 100644 --- a/lldb/source/Symbol/SymbolContext.cpp +++ b/lldb/source/Symbol/SymbolContext.cpp @@ -1056,6 +1056,17 @@ SymbolContextList::GetContextAtIndex(size_t idx, SymbolContext& sc) const } bool +SymbolContextList::GetLastContext(SymbolContext& sc) const +{ + if (!m_symbol_contexts.empty()) + { + sc = m_symbol_contexts.back(); + return true; + } + return false; +} + +bool SymbolContextList::RemoveContextAtIndex (size_t idx) { if (idx < m_symbol_contexts.size()) diff --git a/lldb/source/Symbol/Symtab.cpp b/lldb/source/Symbol/Symtab.cpp index 37c204d1890..ac39e5a1519 100644 --- a/lldb/source/Symbol/Symtab.cpp +++ b/lldb/source/Symbol/Symtab.cpp @@ -16,6 +16,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Symtab.h" +#include "lldb/Target/CPPLanguageRuntime.h" #include "lldb/Target/ObjCLanguageRuntime.h" using namespace lldb; @@ -263,9 +264,9 @@ Symtab::InitNameIndexes() m_name_indexes_computed = true; Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__); // Create the name index vector to be able to quickly search by name - const size_t count = m_symbols.size(); + const size_t num_symbols = m_symbols.size(); #if 1 - m_name_to_index.Reserve (count); + m_name_to_index.Reserve (num_symbols); #else // TODO: benchmark this to see if we save any memory. Otherwise we // will always keep the memory reserved in the vector unless we pull @@ -288,7 +289,12 @@ Symtab::InitNameIndexes() NameToIndexMap::Entry entry; - for (entry.value = 0; entry.value < count; ++entry.value) + // 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, NULL); + + for (entry.value = 0; entry.value<num_symbols; ++entry.value) { const Symbol *symbol = &m_symbols[entry.value]; @@ -303,8 +309,66 @@ Symtab::InitNameIndexes() const Mangled &mangled = symbol->GetMangled(); entry.cstring = mangled.GetMangledName().GetCString(); if (entry.cstring && entry.cstring[0]) + { m_name_to_index.Append (entry); - + + const SymbolType symbol_type = symbol->GetType(); + if (symbol_type == eSymbolTypeCode || symbol_type == eSymbolTypeResolver) + { + if (entry.cstring[0] == '_' && entry.cstring[1] == 'Z' && + (entry.cstring[2] != 'T' && // avoid virtual table, VTT structure, typeinfo structure, and typeinfo name + entry.cstring[2] != 'G' && // avoid guard variables + entry.cstring[2] != 'Z')) // named local entities (if we eventually handle eSymbolTypeData, we will want this back) + { + CPPLanguageRuntime::MethodName cxx_method (mangled.GetDemangledName()); + entry.cstring = cxx_method.GetBasename ().GetCString(); + if (entry.cstring && entry.cstring[0]) + { + // 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 (entry.cstring[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 (const_context && const_context[0]) + { + 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; + } + } + else + { + // No context for this function so this has to be a basename + m_basename_to_index.Append(entry); + } + } + } + } + } + } + entry.cstring = mangled.GetDemangledName().GetCString(); if (entry.cstring && entry.cstring[0]) m_name_to_index.Append (entry); @@ -326,15 +390,64 @@ Symtab::InitNameIndexes() } } + + size_t count; + if (!mangled_name_to_index.IsEmpty()) + { + count = mangled_name_to_index.GetSize(); + for (size_t i=0; i<count; ++i) + { + if (mangled_name_to_index.GetValueAtIndex(i, entry.value)) + { + entry.cstring = mangled_name_to_index.GetCStringAtIndex(i); + if (symbol_contexts[entry.value] && class_contexts.find(symbol_contexts[entry.value]) != class_contexts.end()) + { + 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 + m_method_to_index.Append (entry); + m_basename_to_index.Append (entry); + } + } + } + } m_name_to_index.Sort(); m_name_to_index.SizeToFit(); m_selector_to_index.Sort(); m_selector_to_index.SizeToFit(); + m_basename_to_index.Sort(); + m_basename_to_index.SizeToFit(); + m_method_to_index.Sort(); + m_method_to_index.SizeToFit(); + +// static StreamFile a ("/tmp/a.txt"); +// +// count = m_basename_to_index.GetSize(); +// if (count) +// { +// for (size_t i=0; i<count; ++i) +// { +// if (m_basename_to_index.GetValueAtIndex(i, entry.value)) +// a.Printf ("%s BASENAME\n", m_symbols[entry.value].GetMangled().GetName().GetCString()); +// } +// } +// count = m_method_to_index.GetSize(); +// if (count) +// { +// for (size_t i=0; i<count; ++i) +// { +// if (m_method_to_index.GetValueAtIndex(i, entry.value)) +// a.Printf ("%s METHOD\n", m_symbols[entry.value].GetMangled().GetName().GetCString()); +// } +// } } } void -Symtab::AppendSymbolNamesToMap (const IndexCollection &indexes, +Symtab::AppendSymbolNamesToMap (const IndexCollection &indexes, bool add_demangled, bool add_mangled, NameToIndexMap &name_to_index_map) const @@ -1009,6 +1122,7 @@ Symtab::SymbolIndicesToSymbolContextList (std::vector<uint32_t> &symbol_indexes, // No need to protect this call using m_mutex all other method calls are // already thread safe. + const bool merge_symbol_into_function = true; size_t num_indices = symbol_indexes.size(); if (num_indices > 0) { @@ -1018,7 +1132,7 @@ Symtab::SymbolIndicesToSymbolContextList (std::vector<uint32_t> &symbol_indexes, { sc.symbol = SymbolAtIndex (symbol_indexes[i]); if (sc.symbol) - sc_list.Append (sc); + sc_list.AppendIfUnique(sc, merge_symbol_into_function); } } } @@ -1031,11 +1145,53 @@ Symtab::FindFunctionSymbols (const ConstString &name, { size_t count = 0; std::vector<uint32_t> symbol_indexes; - if (name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull | eFunctionNameTypeAuto)) + + const char *name_cstr = name.GetCString(); + + // eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup() + assert ((name_type_mask & eFunctionNameTypeAuto) == 0); + + if (name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull)) { FindAllSymbolsWithNameAndType (name, eSymbolTypeCode, symbol_indexes); } + if (name_type_mask & eFunctionNameTypeBase) + { + // From mangled names we can't tell what is a basename and what + // is a method name, so we just treat them the same + if (!m_name_indexes_computed) + InitNameIndexes(); + + if (!m_basename_to_index.IsEmpty()) + { + const UniqueCStringMap<uint32_t>::Entry *match; + for (match = m_basename_to_index.FindFirstValueForName(name_cstr); + match != NULL; + match = m_basename_to_index.FindNextValueForName(match)) + { + symbol_indexes.push_back(match->value); + } + } + } + + if (name_type_mask & eFunctionNameTypeMethod) + { + if (!m_name_indexes_computed) + InitNameIndexes(); + + if (!m_method_to_index.IsEmpty()) + { + const UniqueCStringMap<uint32_t>::Entry *match; + for (match = m_method_to_index.FindFirstValueForName(name_cstr); + match != NULL; + match = m_method_to_index.FindNextValueForName(match)) + { + symbol_indexes.push_back(match->value); + } + } + } + if (name_type_mask & eFunctionNameTypeSelector) { if (!m_name_indexes_computed) @@ -1044,7 +1200,7 @@ Symtab::FindFunctionSymbols (const ConstString &name, if (!m_selector_to_index.IsEmpty()) { const UniqueCStringMap<uint32_t>::Entry *match; - for (match = m_selector_to_index.FindFirstValueForName(name.AsCString()); + for (match = m_selector_to_index.FindFirstValueForName(name_cstr); match != NULL; match = m_selector_to_index.FindNextValueForName(match)) { diff --git a/lldb/source/Target/CPPLanguageRuntime.cpp b/lldb/source/Target/CPPLanguageRuntime.cpp index 6b36d14a114..b020e0af18a 100644 --- a/lldb/source/Target/CPPLanguageRuntime.cpp +++ b/lldb/source/Target/CPPLanguageRuntime.cpp @@ -190,65 +190,65 @@ CPPLanguageRuntime::IsCPPMangledName (const char *name) bool CPPLanguageRuntime::StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end) { - if (base_name_end == NULL) - base_name_end = name + strlen (name); + if (base_name_end == NULL) + base_name_end = name + strlen (name); - const char *last_colon = NULL; - for (const char *ptr = base_name_end; ptr != name; ptr--) + const char *last_colon = NULL; + for (const char *ptr = base_name_end; ptr != name; ptr--) { - if (*ptr == ':') + if (*ptr == ':') { - last_colon = ptr; - break; + last_colon = ptr; + break; } } - - if (last_colon == NULL) + + if (last_colon == NULL) { - base_name_start = name; - return true; + base_name_start = name; + return true; } - - // Can't have a C++ name that begins with a single ':', nor contains an internal single ':' - if (last_colon == name) - return false; - else if (last_colon[-1] != ':') - return false; - else + + // Can't have a C++ name that begins with a single ':', nor contains an internal single ':' + if (last_colon == name) + return false; + else if (last_colon[-1] != ':') + return false; + else { - // FIXME: should check if there is - base_name_start = last_colon + 1; - return true; + // FIXME: should check if there is + base_name_start = last_colon + 1; + return true; } } bool CPPLanguageRuntime::IsPossibleCPPCall (const char *name, const char *&base_name_start, const char *&base_name_end) { if (!name) - return false; + return false; // For now, I really can't handle taking template names apart, so if you // have < or > I'll say "could be CPP but leave the base_name empty which // means I couldn't figure out what to use for that. // FIXME: Do I need to do more sanity checking here? - + if (strchr(name, '>') != NULL || strchr (name, '>') != NULL) - return true; - + return true; + size_t name_len = strlen (name); - + if (name[name_len - 1] == ')') { // We've got arguments. base_name_end = strchr (name, '('); if (base_name_end == NULL) - return false; - + return false; + // FIXME: should check that this parenthesis isn't a template specialized // on a function type or something gross like that... } else base_name_end = name + strlen (name); - + return StripNamespacesFromVariableName (name, base_name_start, base_name_end); } @@ -267,3 +267,156 @@ CPPLanguageRuntime::FindEquivalentNames(ConstString type_name, std::vector<Const return count; } + +void +CPPLanguageRuntime::MethodName::Clear() +{ + m_full.Clear(); + m_basename.Clear(); + m_context = llvm::StringRef(); + m_arguments = llvm::StringRef(); + m_qualifiers = llvm::StringRef(); + m_type = eTypeInvalid; + m_parsed = false; + m_parse_error = false; +} + +bool +ReverseFindMatchingChars (const llvm::StringRef &s, + const llvm::StringRef &left_right_chars, + size_t &left_pos, + size_t &right_pos, + size_t pos = llvm::StringRef::npos) +{ + assert (left_right_chars.size() == 2); + left_pos = llvm::StringRef::npos; + const char left_char = left_right_chars[0]; + const char right_char = left_right_chars[1]; + pos = s.find_last_of(left_right_chars, pos); + if (pos == llvm::StringRef::npos || s[pos] == left_char) + return false; + right_pos = pos; + uint32_t depth = 1; + while (pos > 0 && depth > 0) + { + pos = s.find_last_of(left_right_chars, pos); + if (pos == llvm::StringRef::npos) + return false; + if (s[pos] == left_char) + { + if (--depth == 0) + { + left_pos = pos; + return left_pos < right_pos; + } + } + else if (s[pos] == right_char) + { + ++depth; + } + } + return false; +} + +void +CPPLanguageRuntime::MethodName::Parse() +{ + if (!m_parsed && m_full) + { +// ConstString mangled; +// m_full.GetMangledCounterpart(mangled); +// printf ("\n parsing = '%s'\n", m_full.GetCString()); +// if (mangled) +// printf (" mangled = '%s'\n", mangled.GetCString()); + m_parse_error = false; + m_parsed = true; + llvm::StringRef full (m_full.GetCString()); + + size_t arg_start, arg_end; + llvm::StringRef parens("()", 2); + if (ReverseFindMatchingChars (full, parens, arg_start, arg_end)) + { + m_arguments = full.substr(arg_start, arg_end - arg_start + 1); + if (arg_end + 1 < full.size()) + m_qualifiers = full.substr(arg_end + 1); + if (arg_start > 0) + { + size_t basename_end = arg_start; + size_t context_end = llvm::StringRef::npos; + if (basename_end > 0 && full[basename_end-1] == '>') + { + // TODO: handle template junk... + // Templated function + size_t template_start, template_end; + llvm::StringRef lt_gt("<>", 2); + if (ReverseFindMatchingChars (full, lt_gt, template_start, template_end, basename_end)) + context_end = full.rfind(':', template_start); + } + if (context_end == llvm::StringRef::npos) + context_end = full.rfind(':', basename_end); + + if (context_end == llvm::StringRef::npos) + m_basename.SetString(full.substr(0, basename_end)); + else + { + m_context = full.substr(0, context_end - 1); + const size_t basename_begin = context_end + 1; + m_basename.SetString(full.substr(basename_begin, basename_end - basename_begin)); + } + m_type = eTypeUnknownMethod; + } + else + { + m_parse_error = true; + return; + } + +// if (!m_context.empty()) +// printf (" context = '%s'\n", m_context.str().c_str()); +// if (m_basename) +// printf (" basename = '%s'\n", m_basename.GetCString()); +// if (!m_arguments.empty()) +// printf (" arguments = '%s'\n", m_arguments.str().c_str()); +// if (!m_qualifiers.empty()) +// printf ("qualifiers = '%s'\n", m_qualifiers.str().c_str()); + } + else + { + m_parse_error = true; +// printf ("error: didn't find matching parens for arguments\n"); + } + } +} + +const ConstString & +CPPLanguageRuntime::MethodName::GetBasename () +{ + if (!m_parsed) + Parse(); + return m_basename; +} + +llvm::StringRef +CPPLanguageRuntime::MethodName::GetContext () +{ + if (!m_parsed) + Parse(); + return m_context; +} + +llvm::StringRef +CPPLanguageRuntime::MethodName::GetArguments () +{ + if (!m_parsed) + Parse(); + return m_arguments; +} + +llvm::StringRef +CPPLanguageRuntime::MethodName::GetQualifiers () +{ + if (!m_parsed) + Parse(); + return m_qualifiers; +} + |