forked from OSchip/llvm-project
<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. llvm-svn: 178608
This commit is contained in:
parent
1786cb2f01
commit
43fe217b11
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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() - start_size;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
return 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
|
||||
{
|
||||
|
||||
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
|
||||
|
|
|
@ -3116,7 +3116,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
|
|||
// instance methods for eFunctionNameTypeBase.
|
||||
|
||||
target->GetImages().FindFunctions(name,
|
||||
eFunctionNameTypeBase,
|
||||
eFunctionNameTypeFull,
|
||||
include_symbols,
|
||||
include_inlines,
|
||||
append,
|
||||
|
|
|
@ -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 ()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
|
||||
continue;
|
||||
|
||||
ResolveFunction (dwarf_cu, die, sc_list);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
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 (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)
|
||||
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 (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);
|
||||
if (resolved_dies.find(die) == resolved_dies.end())
|
||||
{
|
||||
if (ResolveFunction (dwarf_cu, die, sc_list))
|
||||
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()->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);
|
||||
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1055,6 +1055,17 @@ SymbolContextList::GetContextAtIndex(size_t idx, SymbolContext& sc) const
|
|||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue