Handle stepping through a trampoline where the jump target is calculated a runtime - and so doesn't match

the name of the PLT entry.  This solution assumes a naming convention agreed upon by us and the system folks,
and isn't general.  The general solution requires actually finding & calling the resolver function if it
hasn't been called yet.  That's more tricky.

llvm-svn: 144981
This commit is contained in:
Jim Ingham 2011-11-19 00:19:25 +00:00
parent 6dc4c16417
commit 9683ff1211
5 changed files with 149 additions and 31 deletions

View File

@ -296,8 +296,15 @@ public:
size_t
FindSymbolsWithNameAndType (const ConstString &name,
lldb::SymbolType symbol_type,
SymbolContextList &sc_list);
SymbolContextList &sc_list,
bool append = false);
size_t
FindSymbolsMatchingRegExAndType (const RegularExpression &regex,
lldb::SymbolType symbol_type,
SymbolContextList &sc_list,
bool append = false);
//------------------------------------------------------------------
/// Find types by name.
///

View File

@ -142,6 +142,31 @@ public:
GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0;
//------------------------------------------------------------------
/// Some dynamic loaders provide features where there are a group of symbols "equivalent to"
/// a given symbol one of which will be chosen when the symbol is bound. If you want to
/// set a breakpoint on one of these symbols, you really need to set it on all the
/// equivalent symbols.
///
///
/// @param[in] original_symbol
/// The symbol for which we are finding equivalences.
///
/// @param[in] module_list
/// The set of modules in which to search.
///
/// @param[out] equivalent_symbols
/// The equivalent symbol list - any equivalent symbols found are appended to this list.
///
/// @return
/// Number of equivalent symbols found.
//------------------------------------------------------------------
virtual size_t
FindEquivalentSymbols (Symbol *original_symbol, ModuleList &module_list, SymbolContextList &equivalent_symbols)
{
return 0;
}
//------------------------------------------------------------------
/// Ask if it is ok to try and load or unload an shared library
/// (image).

View File

@ -248,14 +248,35 @@ ModuleList::FindGlobalVariables (const RegularExpression& regex,
size_t
ModuleList::FindSymbolsWithNameAndType (const ConstString &name,
SymbolType symbol_type,
SymbolContextList &sc_list)
SymbolContextList &sc_list,
bool append)
{
Mutex::Locker locker(m_modules_mutex);
sc_list.Clear();
if (!append)
sc_list.Clear();
size_t initial_size = sc_list.GetSize();
collection::iterator pos, end = m_modules.end();
for (pos = m_modules.begin(); pos != end; ++pos)
(*pos)->FindSymbolsWithNameAndType (name, symbol_type, sc_list);
return sc_list.GetSize();
return sc_list.GetSize() - initial_size;
}
size_t
ModuleList::FindSymbolsMatchingRegExAndType (const RegularExpression &regex,
lldb::SymbolType symbol_type,
SymbolContextList &sc_list,
bool append)
{
Mutex::Locker locker(m_modules_mutex);
if (!append)
sc_list.Clear();
size_t initial_size = sc_list.GetSize();
collection::iterator pos, end = m_modules.end();
for (pos = m_modules.begin(); pos != end; ++pos)
(*pos)->FindSymbolsMatchingRegExAndType (regex, symbol_type, sc_list);
return sc_list.GetSize() - initial_size;
}
class ModuleMatches

View File

