mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 13:35:38 +08:00
Fixed a few bugs in the "step in" thread plan logic.
Added a "step-in-target" flag to "thread step-in" so if you have something like: Process 28464 stopped * thread #1: tid = 0x1c03, function: main , stop reason = breakpoint 1.1 frame #0: 0x0000000100000e08 a.out`main at main.c:62 61 -> 62 int A6 = complex (a(4), b(5), c(6)); // Stop here to step targetting b and hitting breakpoint. 63 and you want to get into "complex" skipping a, b and c, you can do: (lldb) step -t complex Process 28464 stopped * thread #1: tid = 0x1c03, function: complex , stop reason = step in frame #0: 0x0000000100000d0d a.out`complex at main.c:44 41 42 int complex (int first, int second, int third) 43 { -> 44 return first + second + third; // Step in targetting complex should stop here 45 } 46 47 int main (int argc, char const *argv[]) llvm-svn: 170008
This commit is contained in:
@@ -52,6 +52,23 @@ ThreadPlanStepInRange::ThreadPlanStepInRange
|
||||
SetFlagsToDefault ();
|
||||
}
|
||||
|
||||
ThreadPlanStepInRange::ThreadPlanStepInRange
|
||||
(
|
||||
Thread &thread,
|
||||
const AddressRange &range,
|
||||
const SymbolContext &addr_context,
|
||||
const char *step_into_target,
|
||||
lldb::RunMode stop_others
|
||||
) :
|
||||
ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
|
||||
ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
|
||||
m_step_past_prologue (true),
|
||||
m_virtual_step (false),
|
||||
m_step_into_target (step_into_target)
|
||||
{
|
||||
SetFlagsToDefault ();
|
||||
}
|
||||
|
||||
ThreadPlanStepInRange::~ThreadPlanStepInRange ()
|
||||
{
|
||||
}
|
||||
@@ -65,6 +82,7 @@ ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
|
||||
{
|
||||
s->Printf ("Stepping through range (stepping into functions): ");
|
||||
DumpRanges(s);
|
||||
s->Printf ("targeting %s.", m_step_into_target.AsCString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +158,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
|
||||
}
|
||||
|
||||
SetPlanComplete();
|
||||
m_no_more_plans = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -279,15 +298,40 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
|
||||
}
|
||||
}
|
||||
|
||||
if (!should_step_out)
|
||||
if (current_plan->GetKind() == eKindStepInRange)
|
||||
{
|
||||
if (current_plan->GetKind() == eKindStepInRange)
|
||||
ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
|
||||
if (step_in_range_plan->m_step_into_target)
|
||||
{
|
||||
ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
|
||||
should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
|
||||
SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
|
||||
if (sc.symbol != NULL)
|
||||
{
|
||||
// First try an exact match, since that's cheap with ConstStrings. Then do a strstr compare.
|
||||
if (step_in_range_plan->m_step_into_target == sc.GetFunctionName())
|
||||
{
|
||||
should_step_out = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *target_name = step_in_range_plan->m_step_into_target.AsCString();
|
||||
const char *function_name = sc.GetFunctionName().AsCString();
|
||||
|
||||
if (function_name == NULL)
|
||||
should_step_out = true;
|
||||
else if (strstr (function_name, target_name) == NULL)
|
||||
should_step_out = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!should_step_out)
|
||||
{
|
||||
ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
|
||||
should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (should_step_out)
|
||||
{
|
||||
// FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
|
||||
@@ -313,8 +357,12 @@ ThreadPlanStepInRange::PlanExplainsStop ()
|
||||
// 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.
|
||||
// In general, we don't want to mark the plan as complete for unexplained stops.
|
||||
// For instance, if you step in to some code with no debug info, so you step out
|
||||
// and in the course of that hit a breakpoint, then you want to stop & show the user
|
||||
// the breakpoint, but not unship the step in plan, since you still may want to complete that
|
||||
// plan when you continue. This is particularly true when doing "step in to target function."
|
||||
// stepping.
|
||||
//
|
||||
// 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.
|
||||
@@ -340,8 +388,8 @@ ThreadPlanStepInRange::PlanExplainsStop ()
|
||||
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
|
||||
if (log)
|
||||
log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
|
||||
SetPlanComplete(false);
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user