Get the breakpoint setting, and the Mac OS X DYLD trampolines and expression evaluator to handle Indirect

symbols correctly.  There were a couple of pieces to this.

1) When a breakpoint location finds itself pointing to an Indirect symbol, when the site for it is created
   it needs to resolve the symbol and actually set the site at its target.
2) Not all breakpoints want to do this (i.e. a straight address breakpoint should always set itself on the
   specified address, so somem machinery was needed to specify that.
3) I added some info to the break list output for indirect symbols so you could see what was happening. 
   Also I made it clear when we re-route through re-exported symbols.
4) I moved ResolveIndirectFunction from ProcessPosix to Process since it works the exact same way on Mac OS X
   and the other posix systems.  If we find a platform that doesn't do it this way, they can override the
   call in Process.
5) Fixed one bug in RunThreadPlan, if you were trying to run a thread plan after a "running" event had
   been broadcast, the event coalescing would cause you to miss the ThreadPlan running event.  So I added
   a way to override the coalescing.
6) Made DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan handle Indirect & Re-exported symbols.

<rdar://problem/15280639>

llvm-svn: 198976
This commit is contained in:
Jim Ingham 2014-01-10 23:46:59 +00:00
parent 87c2b0400d
commit 1460e4bf0e
18 changed files with 441 additions and 186 deletions

View File

@ -612,12 +612,30 @@ protected:
/// Only the Target can make a breakpoint, and it owns the breakpoint lifespans. /// Only the Target can make a breakpoint, and it owns the breakpoint lifespans.
/// The constructor takes a filter and a resolver. Up in Target there are convenience /// The constructor takes a filter and a resolver. Up in Target there are convenience
/// variants that make breakpoints for some common cases. /// variants that make breakpoints for some common cases.
///
/// @param[in] target
/// The target in which the breakpoint will be set.
///
/// @param[in] filter_sp
/// Shared pointer to the search filter that restricts the search domain of the breakpoint.
///
/// @param[in] resolver_sp
/// Shared pointer to the resolver object that will determine breakpoint matches.
///
/// @param hardware
/// If true, request a hardware breakpoint to be used to implement the breakpoint locations.
///
/// @param resolve_indirect_symbols
/// If true, and the address of a given breakpoint location in this breakpoint is set on an
/// indirect symbol (i.e. Symbol::IsIndirect returns true) then the actual breakpoint site will
/// be set on the target of the indirect symbol.
//------------------------------------------------------------------ //------------------------------------------------------------------
// This is the generic constructor // This is the generic constructor
Breakpoint(Target &target, Breakpoint(Target &target,
lldb::SearchFilterSP &filter_sp, lldb::SearchFilterSP &filter_sp,
lldb::BreakpointResolverSP &resolver_sp, lldb::BreakpointResolverSP &resolver_sp,
bool hardware); bool hardware,
bool resolve_indirect_symbols = true);
friend class BreakpointLocation; // To call the following two when determining whether to stop. friend class BreakpointLocation; // To call the following two when determining whether to stop.
@ -643,6 +661,7 @@ private:
BreakpointOptions m_options; // Settable breakpoint options BreakpointOptions m_options; // Settable breakpoint options
BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint. BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint.
std::string m_kind_description; std::string m_kind_description;
bool m_resolve_indirect_symbols;
void void
SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind); SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind);

View File

@ -321,7 +321,59 @@ public:
//------------------------------------------------------------------ //------------------------------------------------------------------
bool bool
InvokeCallback (StoppointCallbackContext *context); InvokeCallback (StoppointCallbackContext *context);
//------------------------------------------------------------------
/// Returns whether we should resolve Indirect functions in setting the breakpoint site
/// for this location.
///
/// @return
/// \b true if the breakpoint SITE for this location should be set on the
/// resolved location for Indirect functions.
//------------------------------------------------------------------
bool
ShouldResolveIndirectFunctions ()
{
return m_should_resolve_indirect_functions;
}
//------------------------------------------------------------------
/// Returns whether the address set in the breakpoint site for this location was found by resolving
/// an indirect symbol.
///
/// @return
/// \b true or \b false as given in the description above.
//------------------------------------------------------------------
bool
IsIndirect ()
{
return m_is_indirect;
}
void
SetIsIndirect (bool is_indirect)
{
m_is_indirect = is_indirect;
}
//------------------------------------------------------------------
/// Returns whether the address set in the breakpoint location was re-routed to the target of a
/// re-exported symbol.
///
/// @return
/// \b true or \b false as given in the description above.
//------------------------------------------------------------------
bool
IsReExported ()
{
return m_is_reexported;
}
void
SetIsReExported (bool is_reexported)
{
m_is_reexported = is_reexported;
}
protected: protected:
friend class BreakpointLocationList; friend class BreakpointLocationList;
friend class Process; friend class Process;
@ -375,12 +427,16 @@ private:
Breakpoint &owner, Breakpoint &owner,
const Address &addr, const Address &addr,
lldb::tid_t tid, lldb::tid_t tid,
bool hardware); bool hardware,
bool check_for_resolver = true);
//------------------------------------------------------------------ //------------------------------------------------------------------
// Data members: // Data members:
//------------------------------------------------------------------ //------------------------------------------------------------------
bool m_being_created; bool m_being_created;
bool m_should_resolve_indirect_functions;
bool m_is_reexported;
bool m_is_indirect;
Address m_address; ///< The address defining this location. Address m_address; ///< The address defining this location.
Breakpoint &m_owner; ///< The breakpoint that produced this object. Breakpoint &m_owner; ///< The breakpoint that produced this object.
std::unique_ptr<BreakpointOptions> m_options_ap; ///< Breakpoint options pointer, NULL if we're using our breakpoint's options. std::unique_ptr<BreakpointOptions> m_options_ap; ///< Breakpoint options pointer, NULL if we're using our breakpoint's options.
@ -389,6 +445,12 @@ private:
Mutex m_condition_mutex; ///< Guards parsing and evaluation of the condition, which could be evaluated by multiple processes. Mutex m_condition_mutex; ///< Guards parsing and evaluation of the condition, which could be evaluated by multiple processes.
size_t m_condition_hash; ///< For testing whether the condition source code changed. size_t m_condition_hash; ///< For testing whether the condition source code changed.
void
SetShouldResolveIndirectFunctions (bool do_resolve)
{
m_should_resolve_indirect_functions = do_resolve;
}
void void
SendBreakpointLocationChangedEvent (lldb::BreakpointEventType eventKind); SendBreakpointLocationChangedEvent (lldb::BreakpointEventType eventKind);

