Reworked the way Process::RunThreadPlan and the ThreadPlanCallFunction interoperate to fix problems where

hitting auto-continue signals while running a thread plan would cause us to lose control of the debug 
session.

<rdar://problem/12993641>

llvm-svn: 174793
This commit is contained in:
Jim Ingham 2013-02-09 01:29:05 +00:00
parent 1aa79e9f63
commit 0161b49cba
37 changed files with 595 additions and 329 deletions

View File

@ -40,13 +40,13 @@ public:
GetUnwindOnError () const;
void
SetUnwindOnError (bool unwind = false);
SetUnwindOnError (bool unwind = true);
bool
GetIgnoreBreakpoints () const;
void
SetIgnoreBreakpoints (bool ignore = false);
SetIgnoreBreakpoints (bool ignore = true);
lldb::DynamicValueType
GetFetchDynamicValue () const;

View File

@ -234,6 +234,12 @@ public:
static bool
GetRestartedFromEvent (const lldb::SBEvent &event);
static size_t
GetNumRestartedReasonsFromEvent (const lldb::SBEvent &event);
static const char *
GetRestartedReasonAtIndexFromEvent (const lldb::SBEvent &event, size_t idx);
static lldb::SBProcess
GetProcessFromEvent (const lldb::SBEvent &event);

View File

