Ensure that the ShouldStopHere plans get called even when doing "virtual" steps.
llvm-svn: 163366
This commit is contained in:
@@ -46,7 +46,8 @@ ThreadPlanStepInRange::ThreadPlanStepInRange
|
||||
) :
|
||||
ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
|
||||
ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
|
||||
m_step_past_prologue (true)
|
||||
m_step_past_prologue (true),
|
||||
m_virtual_step (false)
|
||||
{
|
||||
SetFlagsToDefault ();
|
||||
}
|
||||
@@ -86,113 +87,122 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
|
||||
|
||||
ThreadPlan* new_plan = NULL;
|
||||
|
||||
// Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
|
||||
// continuing...
|
||||
|
||||
bool stop_others;
|
||||
if (m_stop_others != lldb::eAllThreads)
|
||||
stop_others = true;
|
||||
else
|
||||
stop_others = false;
|
||||
|
||||
FrameComparison frame_order = CompareCurrentFrameToStartFrame();
|
||||
|
||||
if (frame_order == eFrameCompareOlder)
|
||||
if (m_virtual_step)
|
||||
{
|
||||
// If we're in an older frame then we should stop.
|
||||
//
|
||||
// A caveat to this is if we think the frame is older but we're actually in a trampoline.
|
||||
// I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are
|
||||
// in a trampoline we think the frame is older because the trampoline confused the backtracer.
|
||||
new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
|
||||
if (new_plan == NULL)
|
||||
return true;
|
||||
else if (log)
|
||||
{
|
||||
log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
|
||||
}
|
||||
|
||||
}
|
||||
else if (frame_order == eFrameCompareEqual && InSymbol())
|
||||
{
|
||||
// If we are not in a place we should step through, we're done.
|
||||
// One tricky bit here is that some stubs don't push a frame, so we have to check
|
||||
// both the case of a frame that is younger, or the same as this frame.
|
||||
// However, if the frame is the same, and we are still in the symbol we started
|
||||
// in, the we don't need to do this. This first check isn't strictly necessary,
|
||||
// but it is more efficient.
|
||||
|
||||
// If we're still in the range, keep going, either by running to the next branch breakpoint, or by
|
||||
// stepping.
|
||||
if (InRange())
|
||||
{
|
||||
SetNextBranchBreakpoint();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetPlanComplete();
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
|
||||
ClearNextBranchBreakpoint();
|
||||
|
||||
// We may have set the plan up above in the FrameIsOlder section:
|
||||
|
||||
if (new_plan == NULL)
|
||||
new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
|
||||
|
||||
if (log)
|
||||
{
|
||||
if (new_plan != NULL)
|
||||
log->Printf ("Found a step through plan: %s", new_plan->GetName());
|
||||
else
|
||||
log->Printf ("No step through plan found.");
|
||||
}
|
||||
|
||||
// If not, give the "should_stop" callback a chance to push a plan to get us out of here.
|
||||
// But only do that if we actually have stepped in.
|
||||
if (!new_plan && frame_order == eFrameCompareYounger)
|
||||
// If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise
|
||||
// we're done.
|
||||
new_plan = InvokeShouldStopHereCallback();
|
||||
|
||||
// If we've stepped in and we are going to stop here, check to see if we were asked to
|
||||
// run past the prologue, and if so do that.
|
||||
|
||||
if (new_plan == NULL && frame_order == eFrameCompareYounger && m_step_past_prologue)
|
||||
}
|
||||
else
|
||||
{
|
||||
lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
|
||||
if (curr_frame)
|
||||
// Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
|
||||
// continuing...
|
||||
|
||||
bool stop_others;
|
||||
if (m_stop_others != lldb::eAllThreads)
|
||||
stop_others = true;
|
||||
else
|
||||
stop_others = false;
|
||||
|
||||
FrameComparison frame_order = CompareCurrentFrameToStartFrame();
|
||||
|
||||
if (frame_order == eFrameCompareOlder)
|
||||
{
|
||||
size_t bytes_to_skip = 0;
|
||||
lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
|
||||
Address func_start_address;
|
||||
|
||||
SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
|
||||
|
||||
if (sc.function)
|
||||
// If we're in an older frame then we should stop.
|
||||
//
|
||||
// A caveat to this is if we think the frame is older but we're actually in a trampoline.
|
||||
// I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are
|
||||
// in a trampoline we think the frame is older because the trampoline confused the backtracer.
|
||||
new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
|
||||
if (new_plan == NULL)
|
||||
return true;
|
||||
else if (log)
|
||||
{
|
||||
func_start_address = sc.function->GetAddressRange().GetBaseAddress();
|
||||
if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
|
||||
bytes_to_skip = sc.function->GetPrologueByteSize();
|
||||
}
|
||||
else if (sc.symbol)
|
||||
{
|
||||
func_start_address = sc.symbol->GetAddress();
|
||||
if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
|
||||
bytes_to_skip = sc.symbol->GetPrologueByteSize();
|
||||
log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
|
||||
}
|
||||
|
||||
}
|
||||
else if (frame_order == eFrameCompareEqual && InSymbol())
|
||||
{
|
||||
// If we are not in a place we should step through, we're done.
|
||||
// One tricky bit here is that some stubs don't push a frame, so we have to check
|
||||
// both the case of a frame that is younger, or the same as this frame.
|
||||
// However, if the frame is the same, and we are still in the symbol we started
|
||||
// in, the we don't need to do this. This first check isn't strictly necessary,
|
||||
// but it is more efficient.
|
||||
|
||||
if (bytes_to_skip != 0)
|
||||
// If we're still in the range, keep going, either by running to the next branch breakpoint, or by
|
||||
// stepping.
|
||||
if (InRange())
|
||||
{
|
||||
func_start_address.Slide (bytes_to_skip);
|
||||
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
|
||||
if (log)
|
||||
log->Printf ("Pushing past prologue ");
|
||||
|
||||
new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
|
||||
SetNextBranchBreakpoint();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetPlanComplete();
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
|
||||
ClearNextBranchBreakpoint();
|
||||
|
||||
// We may have set the plan up above in the FrameIsOlder section:
|
||||
|
||||
if (new_plan == NULL)
|
||||
new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
|
||||
|
||||
if (log)
|
||||
{
|
||||
if (new_plan != NULL)
|
||||
log->Printf ("Found a step through plan: %s", new_plan->GetName());
|
||||
else
|
||||
log->Printf ("No step through plan found.");
|
||||
}
|
||||
|
||||
// If not, give the "should_stop" callback a chance to push a plan to get us out of here.
|
||||
// But only do that if we actually have stepped in.
|
||||
if (!new_plan && frame_order == eFrameCompareYounger)
|
||||
new_plan = InvokeShouldStopHereCallback();
|
||||
|
||||
// If we've stepped in and we are going to stop here, check to see if we were asked to
|
||||
// run past the prologue, and if so do that.
|
||||
|
||||
if (new_plan == NULL && frame_order == eFrameCompareYounger && m_step_past_prologue)
|
||||
{
|
||||
lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
|
||||
if (curr_frame)
|
||||
{
|
||||
size_t bytes_to_skip = 0;
|
||||
lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
|
||||
Address func_start_address;
|
||||
|
||||
SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
|
||||
|
||||
if (sc.function)
|
||||
{
|
||||
func_start_address = sc.function->GetAddressRange().GetBaseAddress();
|
||||
if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
|
||||
bytes_to_skip = sc.function->GetPrologueByteSize();
|
||||
}
|
||||
else if (sc.symbol)
|
||||
{
|
||||
func_start_address = sc.symbol->GetAddress();
|
||||
if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
|
||||
bytes_to_skip = sc.symbol->GetPrologueByteSize();
|
||||
}
|
||||
|
||||
if (bytes_to_skip != 0)
|
||||
{
|
||||
func_start_address.Slide (bytes_to_skip);
|
||||
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
|
||||
if (log)
|
||||
log->Printf ("Pushing past prologue ");
|
||||
|
||||
new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (new_plan == NULL)
|
||||
{
|
||||
@@ -306,6 +316,9 @@ ThreadPlanStepInRange::PlanExplainsStop ()
|
||||
// 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.
|
||||
|
||||
if (m_virtual_step)
|
||||
return true;
|
||||
|
||||
StopInfoSP stop_info_sp = GetPrivateStopReason();
|
||||
if (stop_info_sp)
|
||||
{
|
||||
@@ -347,6 +360,10 @@ ThreadPlanStepInRange::WillResume (lldb::StateType resume_state, bool current_pl
|
||||
log->Printf ("ThreadPlanStepInRange::WillResume: returning false, inline_depth: %d",
|
||||
m_thread.GetCurrentInlinedDepth());
|
||||
SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread));
|
||||
|
||||
// FIXME: Maybe it would be better to create a InlineStep stop reason, but then
|
||||
// the whole rest of the world would have to handle that stop reason.
|
||||
m_virtual_step = true;
|
||||
}
|
||||
return !step_without_resume;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user