@ -1423,6 +1423,14 @@ DynamicLoaderMacOSXDYLD::PrivateProcessStateChanged (Process *process, StateType
}
}
// This bit in the n_desc field of the mach file means that this is a
// stub that runs arbitrary code to determine the trampoline target.
// We've established a naming convention with the CoreOS folks for the
// equivalent symbols they will use for this (which the objc guys didn't follow...)
// For now we'll just look for all symbols matching that naming convention...
#define MACH_O_N_SYMBOL_RESOLVER 0x100
ThreadPlanSP
DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
{
@ -1442,46 +1450,75 @@ DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop
{
SymbolContextList target_symbols;
ModuleList &images = thread.GetProcess().GetTarget().GetImages();
images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, target_symbols);
// FIXME - Make the Run to Address take multiple addresses, and
// run to any of them.
uint32_t num_symbols = target_symbols.GetSize();
if (num_symbols == 1)
size_t num_original_symbols = target_symbols.GetSize();
bool orig_is_resolver = (current_symbol->GetFlags() & MACH_O_N_SYMBOL_RESOLVER) == MACH_O_N_SYMBOL_RESOLVER;
if (num_original_symbols > 0)
{
SymbolContext context;
AddressRange addr_range;
if (target_symbols.GetContextAtIndex(0, context))
// We found symbols that look like they are the targets to our symbol. Now look through the
// modules containing our symbols to see if there are any for our symbol.
ModuleList modules_to_search;
for (size_t i = 0; i < num_original_symbols; i++)
{
context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range);
thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, addr_range.GetBaseAddress(), stop_others));
SymbolContext sc;
target_symbols.GetContextAtIndex(i, sc);
Module* module_to_add = sc.symbol->CalculateSymbolContextModule();
if (module_to_add)
modules_to_search.AppendIfNeeded(static_cast<ModuleSP>(module_to_add));
}
else
// If the original stub symbol is a resolver, then we don't want to break on the symbol with the
// original name, but instead on all the symbols it could resolve to since otherwise we would stop
// in the middle of the resolution...
// Note that the stub is not of the resolver type it will point to the equivalent symbol,
// not the original name, so in that case we don't need to do anything.
if (orig_is_resolver)
{
if (log)
log->Printf ("Couldn't resolve the symbol context.");
target_symbols.Clear();
FindEquivalentSymbols (current_symbol, modules_to_search, target_symbols);
}
}
else if (num_symbols > 1)
{
std::vector<lldb::addr_t> addresses;
addresses.resize (num_symbols);
for (uint32_t i = 0; i < num_symbols; i++)
// FIXME - Make the Run to Address take multiple addresses, and
// run to any of them.
uint32_t num_symbols = target_symbols.GetSize();
if (num_symbols > 0)
{
SymbolContext context;
AddressRange addr_range;
if (target_symbols.GetContextAtIndex(i, context))
std::vector<lldb::addr_t> addresses;
addresses.resize (num_symbols);
for (uint32_t i = 0; i < num_symbols; i++)
{
context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range);
lldb::addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(&thread.GetProcess().GetTarget());
addresses[i] = load_addr;
SymbolContext context;
AddressRange addr_range;
if (target_symbols.GetContextAtIndex(i, context))
{
context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range);
lldb::addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(&thread.GetProcess().GetTarget());
addresses[i] = load_addr;
}
}
if (addresses.size() > 0)
thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, addresses, stop_others));
else
{
if (log)
log->Printf ("Couldn't resolve the symbol contexts.");
}
}
if (addresses.size() > 0)
thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, addresses, stop_others));
else
{
if (log)
log->Printf ("Couldn't resolve the symbol contexts.");
{
log->Printf ("Found a resolver stub for: \"%s\" but could not find any symbols it resolves to.",
trampoline_name.AsCString());
}
}
}
else
@ -1503,6 +1540,29 @@ DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop
return thread_plan_sp;
}
size_t
DynamicLoaderMacOSXDYLD::FindEquivalentSymbols (lldb_private::Symbol *original_symbol,
lldb_private::ModuleList &images,
lldb_private::SymbolContextList &equivalent_symbols)
{
const ConstString &trampoline_name = original_symbol->GetMangled().GetName(Mangled::ePreferMangled);
if (!trampoline_name)
return 0;
size_t initial_size = equivalent_symbols.GetSize();
static const char *resolver_name_regex = "(_gc|_non_gc|\\$[A-Z0-9]+)$";
std::string equivalent_regex_buf("^");
equivalent_regex_buf.append (trampoline_name.GetCString());
equivalent_regex_buf.append (resolver_name_regex);
RegularExpression equivalent_name_regex (equivalent_regex_buf.c_str());
const bool append = true;
images.FindSymbolsMatchingRegExAndType (equivalent_name_regex, eSymbolTypeCode, equivalent_symbols, append);
return equivalent_symbols.GetSize() - initial_size;
}
Error
DynamicLoaderMacOSXDYLD::CanLoadImage ()
{

View File

@ -66,6 +66,11 @@ public:
GetStepThroughTrampolinePlan (lldb_private::Thread &thread,
bool stop_others);
virtual size_t
FindEquivalentSymbols (lldb_private::Symbol *original_symbol,
lldb_private::ModuleList &module_list,
lldb_private::SymbolContextList &equivalent_symbols);
virtual lldb_private::Error
CanLoadImage ();