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[])
git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@170008 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp
index f4339a4..1e51245 100644
--- a/source/Target/ThreadPlanStepInRange.cpp
+++ b/source/Target/ThreadPlanStepInRange.cpp
@@ -52,6 +52,23 @@
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 @@
{
s->Printf ("Stepping through range (stepping into functions): ");
DumpRanges(s);
+ s->Printf ("targeting %s.", m_step_into_target.AsCString());
}
}
@@ -140,6 +158,7 @@
}
SetPlanComplete();
+ m_no_more_plans = true;
return true;
}
@@ -279,15 +298,40 @@
}
}
- 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 @@
// 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 @@
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;