View File

@ -236,7 +236,7 @@ protected:
/// Returns breakpoint location id. /// Returns breakpoint location id.
//------------------------------------------------------------------ //------------------------------------------------------------------
lldb::BreakpointLocationSP lldb::BreakpointLocationSP
Create (const Address &addr); Create (const Address &addr, bool resolve_indirect_symbols);
void void
StartRecordingNewLocations(BreakpointLocationCollection &new_locations); StartRecordingNewLocations(BreakpointLocationCollection &new_locations);
@ -246,6 +246,7 @@ protected:
lldb::BreakpointLocationSP lldb::BreakpointLocationSP
AddLocation (const Address &addr, AddLocation (const Address &addr,
bool resolve_indirect_symbols,
bool *new_location = NULL); bool *new_location = NULL);
bool bool

View File

@ -2986,11 +2986,7 @@ public:
//------------------------------------------------------------------ //------------------------------------------------------------------
virtual lldb::addr_t virtual lldb::addr_t
ResolveIndirectFunction(const Address *address, Error &error) ResolveIndirectFunction(const Address *address, Error &error);
{
error.SetErrorStringWithFormat("error: %s does not support indirect functions in the debug process", GetPluginName().GetCString());
return LLDB_INVALID_ADDRESS;
}
virtual Error virtual Error
GetMemoryRegionInfo (lldb::addr_t load_addr, GetMemoryRegionInfo (lldb::addr_t load_addr,
@ -3670,6 +3666,12 @@ protected:
{ {
return IS_VALID_LLDB_HOST_THREAD(m_private_state_thread); return IS_VALID_LLDB_HOST_THREAD(m_private_state_thread);
} }
void
ForceNextEventDelivery()
{
m_force_next_event_delivery = true;
}
//------------------------------------------------------------------ //------------------------------------------------------------------
// Type definitions // Type definitions
@ -3744,7 +3746,9 @@ protected:
bool m_resume_requested; // If m_currently_handling_event or m_currently_handling_do_on_removals are true, Resume will only request a resume, using this flag to check. bool m_resume_requested; // If m_currently_handling_event or m_currently_handling_do_on_removals are true, Resume will only request a resume, using this flag to check.
bool m_finalize_called; bool m_finalize_called;
bool m_clear_thread_plans_on_stop; bool m_clear_thread_plans_on_stop;
bool m_force_next_event_delivery;
lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent. lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent.
std::map<lldb::addr_t,lldb::addr_t> m_resolved_indirect_addresses;
bool m_destroy_in_process; bool m_destroy_in_process;
enum { enum {

View File

@ -637,7 +637,8 @@ public:
CreateBreakpoint (lldb::SearchFilterSP &filter_sp, CreateBreakpoint (lldb::SearchFilterSP &filter_sp,
lldb::BreakpointResolverSP &resolver_sp, lldb::BreakpointResolverSP &resolver_sp,
bool internal, bool internal,
bool request_hardware); bool request_hardware,
bool resolve_indirect_symbols);
// Use this to create a watchpoint: // Use this to create a watchpoint:
lldb::WatchpointSP lldb::WatchpointSP

View File

@ -45,14 +45,19 @@ Breakpoint::GetEventIdentifier ()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// Breakpoint constructor // Breakpoint constructor
//---------------------------------------------------------------------- //----------------------------------------------------------------------
Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool hardware) : Breakpoint::Breakpoint(Target &target,
SearchFilterSP &filter_sp,
BreakpointResolverSP &resolver_sp,
bool hardware,
bool resolve_indirect_symbols) :
m_being_created(true), m_being_created(true),
m_hardware(hardware), m_hardware(hardware),
m_target (target), m_target (target),
m_filter_sp (filter_sp), m_filter_sp (filter_sp),
m_resolver_sp (resolver_sp), m_resolver_sp (resolver_sp),
m_options (), m_options (),
m_locations (*this) m_locations (*this),
m_resolve_indirect_symbols(resolve_indirect_symbols)
{ {
m_being_created = false; m_being_created = false;
} }
@ -87,7 +92,7 @@ Breakpoint::GetTarget () const
BreakpointLocationSP BreakpointLocationSP
Breakpoint::AddLocation (const Address &addr, bool *new_location) Breakpoint::AddLocation (const Address &addr, bool *new_location)
{ {
return m_locations.AddLocation (addr, new_location); return m_locations.AddLocation (addr, m_resolve_indirect_symbols, new_location);
} }
BreakpointLocationSP BreakpointLocationSP

View File

@ -39,16 +39,29 @@ BreakpointLocation::BreakpointLocation
Breakpoint &owner, Breakpoint &owner,
const Address &addr, const Address &addr,
lldb::tid_t tid, lldb::tid_t tid,
bool hardware bool hardware,
bool check_for_resolver
) : ) :
StoppointLocation (loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()), hardware), StoppointLocation (loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()), hardware),
m_being_created(true), m_being_created(true),
m_should_resolve_indirect_functions (false),
m_is_reexported (false),
m_is_indirect (false),
m_address (addr), m_address (addr),
m_owner (owner), m_owner (owner),
m_options_ap (), m_options_ap (),
m_bp_site_sp (), m_bp_site_sp (),
m_condition_mutex () m_condition_mutex ()
{ {
if (check_for_resolver)
{
Symbol *symbol = m_address.CalculateSymbolContextSymbol();
if (symbol && symbol->IsIndirect())
{
SetShouldResolveIndirectFunctions (true);
}
}
SetThreadID (tid); SetThreadID (tid);
m_being_created = false; m_being_created = false;
} }
@ -545,7 +558,10 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
if (level == lldb::eDescriptionLevelFull || level == eDescriptionLevelInitial) if (level == lldb::eDescriptionLevelFull || level == eDescriptionLevelInitial)
{ {
s->PutCString("where = "); if (IsReExported())
s->PutCString ("re-exported target = ");
else
s->PutCString("where = ");
sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false); sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false);
} }
else else
@ -584,7 +600,10 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
if (sc.symbol) if (sc.symbol)
{ {
s->EOL(); s->EOL();
s->Indent("symbol = "); if (IsReExported())
s->Indent ("re-exported target = ");
else
s->Indent("symbol = ");
s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>")); s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>"));
} }
} }
@ -612,6 +631,24 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
else else
m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress); m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
if (IsIndirect() && m_bp_site_sp)
{
Address resolved_address;
resolved_address.SetLoadAddress(m_bp_site_sp->GetLoadAddress(), target);
Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol();
if (resolved_symbol)
{
if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial)
s->Printf (", ");
else if (level == lldb::eDescriptionLevelVerbose)
{
s->EOL();
s->Indent();
}
s->Printf ("indirect target = %s", resolved_symbol->GetName().GetCString());
}
}
if (level == lldb::eDescriptionLevelVerbose) if (level == lldb::eDescriptionLevelVerbose)
{ {

View File

@ -41,12 +41,12 @@ BreakpointLocationList::~BreakpointLocationList()
} }
BreakpointLocationSP BreakpointLocationSP
BreakpointLocationList::Create (const Address &addr) BreakpointLocationList::Create (const Address &addr, bool resolve_indirect_symbols)
{ {
Mutex::Locker locker (m_mutex); Mutex::Locker locker (m_mutex);
// The location ID is just the size of the location list + 1 // The location ID is just the size of the location list + 1
lldb::break_id_t bp_loc_id = ++m_next_id; lldb::break_id_t bp_loc_id = ++m_next_id;
BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, m_owner.IsHardware())); BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, m_owner.IsHardware(), resolve_indirect_symbols));
m_locations.push_back (bp_loc_sp); m_locations.push_back (bp_loc_sp);
m_address_to_location[addr] = bp_loc_sp; m_address_to_location[addr] = bp_loc_sp;
return bp_loc_sp; return bp_loc_sp;
@ -247,7 +247,7 @@ BreakpointLocationList::GetDescription (Stream *s, lldb::DescriptionLevel level)
} }
BreakpointLocationSP BreakpointLocationSP
BreakpointLocationList::AddLocation (const Address &addr, bool *new_location) BreakpointLocationList::AddLocation (const Address &addr, bool resolve_indirect_symbols, bool *new_location)
{ {
Mutex::Locker locker (m_mutex); Mutex::Locker locker (m_mutex);
@ -256,7 +256,7 @@ BreakpointLocationList::AddLocation (const Address &addr, bool *new_location)
BreakpointLocationSP bp_loc_sp (FindByAddress(addr)); BreakpointLocationSP bp_loc_sp (FindByAddress(addr));
if (!bp_loc_sp) if (!bp_loc_sp)
{ {
bp_loc_sp = Create (addr); bp_loc_sp = Create (addr, resolve_indirect_symbols);
if (bp_loc_sp) if (bp_loc_sp)
{ {
bp_loc_sp->ResolveBreakpointSite(); bp_loc_sp->ResolveBreakpointSite();

View File

@ -272,6 +272,8 @@ BreakpointResolverName::SearchCallback
{ {
if (func_list.GetContextAtIndex(i, sc)) if (func_list.GetContextAtIndex(i, sc))
{ {
bool is_reexported = false;
if (sc.block && sc.block->GetInlinedFunctionInfo()) if (sc.block && sc.block->GetInlinedFunctionInfo())
{ {
if (!sc.block->GetStartAddress(break_addr)) if (!sc.block->GetStartAddress(break_addr))
@ -293,7 +295,10 @@ BreakpointResolverName::SearchCallback
{ {
const Symbol *actual_symbol = sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget()); const Symbol *actual_symbol = sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget());
if (actual_symbol) if (actual_symbol)
{
is_reexported = true;
break_addr = actual_symbol->GetAddress(); break_addr = actual_symbol->GetAddress();
}
} }
else else
{ {
@ -313,6 +318,7 @@ BreakpointResolverName::SearchCallback
if (filter.AddressPasses(break_addr)) if (filter.AddressPasses(break_addr))
{ {
BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location)); BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
bp_loc_sp->SetIsReExported(is_reexported);
if (bp_loc_sp && new_location && !m_breakpoint->IsInternal()) if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
{ {
if (log) if (log)

View File

@ -328,15 +328,27 @@ Address::GetLoadAddress (Target *target) const
addr_t addr_t
Address::GetCallableLoadAddress (Target *target, bool is_indirect) const Address::GetCallableLoadAddress (Target *target, bool is_indirect) const
{ {
if (is_indirect && target) { addr_t code_addr = LLDB_INVALID_ADDRESS;
if (is_indirect && target)
{
ProcessSP processSP = target->GetProcessSP(); ProcessSP processSP = target->GetProcessSP();
Error error; Error error;
if (processSP.get()) if (processSP.get())
return processSP->ResolveIndirectFunction(this, error); {
code_addr = processSP->ResolveIndirectFunction(this, error);
if (!error.Success())
code_addr = LLDB_INVALID_ADDRESS;
}
} }
else
addr_t code_addr = GetLoadAddress (target); {
code_addr = GetLoadAddress (target);
}
if (code_addr == LLDB_INVALID_ADDRESS)
return code_addr;
if (target) if (target)
return target->GetCallableLoadAddress (code_addr, GetAddressClass()); return target->GetCallableLoadAddress (code_addr, GetAddressClass());
return code_addr; return code_addr;

View File

@ -1596,14 +1596,6 @@ 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 ThreadPlanSP
DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
{ {
@ -1612,104 +1604,123 @@ DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop
const SymbolContext &current_context = current_frame->GetSymbolContext(eSymbolContextSymbol); const SymbolContext &current_context = current_frame->GetSymbolContext(eSymbolContextSymbol);
Symbol *current_symbol = current_context.symbol; Symbol *current_symbol = current_context.symbol;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
TargetSP target_sp (thread.CalculateTarget());
if (current_symbol != NULL) if (current_symbol != NULL)
{ {
std::vector<Address> addresses;
if (current_symbol->IsTrampoline()) if (current_symbol->IsTrampoline())
{ {
const ConstString &trampoline_name = current_symbol->GetMangled().GetName(Mangled::ePreferMangled); const ConstString &trampoline_name = current_symbol->GetMangled().GetName(Mangled::ePreferMangled);
if (trampoline_name) if (trampoline_name)
{ {
SymbolContextList target_symbols;
TargetSP target_sp (thread.CalculateTarget());
const ModuleList &images = target_sp->GetImages(); const ModuleList &images = target_sp->GetImages();
images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, target_symbols); SymbolContextList code_symbols;
images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, code_symbols);
size_t num_original_symbols = target_symbols.GetSize(); size_t num_code_symbols = code_symbols.GetSize();
// FIXME: The resolver symbol is only valid in object files. In binaries it is reused for the
// shared library slot number. So we'll have to look this up in the dyld info.
// For now, just turn this off.
// bool orig_is_resolver = (current_symbol->GetFlags() & MACH_O_N_SYMBOL_RESOLVER) == MACH_O_N_SYMBOL_RESOLVER; if (num_code_symbols > 0)
// FIXME: Actually that isn't true, the N_SYMBOL_RESOLVER bit is only valid in .o files. You can't use
// the symbol flags to tell whether something is a symbol resolver in a linked image.
bool orig_is_resolver = false;
if (num_original_symbols > 0)
{ {
// We found symbols that look like they are the targets to our symbol. Now look through the for (uint32_t i = 0; i < num_code_symbols; i++)
// 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++)
{ {
SymbolContext sc; SymbolContext context;
target_symbols.GetContextAtIndex(i, sc); AddressRange addr_range;
if (code_symbols.GetContextAtIndex(i, context))
ModuleSP module_sp (sc.symbol->CalculateSymbolContextModule());
if (module_sp)
modules_to_search.AppendIfNeeded(module_sp);
}
// 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)
{
target_symbols.Clear();
FindEquivalentSymbols (current_symbol, modules_to_search, 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 > 0)
{
std::vector<lldb::addr_t> addresses;
addresses.resize (num_symbols);
for (uint32_t i = 0; i < num_symbols; i++)
{ {
SymbolContext context; context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range);
AddressRange addr_range; addresses.push_back(addr_range.GetBaseAddress());
if (target_symbols.GetContextAtIndex(i, context)) if (log)
{ {
context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range); addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(target_sp.get());
lldb::addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(target_sp.get());
addresses[i] = load_addr; log->Printf ("Found a trampoline target symbol at 0x%" PRIx64 ".", load_addr);
} }
} }
if (addresses.size() > 0) }
thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, addresses, stop_others)); }
else
SymbolContextList reexported_symbols;
images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeReExported, reexported_symbols);
size_t num_reexported_symbols = reexported_symbols.GetSize();
if (num_reexported_symbols > 0)
{
for (uint32_t i = 0; i < num_reexported_symbols; i++)
{
SymbolContext context;
if (reexported_symbols.GetContextAtIndex(i, context))
{ {
if (log) if (context.symbol)
log->Printf ("Couldn't resolve the symbol contexts."); {
Symbol *actual_symbol = context.symbol->ResolveReExportedSymbol(*target_sp.get());
if (actual_symbol)
{
if (actual_symbol->GetAddress().IsValid())
{
addresses.push_back(actual_symbol->GetAddress());
if (log)
{
lldb::addr_t load_addr = actual_symbol->GetAddress().GetLoadAddress(target_sp.get());
log->Printf ("Found a re-exported symbol: %s at 0x%" PRIx64 ".",
actual_symbol->GetName().GetCString(), load_addr);
}
}
}
}
} }
} }
else }
}
}
else if (current_symbol->GetType() == eSymbolTypeReExported)
{
// I am not sure we could ever end up stopped AT a re-exported symbol. But just in case:
const Symbol *actual_symbol = current_symbol->ResolveReExportedSymbol(*(target_sp.get()));
if (actual_symbol)
{
Address target_addr(actual_symbol->GetAddress());
if (target_addr.IsValid())
{
if (log)
log->Printf ("Found a re-exported symbol: %s pointing to: %s at 0x%" PRIx64 ".",
current_symbol->GetName().GetCString(),
actual_symbol->GetName().GetCString(),
target_addr.GetLoadAddress(target_sp.get()));
addresses.push_back (target_addr.GetLoadAddress(target_sp.get()));
}
}
}
if (addresses.size() > 0)
{
// First check whether any of the addresses point to Indirect symbols, and if they do, resolve them:
std::vector<lldb::addr_t> load_addrs;
for (Address address : addresses)
{
Symbol *symbol = address.CalculateSymbolContextSymbol();
if (symbol && symbol->IsIndirect())
{
Error error;
addr_t resolved_addr = thread.GetProcess()->ResolveIndirectFunction(&symbol->GetAddress(), error);
if (error.Success())
{ {
load_addrs.push_back(resolved_addr);
if (log) if (log)
{ log->Printf("ResolveIndirectFunction found resolved target for %s at 0x%" PRIx64 ".",
log->Printf ("Found a resolver stub for: \"%s\" but could not find any symbols it resolves to.", symbol->GetName().GetCString(), resolved_addr);
trampoline_name.AsCString());
}
} }
} }
else else
{ {
if (log) load_addrs.push_back(address.GetLoadAddress(target_sp.get()));
{
log->Printf ("Could not find symbol for trampoline target: \"%s\"", trampoline_name.AsCString());
}
} }
} }
thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, load_addrs, stop_others));
} }
} }
else else
@ -1732,7 +1743,7 @@ DynamicLoaderMacOSXDYLD::FindEquivalentSymbols (lldb_private::Symbol *original_s
size_t initial_size = equivalent_symbols.GetSize(); size_t initial_size = equivalent_symbols.GetSize();
static const char *resolver_name_regex = "(_gc|_non_gc|\\$[A-Z0-9]+)$"; static const char *resolver_name_regex = "(_gc|_non_gc|\\$[A-Za-z0-9\\$]+)$";
std::string equivalent_regex_buf("^"); std::string equivalent_regex_buf("^");
equivalent_regex_buf.append (trampoline_name.GetCString()); equivalent_regex_buf.append (trampoline_name.GetCString());
equivalent_regex_buf.append (resolver_name_regex); equivalent_regex_buf.append (resolver_name_regex);

View File

@ -403,7 +403,9 @@ ItaniumABILanguageRuntime::CreateExceptionBreakpoint (bool catch_bp,
FileSpecList filter_modules; FileSpecList filter_modules;
BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions); BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions);
SearchFilterSP filter_sp (CreateExceptionSearchFilter ()); SearchFilterSP filter_sp (CreateExceptionSearchFilter ());
return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, false); const bool hardware = false;
const bool resolve_indirect_functions = false;
return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, hardware, resolve_indirect_functions);
} }
void void

View File

@ -632,20 +632,6 @@ ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr)
return error; return error;
} }
addr_t
ProcessPOSIX::ResolveIndirectFunction(const Address *address, Error &error)
{
addr_t function_addr = LLDB_INVALID_ADDRESS;
if (address == NULL) {
error.SetErrorStringWithFormat("unable to determine direct function call for NULL address");
} else if (!InferiorCall(this, address, function_addr)) {
function_addr = LLDB_INVALID_ADDRESS;
error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s",
address->CalculateSymbolContextSymbol()->GetName().AsCString());
}
return function_addr;
}
size_t size_t
ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
{ {

View File

@ -104,9 +104,6 @@ public:
virtual lldb_private::Error virtual lldb_private::Error
DoDeallocateMemory(lldb::addr_t ptr); DoDeallocateMemory(lldb::addr_t ptr);
virtual lldb::addr_t
ResolveIndirectFunction(const lldb_private::Address *address, lldb_private::Error &error);
virtual size_t virtual size_t
GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site);

View File

@ -34,9 +34,16 @@
using namespace lldb; using namespace lldb;
using namespace lldb_private; using namespace lldb_private;
bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, bool
addr_t addr, addr_t length, unsigned prot, lldb_private::InferiorCallMmap (Process *process,
unsigned flags, addr_t fd, addr_t offset) { addr_t &allocated_addr,
addr_t addr,
addr_t length,
unsigned prot,
unsigned flags,
addr_t fd,
addr_t offset)
{
Thread *thread = process->GetThreadList().GetSelectedThread().get(); Thread *thread = process->GetThreadList().GetSelectedThread().get();
if (thread == NULL) if (thread == NULL)
return false; return false;
@ -139,8 +146,11 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
return false; return false;
} }
bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, bool
addr_t length) { lldb_private::InferiorCallMunmap (Process *process,
addr_t addr,
addr_t length)
{
Thread *thread = process->GetThreadList().GetSelectedThread().get(); Thread *thread = process->GetThreadList().GetSelectedThread().get();
if (thread == NULL) if (thread == NULL)
return false; return false;
@ -209,7 +219,14 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
return false; return false;
} }
bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) { // FIXME: This has nothing to do with Posix, it is just a convenience function that calls a
// function of the form "void * (*)(void)". We should find a better place to put this.
bool
lldb_private::InferiorCall (Process *process,
const Address *address,
addr_t &returned_func)
{
Thread *thread = process->GetThreadList().GetSelectedThread().get(); Thread *thread = process->GetThreadList().GetSelectedThread().get();
if (thread == NULL || address == NULL) if (thread == NULL || address == NULL)
return false; return false;
@ -233,7 +250,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t
lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
if (call_plan_sp) if (call_plan_sp)
{ {
StreamFile error_strm; StreamString error_strm;
// This plan is a utility plan, so set it to discard itself when done. // This plan is a utility plan, so set it to discard itself when done.
call_plan_sp->SetIsMasterPlan (true); call_plan_sp->SetIsMasterPlan (true);
call_plan_sp->SetOkayToDiscard(true); call_plan_sp->SetOkayToDiscard(true);

View File

@ -269,7 +269,8 @@ LanguageRuntime::CreateExceptionBreakpoint (Target &target,
BreakpointResolverSP resolver_sp(new ExceptionBreakpointResolver(language, catch_bp, throw_bp)); BreakpointResolverSP resolver_sp(new ExceptionBreakpointResolver(language, catch_bp, throw_bp));
SearchFilterSP filter_sp(new ExceptionSearchFilter(target.shared_from_this(), language)); SearchFilterSP filter_sp(new ExceptionSearchFilter(target.shared_from_this(), language));
bool hardware = false; bool hardware = false;
BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware)); bool resolve_indirect_functions = false;
BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware, resolve_indirect_functions));
if (is_internal) if (is_internal)
exc_breakpt_sp->SetBreakpointKind("exception"); exc_breakpt_sp->SetBreakpointKind("exception");

View File

@ -21,6 +21,7 @@
#include "lldb/Core/InputReader.h" #include "lldb/Core/InputReader.h"
#include "lldb/Core/Log.h" #include "lldb/Core/Log.h"
#include "lldb/Core/Module.h" #include "lldb/Core/Module.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Core/PluginManager.h" #include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h" #include "lldb/Core/State.h"
#include "lldb/Expression/ClangUserExpression.h" #include "lldb/Expression/ClangUserExpression.h"
@ -41,6 +42,7 @@
#include "lldb/Target/Thread.h" #include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanBase.h" #include "lldb/Target/ThreadPlanBase.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
#ifndef LLDB_DISABLE_POSIX #ifndef LLDB_DISABLE_POSIX
#include <spawn.h> #include <spawn.h>
@ -1052,6 +1054,7 @@ Process::Process(Target &target, Listener &listener) :
m_currently_handling_event(false), m_currently_handling_event(false),
m_finalize_called(false), m_finalize_called(false),
m_clear_thread_plans_on_stop (false), m_clear_thread_plans_on_stop (false),
m_force_next_event_delivery(false),
m_last_broadcast_state (eStateInvalid), m_last_broadcast_state (eStateInvalid),
m_destroy_in_process (false), m_destroy_in_process (false),
m_can_jit(eCanJITDontKnow) m_can_jit(eCanJITDontKnow)
@ -2143,7 +2146,60 @@ Process::EnableBreakpointSiteByID (lldb::user_id_t break_id)
lldb::break_id_t lldb::break_id_t
Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardware) Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardware)
{ {
const addr_t load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target); addr_t load_addr = LLDB_INVALID_ADDRESS;
bool show_error = true;
switch (GetState())
{
case eStateInvalid:
case eStateUnloaded:
case eStateConnected:
case eStateAttaching:
case eStateLaunching:
case eStateDetached:
case eStateExited:
show_error = false;
break;
case eStateStopped:
case eStateRunning:
case eStateStepping:
case eStateCrashed:
case eStateSuspended:
show_error = IsAlive();
break;
}
// Reset the IsIndirect flag here, in case the location changes from
// pointing to a indirect symbol to a regular symbol.
owner->SetIsIndirect (false);
if (owner->ShouldResolveIndirectFunctions())
{
Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol();
if (symbol && symbol->IsIndirect())
{
Error error;
load_addr = ResolveIndirectFunction (&symbol->GetAddress(), error);
if (!error.Success() && show_error)
{
m_target.GetDebugger().GetErrorFile().Printf ("warning: failed to resolve indirect function at 0x%" PRIx64 " for breakpoint %i.%i: %s\n",
symbol->GetAddress().GetLoadAddress(&m_target),
owner->GetBreakpoint().GetID(),
owner->GetID(),
error.AsCString() ? error.AsCString() : "unkown error");
return LLDB_INVALID_BREAK_ID;
}
Address resolved_address(load_addr);
load_addr = resolved_address.GetOpcodeLoadAddress (&m_target);
owner->SetIsIndirect(true);
}
else
load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target);
}
else
load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target);
if (load_addr != LLDB_INVALID_ADDRESS) if (load_addr != LLDB_INVALID_ADDRESS)
{ {
BreakpointSiteSP bp_site_sp; BreakpointSiteSP bp_site_sp;
@ -2172,28 +2228,6 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw
} }
else else
{ {
bool show_error = true;
switch (GetState())
{
case eStateInvalid:
case eStateUnloaded:
case eStateConnected:
case eStateAttaching:
case eStateLaunching:
case eStateDetached:
case eStateExited:
show_error = false;
break;
case eStateStopped:
case eStateRunning:
case eStateStepping:
case eStateCrashed:
case eStateSuspended:
show_error = IsAlive();
break;
}
if (show_error) if (show_error)
{ {
// Report error for setting breakpoint... // Report error for setting breakpoint...
@ -3804,33 +3838,38 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
// stopped -> running: Report except when there is one or more no votes // stopped -> running: Report except when there is one or more no votes
// and no yes votes. // and no yes votes.
SynchronouslyNotifyStateChanged (state); SynchronouslyNotifyStateChanged (state);
switch (m_last_broadcast_state) if (m_force_next_event_delivery)
return_value = true;
else
{ {
case eStateRunning: switch (m_last_broadcast_state)
case eStateStepping: {
// We always suppress multiple runnings with no PUBLIC stop in between. case eStateRunning:
return_value = false; case eStateStepping:
break; // We always suppress multiple runnings with no PUBLIC stop in between.
default: return_value = false;
// TODO: make this work correctly. For now always report break;
// run if we aren't running so we don't miss any runnning default:
// events. If I run the lldb/test/thread/a.out file and // TODO: make this work correctly. For now always report
// break at main.cpp:58, run and hit the breakpoints on // run if we aren't running so we don't miss any runnning
// multiple threads, then somehow during the stepping over // events. If I run the lldb/test/thread/a.out file and
// of all breakpoints no run gets reported. // break at main.cpp:58, run and hit the breakpoints on
// multiple threads, then somehow during the stepping over
// of all breakpoints no run gets reported.
// This is a transition from stop to run. // This is a transition from stop to run.
switch (m_thread_list.ShouldReportRun (event_ptr)) switch (m_thread_list.ShouldReportRun (event_ptr))
{ {
case eVoteYes: case eVoteYes:
case eVoteNoOpinion: case eVoteNoOpinion:
return_value = true; return_value = true;
break; break;
case eVoteNo: case eVoteNo:
return_value = false; return_value = false;
break; break;
} }
break; break;
}
} }
break; break;
case eStateStopped: case eStateStopped:
@ -3903,6 +3942,9 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
break; break;
} }
// Forcing the next event delivery is a one shot deal. So reset it here.
m_force_next_event_delivery = false;
// We do some coalescing of events (for instance two consecutive running events get coalesced.) // We do some coalescing of events (for instance two consecutive running events get coalesced.)
// But we only coalesce against events we actually broadcast. So we use m_last_broadcast_state // But we only coalesce against events we actually broadcast. So we use m_last_broadcast_state
// to track that. NB - you can't use "m_public_state.GetValue()" for that purpose, as was originally done, // to track that. NB - you can't use "m_public_state.GetValue()" for that purpose, as was originally done,
@ -4984,6 +5026,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
final_timeout.OffsetWithMicroSeconds(timeout_usec); final_timeout.OffsetWithMicroSeconds(timeout_usec);
} }
// This isn't going to work if there are unfetched events on the queue.
// Are there cases where we might want to run the remaining events here, and then try to
// call the function? That's probably being too tricky for our own good.
Event *other_events = listener.PeekAtNextEvent();
if (other_events != NULL)
{
errors.Printf("Calling RunThreadPlan with pending events on the queue.");
return eExecutionSetupError;
}
// We also need to make sure that the next event is delivered. We might be calling a function as part of
// a thread plan, in which case the last delivered event could be the running event, and we don't want
// event coalescing to cause us to lose OUR running event...
ForceNextEventDelivery();
// This while loop must exit out the bottom, there's cleanup that we need to do when we are done. // This while loop must exit out the bottom, there's cleanup that we need to do when we are done.
// So don't call return anywhere within it. // So don't call return anywhere within it.
@ -5772,3 +5830,39 @@ Process::DidExec ()
target.DidExec(); target.DidExec();
} }
addr_t
Process::ResolveIndirectFunction(const Address *address, Error &error)
{
if (address == nullptr)
{
Symbol *symbol = address->CalculateSymbolContextSymbol();
error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s",
symbol ? symbol->GetName().AsCString() : "<UNKNOWN>");
return LLDB_INVALID_ADDRESS;
}
addr_t function_addr = LLDB_INVALID_ADDRESS;
addr_t addr = address->GetLoadAddress(&GetTarget());
std::map<addr_t,addr_t>::const_iterator iter = m_resolved_indirect_addresses.find(addr);
if (iter != m_resolved_indirect_addresses.end())
{
function_addr = (*iter).second;
}
else
{
if (!InferiorCall(this, address, function_addr))
{
Symbol *symbol = address->CalculateSymbolContextSymbol();
error.SetErrorStringWithFormat ("Unable to call resolver for indirect function %s",
symbol ? symbol->GetName().AsCString() : "<UNKNOWN>");
function_addr = LLDB_INVALID_ADDRESS;
}
else
{
m_resolved_indirect_addresses.insert(std::pair<addr_t, addr_t>(addr, function_addr));
}
}
return function_addr;
}