@ -1446,6 +1446,22 @@ public:
{
return m_restarted;
}
size_t
GetNumRestartedReasons ()
{
return m_restarted_reasons.size();
}
const char *
GetRestartedReasonAtIndex(size_t idx)
{
if (idx > m_restarted_reasons.size())
return NULL;
else
return m_restarted_reasons[idx].c_str();
}
bool
GetInterrupted () const
{
@ -1469,6 +1485,15 @@ public:
static bool
GetRestartedFromEvent (const Event *event_ptr);
static size_t
GetNumRestartedReasons(const Event *event_ptr);
static const char *
GetRestartedReasonAtIndex(const Event *event_ptr, size_t idx);
static void
AddRestartedReason (Event *event_ptr, const char *reason);
static void
SetRestartedInEvent (Event *event_ptr, bool new_value);
@ -1499,9 +1524,15 @@ public:
{
m_interrupted = new_value;
}
void
AddRestartedReason (const char *reason)
{
m_restarted_reasons.push_back(reason);
}
lldb::ProcessSP m_process_sp;
lldb::StateType m_state;
std::vector<std::string> m_restarted_reasons;
bool m_restarted; // For "eStateStopped" events, this is true if the target was automatically restarted.
int m_update_state;
bool m_interrupted;
@ -3543,7 +3574,8 @@ protected:
ReadWriteLock m_run_lock;
Predicate<bool> m_currently_handling_event;
bool m_finalize_called;
lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent.
enum {
eCanJITDontKnow= 0,
eCanJITYes,
@ -3637,7 +3669,7 @@ private:
// For Process only
//------------------------------------------------------------------
void ControlPrivateStateThread (uint32_t signal);
DISALLOW_COPY_AND_ASSIGN (Process);
};

View File

@ -106,7 +106,32 @@ public:
else
m_description.clear();
}
// Sometimes the thread plan logic will know that it wants a given stop to stop or not,
// regardless of what the ordinary logic for that StopInfo would dictate. The main example
// of this is the ThreadPlanCallFunction, which for instance knows - based on how that particular
// expression was executed - whether it wants all breakpoints to auto-continue or not.
// Use OverrideShouldStop on the StopInfo to implement this.
void
OverrideShouldStop (bool override_value)
{
m_override_set = true;
m_override_value = override_value;
}
bool
GetOverrideShouldStop()
{
return m_override_set;
}
bool
GetOverriddenShouldStopValue ()
{
return m_override_value;
}
static lldb::StopInfoSP
CreateStopReasonWithBreakpointSiteID (Thread &thread, lldb::break_id_t break_id);
@ -138,6 +163,7 @@ public:
protected:
// Perform any action that is associated with this stop. This is done as the
// Event is removed from the event queue. ProcessEventData::DoOnRemoval does the job.
virtual void
PerformAction (Event *event_ptr)
{
@ -163,6 +189,8 @@ protected:
uint32_t m_resume_id; // This is the resume ID when we made this stop ID.
uint64_t m_value; // A generic value that can be used for things pertaining to this stop info
std::string m_description; // A textual description describing this stop.
bool m_override_set;
bool m_override_value;
// This determines whether the target has run since this stop info.
// N.B. running to evaluate a user expression does not count.

View File

@ -332,7 +332,7 @@ public:
ValidatePlan (Stream *error) = 0;
virtual bool
PlanExplainsStop () = 0;
PlanExplainsStop (Event *event_ptr) = 0;
bool
TracerExplainsStop ()

View File

@ -35,7 +35,7 @@ public:
virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
virtual bool ValidatePlan (Stream *error);
virtual bool PlanExplainsStop ();
virtual bool PlanExplainsStop (Event *event_ptr);
virtual bool ShouldStop (Event *event_ptr);
virtual bool StopOthers ();
virtual lldb::StateType GetPlanRunState ();

View File

@ -59,10 +59,13 @@ public:
ValidatePlan (Stream *error);
virtual bool
PlanExplainsStop ();
PlanExplainsStop (Event *event_ptr);
virtual bool
ShouldStop (Event *event_ptr);
virtual Vote
ShouldReportStop(Event *event_ptr);
virtual bool
StopOthers ();

View File

@ -47,7 +47,7 @@ public:
ValidatePlan (Stream *error);
virtual bool
PlanExplainsStop ();
PlanExplainsStop (Event *event_ptr);
virtual bool
ShouldStop (Event *event_ptr);

View File

@ -61,7 +61,7 @@ public:
SetDefaultFlagValue (uint32_t new_value);
virtual bool
PlanExplainsStop ();
PlanExplainsStop (Event *event_ptr);
virtual bool WillResume (lldb::StateType resume_state, bool current_plan);

View File

@ -27,7 +27,7 @@ public:
virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
virtual bool ValidatePlan (Stream *error);
virtual bool PlanExplainsStop ();
virtual bool PlanExplainsStop (Event *event_ptr);
virtual bool ShouldStop (Event *event_ptr);
virtual bool StopOthers ();
virtual lldb::StateType GetPlanRunState ();

View File

@ -34,7 +34,7 @@ public:
virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
virtual bool ValidatePlan (Stream *error);
virtual bool PlanExplainsStop ();
virtual bool PlanExplainsStop (Event *event_ptr);
virtual bool ShouldStop (Event *event_ptr);
virtual bool StopOthers ();
virtual lldb::StateType GetPlanRunState ();

View File

@ -27,7 +27,7 @@ public:
ThreadPlanStepOverBreakpoint (Thread &thread);
virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
virtual bool ValidatePlan (Stream *error);
virtual bool PlanExplainsStop ();
virtual bool PlanExplainsStop (Event *event_ptr);
virtual bool ShouldStop (Event *event_ptr);
virtual bool StopOthers ();
virtual lldb::StateType GetPlanRunState ();

View File

@ -34,7 +34,7 @@ public:
virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
virtual bool ShouldStop (Event *event_ptr);
virtual bool PlanExplainsStop ();
virtual bool PlanExplainsStop (Event *event_ptr);
virtual bool WillResume (lldb::StateType resume_state, bool current_plan);
protected:

View File

@ -26,7 +26,7 @@ public:
virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
virtual bool ValidatePlan (Stream *error);
virtual bool PlanExplainsStop ();
virtual bool PlanExplainsStop (Event *event_ptr);
virtual bool ShouldStop (Event *event_ptr);
virtual bool StopOthers ();
virtual lldb::StateType GetPlanRunState ();

View File

@ -27,7 +27,7 @@ public:
virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
virtual bool ValidatePlan (Stream *error);
virtual bool PlanExplainsStop ();
virtual bool PlanExplainsStop (Event *event_ptr);
virtual bool ShouldStop (Event *event_ptr);
virtual bool StopOthers ();
virtual lldb::StateType GetPlanRunState ();

View File

@ -39,7 +39,7 @@ public:
%feature("docstring", "Sets whether to unwind the expression stack on error.") SetUnwindOnError;
void
SetUnwindOnError (bool unwind = false);
SetUnwindOnError (bool unwind = true);
bool
GetIgnoreBreakpoints () const;
@ -47,7 +47,7 @@ public:
%feature("docstring", "Sets whether to ignore breakpoint hits while running expressions.") SetUnwindOnError;
void
SetIgnoreBreakpoints (bool ignore = false);
SetIgnoreBreakpoints (bool ignore = true);
lldb::DynamicValueType
GetFetchDynamicValue () const;

View File

@ -328,6 +328,12 @@ public:
static bool
GetRestartedFromEvent (const lldb::SBEvent &event);
static size_t
GetNumRestartedReasonsFromEvent (const lldb::SBEvent &event);
static const char *
GetRestartedReasonAtIndexFromEvent (const lldb::SBEvent &event, size_t idx);
static lldb::SBProcess
GetProcessFromEvent (const lldb::SBEvent &event);

View File

@ -909,6 +909,18 @@ SBProcess::GetRestartedFromEvent (const SBEvent &event)
return Process::ProcessEventData::GetRestartedFromEvent (event.get());
}
size_t
SBProcess::GetNumRestartedReasonsFromEvent (const lldb::SBEvent &event)
{
return Process::ProcessEventData::GetNumRestartedReasons(event.get());
}
const char *
SBProcess::GetRestartedReasonAtIndexFromEvent (const lldb::SBEvent &event, size_t idx)
{
return Process::ProcessEventData::GetRestartedReasonAtIndex(event.get(), idx);
}
SBProcess
SBProcess::GetProcessFromEvent (const SBEvent &event)
{

View File

@ -199,6 +199,11 @@ protected:
if (environment.GetArgumentCount() > 0)
m_options.launch_info.GetEnvironmentEntries ().AppendArguments (environment);
// Get the value of synchronous execution here. If you wait till after you have started to
// run, then you could have hit a breakpoint, whose command might switch the value, and
// then you'll pick up that incorrect value.
bool synchronous_execution = m_interpreter.GetSynchronous ();
// Finalize the file actions, and if none were given, default to opening
// up a pseudo terminal
const bool default_to_use_pty = true;
@ -258,7 +263,6 @@ protected:
error = process->Resume();
if (error.Success())
{
bool synchronous_execution = m_interpreter.GetSynchronous ();
if (synchronous_execution)
{
state = process->WaitForProcessToStop (NULL);

View File

@ -703,7 +703,7 @@ ClangUserExpression::Execute (Stream &error_stream,
}
const bool stop_others = true;
const bool try_all_threads = true;
const bool try_all_threads = run_others;
Address wrapper_address (m_jit_start_addr);
lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),

View File

@ -126,7 +126,7 @@ AppleThreadPlanStepThroughObjCTrampoline::ValidatePlan (Stream *error)
}
bool
AppleThreadPlanStepThroughObjCTrampoline::PlanExplainsStop ()
AppleThreadPlanStepThroughObjCTrampoline::PlanExplainsStop (Event *event_ptr)
{
// If we get asked to explain the stop it will be because something went
// wrong (like the implementation for selector function crashed... We're going

View File

@ -46,7 +46,7 @@ public:
ValidatePlan (Stream *error);
virtual bool
PlanExplainsStop ();
PlanExplainsStop (Event *event_ptr);
virtual lldb::StateType

View File

@ -1021,6 +1021,7 @@ Process::Process(Target &target, Listener &listener) :
m_run_lock (),
m_currently_handling_event(false),
m_finalize_called(false),
m_last_broadcast_state (eStateInvalid),
m_can_jit(eCanJITDontKnow)
{
CheckInWithManager ();
@ -3146,9 +3147,9 @@ Process::ConnectRemote (Stream *strm, const char *remote_url)
Error
Process::PrivateResume ()
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_STEP));
LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_STEP));
if (log)
log->Printf("Process::Resume() m_stop_id = %u, public state: %s private state: %s",
log->Printf("Process::PrivateResume() m_stop_id = %u, public state: %s private state: %s",
m_mod_id.GetStopID(),
StateAsCString(m_public_state.GetValue()),
StateAsCString(m_private_state.GetValue()));
@ -3170,7 +3171,7 @@ Process::PrivateResume ()
// Last thing, do the PreResumeActions.
if (!RunPreResumeActions())
{
error.SetErrorStringWithFormat ("Process::Resume PreResumeActions failed, not resuming.");
error.SetErrorStringWithFormat ("Process::PrivateResume PreResumeActions failed, not resuming.");
}
else
{
@ -3197,7 +3198,7 @@ Process::PrivateResume ()
}
}
else if (log)
log->Printf ("Process::WillResume() got an error \"%s\".", error.AsCString("<unknown error>"));
log->Printf ("Process::PrivateResume() got an error \"%s\".", error.AsCString("<unknown error>"));
return error;
}
@ -3422,8 +3423,8 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
{
const StateType state = Process::ProcessEventData::GetStateFromEvent (event_ptr);
bool return_value = true;
LogSP log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
LogSP log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS | LIBLLDB_LOG_PROCESS));
switch (state)
{
case eStateConnected:
@ -3448,7 +3449,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
// stopped -> running: Report except when there is one or more no votes
// and no yes votes.
SynchronouslyNotifyStateChanged (state);
switch (m_public_state.GetValue())
switch (m_last_broadcast_state)
{
case eStateRunning:
case eStateStepping:
@ -3490,32 +3491,50 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
if (ProcessEventData::GetInterruptedFromEvent (event_ptr))
{
if (log)
log->Printf ("Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s", event_ptr, StateAsCString(state));
return true;
log->Printf ("Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s",
event_ptr,
StateAsCString(state));
return_value = true;
}
else
{
if (m_thread_list.ShouldStop (event_ptr) == false)
// It makes no sense to ask "ShouldStop" if we've already been restarted...
// Asking the thread list is also not likely to go well, since we are running again.
// So in that case just report the event.
bool was_restarted = ProcessEventData::GetRestartedFromEvent (event_ptr);
bool should_resume = false;
if (!was_restarted)
should_resume = m_thread_list.ShouldStop (event_ptr) == false;
if (was_restarted || should_resume)
{
// ShouldStop may have restarted the target already. If so, don't
// resume it twice.
bool was_restarted = ProcessEventData::GetRestartedFromEvent (event_ptr);
switch (m_thread_list.ShouldReportStop (event_ptr))
Vote stop_vote = m_thread_list.ShouldReportStop (event_ptr);
if (log)
log->Printf ("Process::ShouldBroadcastEvent: should_stop: %i state: %s was_restarted: %i stop_vote: %d.",
should_resume,
StateAsCString(state),
was_restarted,
stop_vote);
switch (stop_vote)
{
case eVoteYes:
Process::ProcessEventData::SetRestartedInEvent (event_ptr, true);
// Intentional fall-through here.
return_value = true;
break;
case eVoteNoOpinion:
case eVoteNo:
return_value = false;
break;
}
if (log)
log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s", event_ptr, StateAsCString(state));
if (!was_restarted)
{
if (log)
log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s", event_ptr, StateAsCString(state));
ProcessEventData::SetRestartedInEvent(event_ptr, true);
PrivateResume ();
}
}
else
{
@ -3524,10 +3543,25 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
}
}
}
break;
}
// 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
// to track that. NB - you can't use "m_public_state.GetValue()" for that purpose, as was originally done,
// because the PublicState reflects the last event pulled off the queue, and there may be several
// events stacked up on the queue unserviced. So the PublicState may not reflect the last broadcasted event
// yet. m_last_broadcast_state gets updated here.
if (return_value)
m_last_broadcast_state = state;
if (log)
log->Printf ("Process::ShouldBroadcastEvent (%p) => %s - %s", event_ptr, StateAsCString(state), return_value ? "YES" : "NO");
log->Printf ("Process::ShouldBroadcastEvent (%p) => new state: %s, last broadcast state: %s - %s",
event_ptr,
StateAsCString(state),
StateAsCString(m_last_broadcast_state),
return_value ? "YES" : "NO");
return return_value;
}
@ -3585,7 +3619,7 @@ Process::StopPrivateStateThread ()
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
printf ("Went to stop the private state thread, but it was already invalid.");
log->Printf ("Went to stop the private state thread, but it was already invalid.");
}
}
@ -3667,6 +3701,9 @@ Process::HandlePrivateEvent (EventSP &event_sp)
if (m_next_event_action_ap.get() != NULL)
{
NextEventAction::EventActionResult action_result = m_next_event_action_ap->PerformAction(event_sp);
if (log)
log->Printf ("Ran next event action, result was %d.", action_result);
switch (action_result)
{
case NextEventAction::eEventActionSuccess:
@ -3871,7 +3908,7 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
if (m_update_state != 1)
return;
m_process_sp->SetPublicState (m_state);
// If we're stopped and haven't restarted, then do the breakpoint commands here:
@ -3926,20 +3963,29 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
StopInfoSP stop_info_sp = thread_sp->GetStopInfo ();
if (stop_info_sp && stop_info_sp->IsValid())
{
stop_info_sp->PerformAction(event_ptr);
// The stop action might restart the target. If it does, then we want to mark that in the
// event so that whoever is receiving it will know to wait for the running event and reflect
// that state appropriately.
// We also need to stop processing actions, since they aren't expecting the target to be running.
// FIXME: we might have run.
if (stop_info_sp->HasTargetRunSinceMe())
bool this_thread_wants_to_stop;
if (stop_info_sp->GetOverrideShouldStop())
{
SetRestarted (true);
break;
this_thread_wants_to_stop = stop_info_sp->GetOverriddenShouldStopValue();
}
else
{
stop_info_sp->PerformAction(event_ptr);
// The stop action might restart the target. If it does, then we want to mark that in the
// event so that whoever is receiving it will know to wait for the running event and reflect
// that state appropriately.
// We also need to stop processing actions, since they aren't expecting the target to be running.
// FIXME: we might have run.
if (stop_info_sp->HasTargetRunSinceMe())
{
SetRestarted (true);
break;
}
this_thread_wants_to_stop = stop_info_sp->ShouldStop(event_ptr);
}
bool this_thread_wants_to_stop = stop_info_sp->ShouldStop(event_ptr);
if (still_should_stop == false)
still_should_stop = this_thread_wants_to_stop;
}
@ -3954,7 +4000,7 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
SetRestarted(true);
// Use the public resume method here, since this is just
// extending a public resume.
m_process_sp->Resume();
m_process_sp->PrivateResume();
}
else
{
@ -3965,7 +4011,6 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
SetRestarted(true);
}
}
}
}
@ -4028,6 +4073,34 @@ Process::ProcessEventData::SetRestartedInEvent (Event *event_ptr, bool new_value
data->SetRestarted(new_value);
}
size_t
Process::ProcessEventData::GetNumRestartedReasons(const Event *event_ptr)
{
ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
if (data != NULL)
return data->GetNumRestartedReasons();
else
return 0;
}
const char *
Process::ProcessEventData::GetRestartedReasonAtIndex(const Event *event_ptr, size_t idx)
{
ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
if (data != NULL)
return data->GetRestartedReasonAtIndex(idx);
else
return NULL;
}
void
Process::ProcessEventData::AddRestartedReason (Event *event_ptr, const char *reason)
{
ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
if (data != NULL)
data->AddRestartedReason(reason);
}
bool
Process::ProcessEventData::GetInterruptedFromEvent (const Event *event_ptr)
{
@ -4479,12 +4552,38 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
TimeValue* timeout_ptr = NULL;
TimeValue real_timeout;
bool first_timeout = true;
bool before_first_timeout = true; // This is set to false the first time that we have to halt the target.
bool do_resume = true;
bool handle_running_event = true;
const uint64_t default_one_thread_timeout_usec = 250000;
uint64_t computed_timeout = 0;
// This is just for accounting:
uint32_t num_resumes = 0;
TimeValue one_thread_timeout = TimeValue::Now();
TimeValue final_timeout = one_thread_timeout;
if (run_others)
{
// If we are running all threads then we take half the time to run all threads, bounded by
// .25 sec.
if (timeout_usec == 0)
one_thread_timeout.OffsetWithMicroSeconds(default_one_thread_timeout_usec);
else
{
uint64_t computed_timeout = computed_timeout = timeout_usec / 2;
if (computed_timeout > default_one_thread_timeout_usec)
computed_timeout = default_one_thread_timeout_usec;
one_thread_timeout.OffsetWithMicroSeconds(computed_timeout);
}
final_timeout.OffsetWithMicroSeconds (timeout_usec);
}
else
{
if (timeout_usec != 0)
final_timeout.OffsetWithMicroSeconds(timeout_usec);
}
// 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.
@ -4493,6 +4592,11 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// We usually want to resume the process if we get to the top of the loop.
// The only exception is if we get two running events with no intervening
// stop, which can happen, we will just wait for then next stop event.
if (log)
log->Printf ("Top of while loop: do_resume: %i handle_running_event: %i before_first_timeout: %i.",
do_resume,
handle_running_event,
before_first_timeout);
if (do_resume || handle_running_event)
{
@ -4500,38 +4604,59 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (do_resume)
{
num_resumes++;
Error resume_error = PrivateResume ();
if (!resume_error.Success())
{
errors.Printf("Error resuming inferior: \"%s\".\n", resume_error.AsCString());
errors.Printf("Error resuming inferior the %d time: \"%s\".\n",
num_resumes,
resume_error.AsCString());
return_value = eExecutionSetupError;
break;
}
}
real_timeout = TimeValue::Now();
real_timeout.OffsetWithMicroSeconds(500000);
timeout_ptr = &real_timeout;
got_event = listener.WaitForEvent(timeout_ptr, event_sp);
TimeValue resume_timeout = TimeValue::Now();
resume_timeout.OffsetWithMicroSeconds(500000);
got_event = listener.WaitForEvent(&resume_timeout, event_sp);
if (!got_event)
{
if (log)
log->PutCString("Process::RunThreadPlan(): didn't get any event after initial resume, exiting.");
log->Printf ("Process::RunThreadPlan(): didn't get any event after resume %d, exiting.",
num_resumes);
errors.Printf("Didn't get any event after initial resume, exiting.");
errors.Printf("Didn't get any event after resume %d, exiting.", num_resumes);
return_value = eExecutionSetupError;
break;
}
stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
if (stop_state != eStateRunning)
{
if (log)
log->Printf("Process::RunThreadPlan(): didn't get running event after "
"initial resume, got %s instead.",
StateAsCString(stop_state));
bool restarted = false;
if (stop_state == eStateStopped)
{
restarted = Process::ProcessEventData::GetRestartedFromEvent(event_sp.get());
if (log)
log->Printf("Process::RunThreadPlan(): didn't get running event after "
"resume %d, got %s instead (restarted: %i, do_resume: %i, handle_running_event: %i).",
num_resumes,
StateAsCString(stop_state),
restarted,
do_resume,
handle_running_event);
}
if (restarted)
{
// This is probably an overabundance of caution, I don't think I should ever get a stopped & restarted
// event here. But if I do, the best thing is to Halt and then get out of here.
Halt();
}
errors.Printf("Didn't get running event after initial resume, got %s instead.",
StateAsCString(stop_state));
return_value = eExecutionSetupError;
@ -4545,55 +4670,35 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// won't be able to gather the result at this point.
// We set the timeout AFTER the resume, since the resume takes some time and we
// don't want to charge that to the timeout.
if (first_timeout)
{
if (run_others)
{
// If we are running all threads then we take half the time to run all threads, bounded by
// .25 sec.
if (timeout_usec == 0)
computed_timeout = default_one_thread_timeout_usec;
else
{
computed_timeout = timeout_usec / 2;
if (computed_timeout > default_one_thread_timeout_usec)
{
computed_timeout = default_one_thread_timeout_usec;
}
timeout_usec -= computed_timeout;
}
}
else
{
computed_timeout = timeout_usec;
}
}
else
{
computed_timeout = timeout_usec;
}
if (computed_timeout != 0)
{
// we have a > 0 timeout, let us set it so that we stop after the deadline
real_timeout = TimeValue::Now();
real_timeout.OffsetWithMicroSeconds(computed_timeout);
timeout_ptr = &real_timeout;
}
else
{
timeout_ptr = NULL;
}
}
else
{
if (log)
log->PutCString ("Process::RunThreadPlan(): handled an extra running event.");
do_resume = true;
handle_running_event = true;
log->PutCString ("Process::RunThreadPlan(): waiting for next event.");
}
if (before_first_timeout)
{
if (run_others)
timeout_ptr = &one_thread_timeout;
else
{
if (timeout_usec == 0)
timeout_ptr = NULL;
else
timeout_ptr = &final_timeout;
}
}
else
{
if (timeout_usec == 0)
timeout_ptr = NULL;
else
timeout_ptr = &final_timeout;
}
do_resume = true;
handle_running_event = true;
// Now wait for the process to stop again:
event_sp.reset();
@ -4602,12 +4707,9 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (timeout_ptr)
{
StreamString s;
s.Printf ("about to wait - timeout is:\n ");
timeout_ptr->Dump (&s, 120);
s.Printf ("\nNow is:\n ");
TimeValue::Now().Dump (&s, 120);
log->Printf ("Process::RunThreadPlan(): %s", s.GetData());
log->Printf ("Process::RunThreadPlan(): about to wait - now is %llu - endpoint is %llu",
TimeValue::Now().GetAsMicroSecondsSinceJan1_1970(),
timeout_ptr->GetAsMicroSecondsSinceJan1_1970());
}
else
{
@ -4625,11 +4727,11 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (event_sp->GetType() == eBroadcastBitInterrupt)
{
Halt();
keep_going = false;
return_value = eExecutionInterrupted;
errors.Printf ("Execution halted by user interrupt.");
if (log)
log->Printf ("Process::RunThreadPlan(): Got interrupted by eBroadcastBitInterrupted, exiting.");
break;
}
else
{
@ -4641,7 +4743,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
case lldb::eStateStopped:
{
// Yay, we're done. Now make sure that our thread plan actually completed.
// We stopped, figure out what we are going to do now.
ThreadSP thread_sp = GetThreadList().FindThreadByIndexID (thread_idx_id);
if (!thread_sp)
{
@ -4652,52 +4754,63 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
else
{
StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
StopReason stop_reason = eStopReasonInvalid;
if (stop_info_sp)
stop_reason = stop_info_sp->GetStopReason();
if (stop_reason == eStopReasonPlanComplete)
// If we were restarted, we just need to go back up to fetch another event.
if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
{
if (log)
log->PutCString ("Process::RunThreadPlan(): execution completed successfully.");
// Now mark this plan as private so it doesn't get reported as the stop reason
// after this point.
if (thread_plan_sp)
thread_plan_sp->SetPrivate (orig_plan_private);
return_value = eExecutionCompleted;
{
log->Printf ("Process::RunThreadPlan(): Got a stop and restart, so we'll continue waiting.");
}
keep_going = true;
do_resume = false;
handle_running_event = true;
}
else
{
// Something restarted the target, so just wait for it to stop for real.
if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
StopReason stop_reason = eStopReasonInvalid;
if (stop_info_sp)
stop_reason = stop_info_sp->GetStopReason();
// FIXME: We only check if the stop reason is plan complete, should we make sure that
// it is OUR plan that is complete?
if (stop_reason == eStopReasonPlanComplete)
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Somebody stopped and then restarted, we'll continue waiting.");
keep_going = true;
do_resume = false;
handle_running_event = true;
log->PutCString ("Process::RunThreadPlan(): execution completed successfully.");
// Now mark this plan as private so it doesn't get reported as the stop reason
// after this point.
if (thread_plan_sp)
thread_plan_sp->SetPrivate (orig_plan_private);
return_value = eExecutionCompleted;
}
else
{
if (log)
log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");
// Something restarted the target, so just wait for it to stop for real.
if (stop_reason == eStopReasonBreakpoint)
{
if (log)
log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription());
return_value = eExecutionHitBreakpoint;
}
else
{
if (log)
log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");
return_value = eExecutionInterrupted;
}
}
}
}
}
break;
case lldb::eStateCrashed:
if (log)
log->PutCString ("Process::RunThreadPlan(): execution crashed.");
return_value = eExecutionInterrupted;
break;
case lldb::eStateRunning:
// This shouldn't really happen, but sometimes we do get two running events without an
// intervening stop, and in that case we should just go back to waiting for the stop.
do_resume = false;
keep_going = true;
handle_running_event = false;
@ -4734,15 +4847,15 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// If we didn't get an event that means we've timed out...
// We will interrupt the process here. Depending on what we were asked to do we will
// either exit, or try with all threads running for the same timeout.
// Not really sure what to do if Halt fails here...
if (log) {
if (run_others)
{
if (first_timeout)
log->Printf ("Process::RunThreadPlan(): Running function with timeout: %" PRId64 " timed out, "
"trying for %d usec with all threads enabled.",
computed_timeout, timeout_usec);
uint64_t remaining_time = final_timeout - TimeValue::Now();
if (before_first_timeout)
log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, "
"running till for %" PRId64 " usec with all threads enabled.",
remaining_time);
else
log->Printf ("Process::RunThreadPlan(): Restarting function with all threads enabled "
"and timeout: %d timed out, abandoning execution.",
@ -4754,148 +4867,122 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
timeout_usec);
}
Error halt_error = Halt();
if (halt_error.Success())
// It is possible that between the time we issued the Halt, and we get around to calling Halt the target
// could have stopped. That's fine, Halt will figure that out and send the appropriate Stopped event.
// BUT it is also possible that we stopped & restarted (e.g. hit a signal with "stop" set to false.) In
// that case, we'll get the stopped & restarted event, and we should go back to waiting for the Halt's
// stopped event. That's what this while loop does.
bool back_to_top = true;
uint32_t try_halt_again = 0;
bool do_halt = true;
const uint32_t num_retries = 5;
while (try_halt_again < num_retries)
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Halt succeeded.");
Error halt_error;
if (do_halt)
{
if (log)
log->Printf ("Process::RunThreadPlan(): Running Halt.");
halt_error = Halt();
}
if (halt_error.Success())
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Halt succeeded.");
real_timeout = TimeValue::Now();
real_timeout.OffsetWithMicroSeconds(500000);
got_event = listener.WaitForEvent(&real_timeout, event_sp);
// If halt succeeds, it always produces a stopped event. Wait for that:
real_timeout = TimeValue::Now();
real_timeout.OffsetWithMicroSeconds(500000);
got_event = listener.WaitForEvent(&real_timeout, event_sp);
if (got_event)
{
stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
if (log)
if (got_event)
{
log->Printf ("Process::RunThreadPlan(): Stopped with event: %s", StateAsCString(stop_state));
if (stop_state == lldb::eStateStopped
&& Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get()))
log->PutCString (" Event was the Halt interruption event.");
}
if (stop_state == lldb::eStateStopped)
{
// Between the time we initiated the Halt and the time we delivered it, the process could have
// already finished its job. Check that here:
if (thread->IsThreadPlanDone (thread_plan_sp.get()))
stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
if (log)
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Even though we timed out, the call plan was done. "
"Exiting wait loop.");
return_value = eExecutionCompleted;
break;
}
if (!run_others)
{
if (log)
log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting.");
return_value = eExecutionInterrupted;
break;
log->Printf ("Process::RunThreadPlan(): Stopped with event: %s", StateAsCString(stop_state));
if (stop_state == lldb::eStateStopped
&& Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get()))
log->PutCString (" Event was the Halt interruption event.");
}
if (first_timeout)
if (stop_state == lldb::eStateStopped)
{
// Set all the other threads to run, and return to the top of the loop, which will continue;
first_timeout = false;
thread_plan_sp->SetStopOthers (false);
if (log)
log->PutCString ("Process::RunThreadPlan(): about to resume.");
// Between the time we initiated the Halt and the time we delivered it, the process could have
// already finished its job. Check that here:
if (thread->IsThreadPlanDone (thread_plan_sp.get()))
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Even though we timed out, the call plan was done. "
"Exiting wait loop.");
return_value = eExecutionCompleted;
back_to_top = false;
break;
}
if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Went to halt but got a restarted event, there must be an un-restarted stopped event so try again... "
"Exiting wait loop.");
try_halt_again++;
do_halt = false;
continue;
}
continue;
}
else
{
// Running all threads failed, so return Interrupted.
if (log)
log->PutCString("Process::RunThreadPlan(): running all threads timed out.");
return_value = eExecutionInterrupted;
break;
}
}
}
else
{ if (log)
log->PutCString("Process::RunThreadPlan(): halt said it succeeded, but I got no event. "
"I'm getting out of here passing Interrupted.");
return_value = eExecutionInterrupted;
break;
}
}
else
{
// This branch is to work around some problems with gdb-remote's Halt. It is a little racy, and can return
// an error from halt, but if you wait a bit you'll get a stopped event anyway.
if (log)
log->Printf ("Process::RunThreadPlan(): halt failed: error = \"%s\", I'm just going to wait a little longer and see if I get a stopped event.",
halt_error.AsCString());
real_timeout = TimeValue::Now();
real_timeout.OffsetWithMicroSeconds(500000);
timeout_ptr = &real_timeout;
got_event = listener.WaitForEvent(&real_timeout, event_sp);
if (!got_event || event_sp.get() == NULL)
{
// This is not going anywhere, bag out.
if (log)
log->PutCString ("Process::RunThreadPlan(): halt failed: and waiting for the stopped event failed.");
return_value = eExecutionInterrupted;
break;
}
else
{
stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
if (log)
log->PutCString ("Process::RunThreadPlan(): halt failed: but then I got a stopped event. Whatever...");
if (stop_state == lldb::eStateStopped)
{
// Between the time we initiated the Halt and the time we delivered it, the process could have
// already finished its job. Check that here:
if (thread->IsThreadPlanDone (thread_plan_sp.get()))
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Even though we timed out, the call plan was done. "
"Exiting wait loop.");
return_value = eExecutionCompleted;
break;
}
if (!run_others)
{
if (log)
log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting.");
return_value = eExecutionInterrupted;
back_to_top = false;
break;
}
if (before_first_timeout)
{
// Set all the other threads to run, and return to the top of the loop, which will continue;
before_first_timeout = false;
thread_plan_sp->SetStopOthers (false);
if (log)
log->PutCString ("Process::RunThreadPlan(): about to resume.");
if (first_timeout)
{
// Set all the other threads to run, and return to the top of the loop, which will continue;
first_timeout = false;
thread_plan_sp->SetStopOthers (false);
if (log)
log->PutCString ("Process::RunThreadPlan(): About to resume.");
continue;
}
else
{
// Running all threads failed, so return Interrupted.
if (log)
log->PutCString ("Process::RunThreadPlan(): running all threads timed out.");
return_value = eExecutionInterrupted;
break;
back_to_top = true;
break;
}
else
{
// Running all threads failed, so return Interrupted.
if (log)
log->PutCString("Process::RunThreadPlan(): running all threads timed out.");
return_value = eExecutionInterrupted;
back_to_top = false;
break;
}
}
}
else
{
if (log)
log->Printf ("Process::RunThreadPlan(): halt failed, I waited and didn't get"
" a stopped event, instead got %s.", StateAsCString(stop_state));
{ if (log)
log->PutCString("Process::RunThreadPlan(): halt said it succeeded, but I got no event. "
"I'm getting out of here passing Interrupted.");
return_value = eExecutionInterrupted;
break;
back_to_top = false;
break;
}
}
else
{
try_halt_again++;
continue;
}
}
if (!back_to_top || try_halt_again > num_retries)
break;
else
continue;
}
} // END WAIT LOOP

