[Lldb-commits] [lldb] r178608 - <rdar://problem/13506727>

Kopec, Matt matt.kopec at intel.com
Fri Apr 19 16:36:34 PDT 2013


Hi Greg,

After the recent build fixes we have uncovered some older regressions in lldb for expressions on Linux and they seem to be specific to C++ expressions. I did a little debugging and found the problem, in general, is a mismatch between the symbol lldb is searching for that it has parsed from an expression and the demangled symbol name in the dwarf/symbol table. Specifically, I think the commit below introduced the problems.

For instance, if 'int a_function_to_call() { return 0;}' is compiled as a c++ function, the demangled name becomes 'a_function_to_call()'. Similarly, an overloaded version 'int a_function_to_call(int i)' becomes 'a_function_to_call(int)'. Trying to print the demangled function pointer (ie. expression a_function_to_call) or calling the demangled function using an expression will fail. However, invoking the mangled name works as expected.

The expressions still work on mac with debug information due to the 'dwarf apple debug info' being used but trying to call c++ functions without debug info should fail just like it fails on Linux right now.

Can you let me know if you can reproduce the problem on mac without debug info?

Thanks,
Matt 


On 2013-04-02, at 10:00 PM, Greg Clayton <gclayton at apple.com> wrote:

> Author: gclayton
> Date: Tue Apr  2 21:00:15 2013
> New Revision: 178608
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=178608&view=rev
> Log:
> <rdar://problem/13506727> 
> 
> Symbol table function names should support lookups like symbols with debug info. 
> 
> To fix this I:
> - Gutted the way FindFunctions is used, there used to be way too much smarts only in the DWARF plug-in
> - Made it more efficient by chopping the name up once and using simpler queries so that SymbolFile and Symtab plug-ins don't need to do as much
> - Filter the results at a higher level
> - Make the lldb_private::Symtab able to chop up C++ mangled names and make as much sense out of them as possible and also be able to search by basename, fullname, method name, and selector name.
> 
> 
> Modified:
>    lldb/trunk/include/lldb/Breakpoint/BreakpointResolverName.h
>    lldb/trunk/include/lldb/Core/Module.h
>    lldb/trunk/include/lldb/Symbol/SymbolContext.h
>    lldb/trunk/include/lldb/Symbol/Symtab.h
>    lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h
>    lldb/trunk/source/Breakpoint/BreakpointResolverName.cpp
>    lldb/trunk/source/Core/Module.cpp
>    lldb/trunk/source/Core/ModuleList.cpp
>    lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp
>    lldb/trunk/source/Interpreter/CommandObjectRegexCommand.cpp
>    lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
>    lldb/trunk/source/Symbol/SymbolContext.cpp
>    lldb/trunk/source/Symbol/Symtab.cpp
>    lldb/trunk/source/Target/CPPLanguageRuntime.cpp
> 
> Modified: lldb/trunk/include/lldb/Breakpoint/BreakpointResolverName.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Breakpoint/BreakpointResolverName.h?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/include/lldb/Breakpoint/BreakpointResolverName.h (original)
> +++ lldb/trunk/include/lldb/Breakpoint/BreakpointResolverName.h Tue Apr  2 21:00:15 2013
> @@ -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);
> };
> 
> Modified: lldb/trunk/include/lldb/Core/Module.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Module.h?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/include/lldb/Core/Module.h (original)
> +++ lldb/trunk/include/lldb/Core/Module.h Tue Apr  2 21:00:15 2013
> @@ -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
> 
> Modified: lldb/trunk/include/lldb/Symbol/SymbolContext.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/SymbolContext.h?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/include/lldb/Symbol/SymbolContext.h (original)
> +++ lldb/trunk/include/lldb/Symbol/SymbolContext.h Tue Apr  2 21:00:15 2013
> @@ -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);
>     //------------------------------------------------------------------
> 
> Modified: lldb/trunk/include/lldb/Symbol/Symtab.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/Symtab.h?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/include/lldb/Symbol/Symtab.h (original)
> +++ lldb/trunk/include/lldb/Symbol/Symtab.h Tue Apr  2 21:00:15 2013
> @@ -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,
> 
> Modified: lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h (original)
> +++ lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h Tue Apr  2 21:00:15 2013
> @@ -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();
> 
> 
> Modified: lldb/trunk/source/Breakpoint/BreakpointResolverName.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Breakpoint/BreakpointResolverName.cpp?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/source/Breakpoint/BreakpointResolverName.cpp (original)
> +++ lldb/trunk/source/Breakpoint/BreakpointResolverName.cpp Tue Apr  2 21:00:15 2013
> @@ -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::BreakpointResolv
> 
>     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::BreakpointResolv
>                                                 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::BreakpointResolv
>                                                 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::BreakpointResolv
>     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 (
>         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());
>         }
>     }
> }
> 
> Modified: lldb/trunk/source/Core/Module.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Module.cpp?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/source/Core/Module.cpp (original)
> +++ lldb/trunk/source/Core/Module.cpp Tue Apr  2 21:00:15 2013
> @@ -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
>     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,
>     }
>     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
> 
> Modified: lldb/trunk/source/Core/ModuleList.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ModuleList.cpp?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/source/Core/ModuleList.cpp (original)
> +++ lldb/trunk/source/Core/ModuleList.cpp Tue Apr  2 21:00:15 2013
> @@ -337,14 +337,64 @@ ModuleList::FindFunctions (const ConstSt
>     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)
> +    const size_t old_size = sc_list.GetSize();
> +    
> +    if (name_type_mask & eFunctionNameTypeAuto)
>     {
> -        (*pos)->FindFunctions (name, NULL, name_type_mask, include_symbols, include_inlines, true, sc_list);
> +        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
> 
> Modified: lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp (original)
> +++ lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp Tue Apr  2 21:00:15 2013
> @@ -3116,7 +3116,7 @@ ClangExpressionDeclMap::FindExternalVisi
>                 //   instance methods for eFunctionNameTypeBase.
> 
>                 target->GetImages().FindFunctions(name,
> -                                                  eFunctionNameTypeBase,
> +                                                  eFunctionNameTypeFull,
>                                                   include_symbols,
>                                                   include_inlines,
>                                                   append, 
> 
> Modified: lldb/trunk/source/Interpreter/CommandObjectRegexCommand.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandObjectRegexCommand.cpp?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/source/Interpreter/CommandObjectRegexCommand.cpp (original)
> +++ lldb/trunk/source/Interpreter/CommandObjectRegexCommand.cpp Tue Apr  2 21:00:15 2013
> @@ -35,8 +35,8 @@ CommandObjectRegexCommand::CommandObject
> ) :
>     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 ()
> {
> }
> 
> 
> Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (original)
> +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp Tue Apr  2 21:00:15 2013
> @@ -3322,6 +3322,9 @@ SymbolFileDWARF::FindFunctions (const Co
>                         "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 Co
>     // 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 Co
> 
>             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 Co
>                         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 Co
>                     }                                    
>                 }
>             }
> -            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.
> +                
> +                // 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);
> 
> -                if (effective_name_type_mask & eFunctionNameTypeMethod
> -                    || effective_name_type_mask & eFunctionNameTypeBase)
> +                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 Co
>         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 Co
>                     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 Co
>                         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);
>         }
> 
> Modified: lldb/trunk/source/Symbol/SymbolContext.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/SymbolContext.cpp?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/source/Symbol/SymbolContext.cpp (original)
> +++ lldb/trunk/source/Symbol/SymbolContext.cpp Tue Apr  2 21:00:15 2013
> @@ -1056,6 +1056,17 @@ SymbolContextList::GetContextAtIndex(siz
> }
> 
> 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())
> 
> Modified: lldb/trunk/source/Symbol/Symtab.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/Symtab.cpp?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/source/Symbol/Symtab.cpp (original)
> +++ lldb/trunk/source/Symbol/Symtab.cpp Tue Apr  2 21:00:15 2013
> @@ -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
>     // 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
>         {
>             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 Const
> {
>     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 Const
>         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))
>             {
> 
> Modified: lldb/trunk/source/Target/CPPLanguageRuntime.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/CPPLanguageRuntime.cpp?rev=178608&r1=178607&r2=178608&view=diff
> ==============================================================================
> --- lldb/trunk/source/Target/CPPLanguageRuntime.cpp (original)
> +++ lldb/trunk/source/Target/CPPLanguageRuntime.cpp Tue Apr  2 21:00:15 2013
> @@ -190,65 +190,65 @@ CPPLanguageRuntime::IsCPPMangledName (co
> 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(
> 
>     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;
> +}
> +
> 
> 
> _______________________________________________
> lldb-commits mailing list
> lldb-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits





More information about the lldb-commits mailing list