View File

@ -250,7 +250,7 @@ Target::CreateSourceRegexBreakpoint (const FileSpecList *containingModules,
{ {
SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, source_file_spec_list)); SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, source_file_spec_list));
BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex (NULL, source_regex)); BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex (NULL, source_regex));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
} }
@ -304,7 +304,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules,
line_no, line_no,
check_inlines, check_inlines,
skip_prologue)); skip_prologue));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
} }
@ -331,7 +331,7 @@ Target::CreateBreakpoint (Address &addr, bool internal, bool hardware)
{ {
SearchFilterSP filter_sp(new SearchFilterForNonModuleSpecificSearches (shared_from_this())); SearchFilterSP filter_sp(new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr)); BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, false);
} }
BreakpointSP BreakpointSP
@ -356,7 +356,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules,
func_name_type_mask, func_name_type_mask,
Breakpoint::Exact, Breakpoint::Exact,
skip_prologue)); skip_prologue));
bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
} }
return bp_sp; return bp_sp;
} }
@ -383,7 +383,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules,
func_names, func_names,
func_name_type_mask, func_name_type_mask,
skip_prologue)); skip_prologue));
bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
} }
return bp_sp; return bp_sp;
} }
@ -411,7 +411,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules,
num_names, num_names,
func_name_type_mask, func_name_type_mask,
skip_prologue)); skip_prologue));
bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
} }
return bp_sp; return bp_sp;
} }
@ -489,7 +489,7 @@ Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules,
func_regex, func_regex,
skip_prologue == eLazyBoolCalculate ? GetSkipPrologue() : skip_prologue)); skip_prologue == eLazyBoolCalculate ? GetSkipPrologue() : skip_prologue));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
} }
lldb::BreakpointSP lldb::BreakpointSP
@ -499,12 +499,12 @@ Target::CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_
} }
BreakpointSP BreakpointSP
Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware) Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware, bool resolve_indirect_symbols)
{ {
BreakpointSP bp_sp; BreakpointSP bp_sp;
if (filter_sp && resolver_sp) if (filter_sp && resolver_sp)
{ {
bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp, request_hardware)); bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp, request_hardware, resolve_indirect_symbols));
resolver_sp->SetBreakpoint (bp_sp.get()); resolver_sp->SetBreakpoint (bp_sp.get());
if (internal) if (internal)