View File

@ -38,7 +38,9 @@ StopInfo::StopInfo (Thread &thread, uint64_t value) :
m_thread (thread),
m_stop_id (thread.GetProcess()->GetStopID()),
m_resume_id (thread.GetProcess()->GetResumeID()),
m_value (value)
m_value (value),
m_override_set(false),
m_override_value(true)
{
}
@ -772,6 +774,12 @@ public:
return eStopReasonSignal;
}
virtual bool
ShouldStopSynchronous (Event *event_ptr)
{
return m_thread.GetProcess()->GetUnixSignals().GetShouldStop (m_value);
}
virtual bool
ShouldStop (Event *event_ptr)
{
@ -783,7 +791,16 @@ public:
virtual bool
ShouldNotify (Event *event_ptr)
{
return m_thread.GetProcess()->GetUnixSignals().GetShouldNotify (m_value);
bool should_notify = m_thread.GetProcess()->GetUnixSignals().GetShouldNotify (m_value);
if (should_notify)
{
StreamString strm;
strm.Printf ("thread %d received signal: %s",
m_thread.GetIndexID(),
m_thread.GetProcess()->GetUnixSignals().GetSignalAsCString (m_value));
Process::ProcessEventData::AddRestartedReason(event_ptr, strm.GetData());
}
return should_notify;
}
@ -924,6 +941,16 @@ public:
{
return m_return_valobj_sp;
}
protected:
virtual bool
ShouldStop (Event *event_ptr)
{
if (m_plan_sp)
return m_plan_sp->ShouldStop(event_ptr);
else
return StopInfo::ShouldStop(event_ptr);
}
private:
ThreadPlanSP m_plan_sp;
@ -956,7 +983,6 @@ public:
{
return "exec";
}
protected:
protected:
virtual void

View File

@ -646,7 +646,7 @@ Thread::ShouldStop (Event* event_ptr)
bool done_processing_current_plan = false;
if (!current_plan->PlanExplainsStop())
if (!current_plan->PlanExplainsStop(event_ptr))
{
if (current_plan->TracerExplainsStop())
{
@ -660,7 +660,7 @@ Thread::ShouldStop (Event* event_ptr)
ThreadPlan *plan_ptr = current_plan;
while ((plan_ptr = GetPreviousPlan(plan_ptr)) != NULL)
{
if (plan_ptr->PlanExplainsStop())
if (plan_ptr->PlanExplainsStop(event_ptr))
{
should_stop = plan_ptr->ShouldStop (event_ptr);
@ -831,9 +831,24 @@ Thread::ShouldReportStop (Event* event_ptr)
}
else
{
Vote thread_vote = eVoteNoOpinion;
ThreadPlan *plan_ptr = GetCurrentPlan();
while (1)
{
if (plan_ptr->PlanExplainsStop(event_ptr))
{
thread_vote = plan_ptr->ShouldReportStop(event_ptr);
break;
}
if (PlanIsBasePlan(plan_ptr))
break;
else
plan_ptr = GetPreviousPlan(plan_ptr);
}
if (log)
log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote for current plan\n", GetID());
return GetCurrentPlan()->ShouldReportStop (event_ptr);
log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote %i for current plan\n", GetID(), thread_vote);
return thread_vote;
}
}

View File

@ -68,7 +68,7 @@ ThreadPlanBase::ValidatePlan (Stream *error)
}
bool
ThreadPlanBase::PlanExplainsStop ()
ThreadPlanBase::PlanExplainsStop (Event *event_ptr)
{
// The base plan should defer to its tracer, since by default it
// always handles the stop.

View File

@ -231,7 +231,7 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
ThreadPlanCallFunction::~ThreadPlanCallFunction ()
{
DoTakedown(true);
DoTakedown(PlanSucceeded());
}
void
@ -309,7 +309,7 @@ ThreadPlanCallFunction::DoTakedown (bool success)
void
ThreadPlanCallFunction::WillPop ()
{
DoTakedown(true);
DoTakedown(PlanSucceeded());
}
void
@ -335,14 +335,25 @@ ThreadPlanCallFunction::ValidatePlan (Stream *error)
return true;
}
Vote
ThreadPlanCallFunction::ShouldReportStop(Event *event_ptr)
{
if (m_takedown_done || IsPlanComplete())
return eVoteYes;
else
return ThreadPlan::ShouldReportStop(event_ptr);
}
bool
ThreadPlanCallFunction::PlanExplainsStop ()
ThreadPlanCallFunction::PlanExplainsStop (Event *event_ptr)
{
LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP|LIBLLDB_LOG_PROCESS));
m_real_stop_info_sp = GetPrivateStopReason();
// If our subplan knows why we stopped, even if it's done (which would forward the question to us)
// we answer yes.
if (m_subplan_sp.get() != NULL && m_subplan_sp->PlanExplainsStop())
if (m_subplan_sp.get() != NULL && m_subplan_sp->PlanExplainsStop(event_ptr))
{
SetPlanComplete();
return true;
@ -355,16 +366,15 @@ ThreadPlanCallFunction::PlanExplainsStop ()
stop_reason = eStopReasonNone;
else
stop_reason = m_real_stop_info_sp->GetStopReason();
if (log)
log->Printf ("ThreadPlanCallFunction::PlanExplainsStop: Got stop reason - %s.", Thread::StopReasonAsCString(stop_reason));
if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop())
return true;
// If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
if (!m_unwind_on_error)
return false;
// Otherwise, check the case where we stopped for an internal breakpoint, in that case, continue on.
// If it is not an internal breakpoint, consult OkayToDiscard.
// We control breakpoints separately from other "stop reasons." So first,
// check the case where we stopped for an internal breakpoint, in that case, continue on.
// If it is not an internal breakpoint, consult m_ignore_breakpoints.
if (stop_reason == eStopReasonBreakpoint)
@ -381,6 +391,8 @@ ThreadPlanCallFunction::PlanExplainsStop ()
for (uint32_t i = 0; i < num_owners; i++)
{
Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
if (log)
log->Printf ("ThreadPlanCallFunction::PlanExplainsStop: hit breakpoint %d while calling function", bp.GetID());
if (!bp.IsInternal())
{
@ -389,16 +401,32 @@ ThreadPlanCallFunction::PlanExplainsStop ()
}
}
if (is_internal)
{
if (log)
log->Printf ("ThreadPlanCallFunction::PlanExplainsStop hit an internal breakpoint, not stopping.");
return false;
}
}
if (m_ignore_breakpoints)
{
DoTakedown(false);
if (log)
log->Printf("ThreadPlanCallFunction::PlanExplainsStop: we are ignoring breakpoints, overriding breakpoint stop info ShouldStop, returning true");
m_real_stop_info_sp->OverrideShouldStop(false);
return true;
}
else
{
if (log)
log->Printf("ThreadPlanCallFunction::PlanExplainsStop: we are not ignoring breakpoints, overriding breakpoint stop info ShouldStop, returning true");
m_real_stop_info_sp->OverrideShouldStop(true);
return false;
}
}
else if (!m_unwind_on_error)
{
// If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
return false;
}
else
{
@ -406,19 +434,25 @@ ThreadPlanCallFunction::PlanExplainsStop ()
// If we want to discard the plan, then we say we explain the stop
// but if we are going to be discarded, let whoever is above us
// explain the stop.
SetPlanComplete(false);
if (m_subplan_sp)
// But don't discard the plan if the stop would restart itself (for instance if it is a
// signal that is set not to stop. Check that here first. We just say we explain the stop
// but aren't done and everything will continue on from there.
if (m_real_stop_info_sp->ShouldStopSynchronous(event_ptr))
{
if (m_unwind_on_error)
SetPlanComplete(false);
if (m_subplan_sp)
{
DoTakedown(false);
return true;
if (m_unwind_on_error)
return true;
else
return false;
}
else
return false;
}
else
return false;
return true;
}
}
@ -427,14 +461,11 @@ ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
{
// We do some computation in PlanExplainsStop that may or may not set the plan as complete.
// We need to do that here to make sure our state is correct.
PlanExplainsStop();
PlanExplainsStop(event_ptr);
if (IsPlanComplete())
{
ReportRegisterState ("Function completed. Register state was:");
DoTakedown(true);
return true;
}
else
@ -495,12 +526,6 @@ ThreadPlanCallFunction::MischiefManaged ()
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (PlanExplainsStop() && !IsPlanComplete())
{
if (log)
log->Printf ("ThreadPlanCallFunction: Got into MischiefManaged, explained stop but was not complete.");
}
if (IsPlanComplete())
{
if (log)

View File

@ -188,7 +188,7 @@ ThreadPlanRunToAddress::ValidatePlan (Stream *error)
}
bool
ThreadPlanRunToAddress::PlanExplainsStop ()
ThreadPlanRunToAddress::PlanExplainsStop (Event *event_ptr)
{
return AtOurAddress();
}

View File

@ -351,7 +351,7 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
}
bool
ThreadPlanStepInRange::PlanExplainsStop ()
ThreadPlanStepInRange::PlanExplainsStop (Event *event_ptr)
{
// We always explain a stop. Either we've just done a single step, in which
// case we'll do our ordinary processing, or we stopped for some

View File

@ -81,7 +81,7 @@ ThreadPlanStepInstruction::ValidatePlan (Stream *error)
}
bool
ThreadPlanStepInstruction::PlanExplainsStop ()
ThreadPlanStepInstruction::PlanExplainsStop (Event *event_ptr)
{
StopInfoSP stop_info_sp = GetPrivateStopReason();
if (stop_info_sp)

View File

@ -174,7 +174,7 @@ ThreadPlanStepOut::ValidatePlan (Stream *error)
}
bool
ThreadPlanStepOut::PlanExplainsStop ()
ThreadPlanStepOut::PlanExplainsStop (Event *event_ptr)
{
// If one of our child plans just finished, then we do explain the stop.
if (m_step_out_plan_sp)

View File

@ -58,7 +58,7 @@ ThreadPlanStepOverBreakpoint::ValidatePlan (Stream *error)
}
bool
ThreadPlanStepOverBreakpoint::PlanExplainsStop ()
ThreadPlanStepOverBreakpoint::PlanExplainsStop (Event *event_ptr)
{
StopInfoSP stop_info_sp = GetPrivateStopReason();
if (stop_info_sp)

View File

@ -290,7 +290,7 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
}
bool
ThreadPlanStepOverRange::PlanExplainsStop ()
ThreadPlanStepOverRange::PlanExplainsStop (Event *event_ptr)
{
// For crashes, breakpoint hits, signals, etc, let the base plan (or some plan above us)
// handle the stop. That way the user can see the stop, step around, and then when they

View File

@ -139,7 +139,7 @@ ThreadPlanStepThrough::ValidatePlan (Stream *error)
}
bool
ThreadPlanStepThrough::PlanExplainsStop ()
ThreadPlanStepThrough::PlanExplainsStop (Event *event_ptr)
{
// If we have a sub-plan, it will have been asked first if we explain the stop, and
// we won't get asked. The only time we would be the one directly asked this question

View File

@ -305,7 +305,7 @@ ThreadPlanStepUntil::AnalyzeStop()
}
bool
ThreadPlanStepUntil::PlanExplainsStop ()
ThreadPlanStepUntil::PlanExplainsStop (Event *event_ptr)
{
// We don't explain signals or breakpoints (breakpoints that handle stepping in or
// out will be handled by a child plan.

View File

@ -32,6 +32,7 @@ def stop_if_called_from_a():
should_stop = False
dbg.SetAsync(old_async)
print >> sys.stdout, "stop_if_called_from_a returning: ", should_stop
return should_stop

View File

@ -973,11 +973,32 @@ Driver::HandleProcessEvent (const SBEvent &event)
// Make sure the program hasn't been auto-restarted:
if (SBProcess::GetRestartedFromEvent (event))
{
size_t num_reasons = SBProcess::GetNumRestartedReasonsFromEvent(event);
if (num_reasons > 0)
{
// FIXME: Do we want to report this, or would that just be annoyingly chatty?
char message[1024];
int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " stopped and was programmatically restarted.\n",
if (num_reasons == 1)
{
char message[1024];
const char *reason = SBProcess::GetRestartedReasonAtIndexFromEvent (event, 0);
int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " stopped and restarted: %s\n",
process.GetProcessID(), reason ? reason : "<UNKNOWN REASON>");
m_io_channel_ap->OutWrite(message, message_len, ASYNC);
}
else
{
char message[1024];
int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " stopped and restarted, reasons:\n",
process.GetProcessID());
m_io_channel_ap->OutWrite(message, message_len, ASYNC);
m_io_channel_ap->OutWrite(message, message_len, ASYNC);
for (size_t i = 0; i < num_reasons; i++)
{
const char *reason = SBProcess::GetRestartedReasonAtIndexFromEvent (event, i);
int message_len = ::snprintf(message, sizeof(message), "\t%s\n", reason ? reason : "<UNKNOWN REASON>");
m_io_channel_ap->OutWrite(message, message_len, ASYNC);
}
}
}
}
else
{