From fbbfe6ecf0a400b26e6b6839a8d06bd8be46ad2a Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Tue, 1 May 2012 18:38:37 +0000 Subject: [PATCH] Fix reporting of stop reasons when the StepOver & StepIn plans stop because of a crash or breakpoint. Added the ability for a plan to say it is done but doesn't want to be the reason for the stop. llvm-svn: 155927 --- lldb/include/lldb/Target/ThreadPlan.h | 19 +++++++++- .../lldb/Target/ThreadPlanStepInRange.h | 3 ++ .../lldb/Target/ThreadPlanStepOverRange.h | 1 + .../include/lldb/Target/ThreadPlanStepRange.h | 1 - lldb/source/Target/Thread.cpp | 2 +- lldb/source/Target/ThreadPlan.cpp | 6 ++- lldb/source/Target/ThreadPlanStepInRange.cpp | 38 +++++++++++++++++++ .../source/Target/ThreadPlanStepOverRange.cpp | 38 +++++++++++++++++++ lldb/source/Target/ThreadPlanStepRange.cpp | 36 ------------------ 9 files changed, 103 insertions(+), 41 deletions(-) diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index 090c473adf3f..2cb6fea31c1d 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -142,6 +142,16 @@ namespace lldb_private { // all threads will be called, the stop event is placed on the Process's public broadcaster, and // control returns to the upper layers of the debugger. // +// Reporting the stop: +// +// When the process stops, the thread is given a StopReason, in the form of a StopInfo object. If there is a completed +// plan corresponding to the stop, then the "actual" stop reason will be suppressed, and instead a StopInfoThreadPlan +// object will be cons'ed up from the highest completed plan in the stack. However, if the plan doesn't want to be +// the stop reason, then it can call SetPlanComplete and pass in "false" for the "success" parameter. In that case, +// the real stop reason will be used instead. One exapmle of this is the "StepRangeStepIn" thread plan. If it stops +// because of a crash or breakpoint hit, it wants to unship itself, because it isn't so useful to have step in keep going +// after a breakpoint hit. But it can't be the reason for the stop or no-one would see that they had hit a breakpoint. +// // Automatically Resuming: // // If ShouldStop for all threads returns "false", then the target process will resume. This then cycles back to @@ -396,7 +406,13 @@ public: IsPlanComplete(); void - SetPlanComplete (); + SetPlanComplete (bool success = true); + + bool + PlanSucceeded () + { + return m_plan_succeeded; + } virtual bool IsBasePlan() @@ -489,6 +505,7 @@ private: bool m_plan_private; bool m_okay_to_discard; bool m_is_master_plan; + bool m_plan_succeeded; lldb::ThreadPlanTracerSP m_tracer_sp; diff --git a/lldb/include/lldb/Target/ThreadPlanStepInRange.h b/lldb/include/lldb/Target/ThreadPlanStepInRange.h index 7eb571777d52..664cedeb1d0d 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepInRange.h +++ b/lldb/include/lldb/Target/ThreadPlanStepInRange.h @@ -49,6 +49,9 @@ public: static void SetDefaultFlagValue (uint32_t new_value); + virtual bool + PlanExplainsStop (); + protected: virtual void diff --git a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h index 39b1414f27bd..23e8e959bda8 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h +++ b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h @@ -35,6 +35,7 @@ public: virtual void GetDescription (Stream *s, lldb::DescriptionLevel level); virtual bool ShouldStop (Event *event_ptr); + virtual bool PlanExplainsStop (); protected: diff --git a/lldb/include/lldb/Target/ThreadPlanStepRange.h b/lldb/include/lldb/Target/ThreadPlanStepRange.h index dc1021d71ade..3ca5b3a574dd 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepRange.h +++ b/lldb/include/lldb/Target/ThreadPlanStepRange.h @@ -42,7 +42,6 @@ public: virtual lldb::StateType GetPlanRunState (); virtual bool WillStop (); virtual bool MischiefManaged (); - virtual bool PlanExplainsStop (); virtual void DidPush (); diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 7445ffc06f29..aaec66576d20 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -97,7 +97,7 @@ lldb::StopInfoSP Thread::GetStopInfo () { ThreadPlanSP plan_sp (GetCompletedPlan()); - if (plan_sp) + if (plan_sp && plan_sp->PlanSucceeded()) return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject()); else { diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index 5f396d94755c..22c2fc4b8ffc 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -37,7 +37,8 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vo m_plan_complete (false), m_plan_private (false), m_okay_to_discard (false), - m_is_master_plan (false) + m_is_master_plan (false), + m_plan_succeeded(true) { SetID (GetNextID()); } @@ -57,10 +58,11 @@ ThreadPlan::IsPlanComplete () } void -ThreadPlan::SetPlanComplete () +ThreadPlan::SetPlanComplete (bool success) { Mutex::Locker locker(m_plan_complete_mutex); m_plan_complete = true; + m_plan_succeeded = success; } bool diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 9fbca6b03f71..0db23a114b81 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -295,3 +295,41 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, return NULL; } + +bool +ThreadPlanStepInRange::PlanExplainsStop () +{ + // 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 + // reason that isn't handled by our sub-plans, in which case we want to just stop right + // away. + // We also set ourselves complete when we stop for this sort of unintended reason, but mark + // success as false so we don't end up being the reason for the stop. + // + // The only variation is that if we are doing "step by running to next branch" in which case + // if we hit our branch breakpoint we don't set the plan to complete. + + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + StopInfoSP stop_info_sp = GetPrivateStopReason(); + if (stop_info_sp) + { + StopReason reason = stop_info_sp->GetStopReason(); + + switch (reason) + { + case eStopReasonBreakpoint: + if (NextRangeBreakpointExplainsStop(stop_info_sp)) + return true; + case eStopReasonWatchpoint: + case eStopReasonSignal: + case eStopReasonException: + if (log) + log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step."); + SetPlanComplete(false); + break; + default: + break; + } + } + return true; +} diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp index c147e83b19ed..933983bb7d12 100644 --- a/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -170,3 +170,41 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr) else return false; } + +bool +ThreadPlanStepOverRange::PlanExplainsStop () +{ + // 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 + // are done, continue and have their step complete. The exception is if we've hit our + // "run to next branch" breakpoint. + // Note, unlike the step in range plan, we don't mark ourselves complete if we hit an + // unexplained breakpoint/crash. + + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + StopInfoSP stop_info_sp = GetPrivateStopReason(); + if (stop_info_sp) + { + StopReason reason = stop_info_sp->GetStopReason(); + + switch (reason) + { + case eStopReasonBreakpoint: + if (NextRangeBreakpointExplainsStop(stop_info_sp)) + return true; + else + return false; + break; + case eStopReasonWatchpoint: + case eStopReasonSignal: + case eStopReasonException: + if (log) + log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step."); + return false; + break; + default: + break; + } + } + return true; +} diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 113e45963eac..91fc998fbaa4 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -349,42 +349,6 @@ ThreadPlanStepRange::NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info return bp_site_sp->GetNumberOfOwners() == 1; } -bool -ThreadPlanStepRange::PlanExplainsStop () -{ - // 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 - // reason that isn't handled by our sub-plans, in which case we want to just stop right - // away. - - LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - StopInfoSP stop_info_sp = GetPrivateStopReason(); - if (stop_info_sp) - { - StopReason reason = stop_info_sp->GetStopReason(); - - switch (reason) - { - case eStopReasonBreakpoint: - if (NextRangeBreakpointExplainsStop(stop_info_sp)) - return true; - else - return false; - break; - case eStopReasonWatchpoint: - case eStopReasonSignal: - case eStopReasonException: - if (log) - log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step."); - SetPlanComplete(); - break; - default: - break; - } - } - return true; -} - bool ThreadPlanStepRange::WillStop () {