summaryrefslogtreecommitdiffstats
path: root/lldb
diff options
context:
space:
mode:
Diffstat (limited to 'lldb')
-rw-r--r--lldb/include/lldb/API/SBThread.h3
-rw-r--r--lldb/include/lldb/Target/Thread.h46
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepInRange.h22
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepOverRange.h7
-rw-r--r--lldb/scripts/Python/interface/SBThread.i3
-rw-r--r--lldb/source/API/SBThread.cpp34
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp27
-rw-r--r--lldb/source/Target/Thread.cpp39
-rw-r--r--lldb/source/Target/ThreadPlanStepInRange.cpp62
-rw-r--r--lldb/test/lang/c/stepping/TestStepAndBreakpoints.py65
-rw-r--r--lldb/test/lang/c/stepping/main.c15
11 files changed, 265 insertions, 58 deletions
diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h
index 62abed16452..20f7e1ae842 100644
--- a/lldb/include/lldb/API/SBThread.h
+++ b/lldb/include/lldb/API/SBThread.h
@@ -99,6 +99,9 @@ public:
StepInto (lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
void
+ StepInto (const char *target_name, lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
+
+ void
StepOut ();
void
diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h
index 8eb320270b3..1e2e584c8c4 100644
--- a/lldb/include/lldb/Target/Thread.h
+++ b/lldb/include/lldb/Target/Thread.h
@@ -480,8 +480,8 @@ public:
bool stop_other_threads);
//------------------------------------------------------------------
- /// Queues the plan used to step through an address range, stepping into or over
- /// function calls depending on the value of StepType.
+ /// Queues the plan used to step through an address range, stepping over
+ /// function calls.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
@@ -507,10 +507,48 @@ public:
/// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual ThreadPlan *
- QueueThreadPlanForStepRange (bool abort_other_plans,
- StepType type,
+ QueueThreadPlanForStepOverRange (bool abort_other_plans,
const AddressRange &range,
const SymbolContext &addr_context,
+ lldb::RunMode stop_other_threads);
+
+ //------------------------------------------------------------------
+ /// Queues the plan used to step through an address range, stepping into functions.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @param[in] type
+ /// Type of step to do, only eStepTypeInto and eStepTypeOver are supported by this plan.
+ ///
+ /// @param[in] range
+ /// The address range to step through.
+ ///
+ /// @param[in] addr_context
+ /// When dealing with stepping through inlined functions the current PC is not enough information to know
+ /// what "step" means. For instance a series of nested inline functions might start at the same address.
+ // The \a addr_context provides the current symbol context the step
+ /// is supposed to be out of.
+ // FIXME: Currently unused.
+ ///
+ /// @param[in] step_in_target
+ /// Name if function we are trying to step into. We will step out if we don't land in that function.
+ ///
+ /// @param[in] stop_other_threads
+ /// \b true if we will stop other threads while we single step this one.
+ ///
+ /// @param[in] avoid_code_without_debug_info
+ /// If \b true we will step out if we step into code with no debug info.
+ ///
+ /// @return
+ /// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual ThreadPlan *
+ QueueThreadPlanForStepInRange (bool abort_other_plans,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_in_target,
lldb::RunMode stop_other_threads,
bool avoid_code_without_debug_info);
diff --git a/lldb/include/lldb/Target/ThreadPlanStepInRange.h b/lldb/include/lldb/Target/ThreadPlanStepInRange.h
index a0562126945..b7b89636cb3 100644
--- a/lldb/include/lldb/Target/ThreadPlanStepInRange.h
+++ b/lldb/include/lldb/Target/ThreadPlanStepInRange.h
@@ -32,6 +32,12 @@ public:
const SymbolContext &addr_context,
lldb::RunMode stop_others);
+ ThreadPlanStepInRange (Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_into_function_name,
+ lldb::RunMode stop_others);
+
virtual
~ThreadPlanStepInRange ();
@@ -43,6 +49,11 @@ public:
void SetAvoidRegexp(const char *name);
+ void SetStepInTarget (const char *target)
+ {
+ m_step_into_target.SetCString(target);
+ }
+
static ThreadPlan *
DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton);
@@ -65,10 +76,15 @@ protected:
private:
friend ThreadPlan *
- Thread::QueueThreadPlanForStepRange (bool abort_other_plans,
- StepType type,
+ Thread::QueueThreadPlanForStepOverRange (bool abort_other_plans,
const AddressRange &range,
const SymbolContext &addr_context,
+ lldb::RunMode stop_others);
+ friend ThreadPlan *
+ Thread::QueueThreadPlanForStepInRange (bool abort_other_plans,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_in_target,
lldb::RunMode stop_others,
bool avoid_code_without_debug_info);
@@ -81,7 +97,7 @@ private:
bool m_step_past_prologue; // FIXME: For now hard-coded to true, we could put a switch in for this if there's
// demand for that.
bool m_virtual_step; // true if we've just done a "virtual step", i.e. just moved the inline stack depth.
-
+ ConstString m_step_into_target;
DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepInRange);
};
diff --git a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h
index 7423856a896..5f3a4355e9c 100644
--- a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h
+++ b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h
@@ -41,13 +41,6 @@ protected:
private:
- friend ThreadPlan *
- Thread::QueueThreadPlanForStepRange (bool abort_other_plans,
- StepType type,
- const AddressRange &range,
- const SymbolContext &addr_context,
- lldb::RunMode stop_others,
- bool avoid_code_without_debug_info);
bool m_first_resume;
DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepOverRange);
diff --git a/lldb/scripts/Python/interface/SBThread.i b/lldb/scripts/Python/interface/SBThread.i
index 0401ec13a42..e597c07d2db 100644
--- a/lldb/scripts/Python/interface/SBThread.i
+++ b/lldb/scripts/Python/interface/SBThread.i
@@ -124,6 +124,9 @@ public:
StepInto (lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
void
+ StepInto (const char *target_name, lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
+
+ void
StepOut ();
void
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index 2e5b7b70410..c1e834bbd92 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -564,13 +564,10 @@ SBThread::StepOver (lldb::RunMode stop_other_threads)
if (frame_sp->HasDebugInformation ())
{
SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
- new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans,
- eStepTypeOver,
- sc.line_entry.range,
- sc,
- stop_other_threads,
- false);
-
+ new_plan = thread->QueueThreadPlanForStepOverRange (abort_other_plans,
+ sc.line_entry.range,
+ sc,
+ stop_other_threads);
}
else
{
@@ -588,14 +585,23 @@ SBThread::StepOver (lldb::RunMode stop_other_threads)
void
SBThread::StepInto (lldb::RunMode stop_other_threads)
{
+ StepInto (NULL, stop_other_threads);
+}
+
+void
+SBThread::StepInto (const char *target_name, lldb::RunMode stop_other_threads)
+{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
Mutex::Locker api_locker;
ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
if (log)
- log->Printf ("SBThread(%p)::StepInto (stop_other_threads='%s')", exe_ctx.GetThreadPtr(),
+ log->Printf ("SBThread(%p)::StepInto (target_name='%s', stop_other_threads='%s')",
+ exe_ctx.GetThreadPtr(),
+ target_name? target_name: "<NULL>",
Thread::RunModeAsCString (stop_other_threads));
+
if (exe_ctx.HasThreadScope())
{
bool abort_other_plans = false;
@@ -608,12 +614,12 @@ SBThread::StepInto (lldb::RunMode stop_other_threads)
{
bool avoid_code_without_debug_info = true;
SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
- new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans,
- eStepTypeInto,
- sc.line_entry.range,
- sc,
- stop_other_threads,
- avoid_code_without_debug_info);
+ new_plan = thread->QueueThreadPlanForStepInRange (abort_other_plans,
+ sc.line_entry.range,
+ sc,
+ target_name,
+ stop_other_threads,
+ avoid_code_without_debug_info);
}
else
{
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index b5fa5192371..7a58441fb3c 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -325,6 +325,13 @@ public:
}
break;
+ case 't':
+ {
+ m_step_in_target.clear();
+ m_step_in_target.assign(option_arg);
+
+ }
+ break;
default:
error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
break;
@@ -339,6 +346,7 @@ public:
m_avoid_no_debug = true;
m_run_mode = eOnlyDuringStepping;
m_avoid_regexp.clear();
+ m_step_in_target.clear();
}
const OptionDefinition*
@@ -355,6 +363,7 @@ public:
bool m_avoid_no_debug;
RunMode m_run_mode;
std::string m_avoid_regexp;
+ std::string m_step_in_target;
};
CommandObjectThreadStepWithTypeAndScope (CommandInterpreter &interpreter,
@@ -469,9 +478,10 @@ protected:
if (frame->HasDebugInformation ())
{
- new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, m_step_type,
+ new_plan = thread->QueueThreadPlanForStepInRange (abort_other_plans,
frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
- frame->GetSymbolContext(eSymbolContextEverything),
+ frame->GetSymbolContext(eSymbolContextEverything),
+ m_options.m_step_in_target.c_str(),
stop_other_threads,
m_options.m_avoid_no_debug);
if (new_plan && !m_options.m_avoid_regexp.empty())
@@ -489,12 +499,10 @@ protected:
StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
if (frame->HasDebugInformation())
- new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans,
- m_step_type,
- frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
- frame->GetSymbolContext(eSymbolContextEverything),
- stop_other_threads,
- false);
+ new_plan = thread->QueueThreadPlanForStepOverRange (abort_other_plans,
+ frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
+ frame->GetSymbolContext(eSymbolContextEverything),
+ stop_other_threads);
else
new_plan = thread->QueueThreadPlanForStepSingleInstruction (true,
abort_other_plans,
@@ -595,7 +603,8 @@ CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_1, false, "avoid-no-debug", 'a', required_argument, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether step-in will step over functions with no debug information."},
{ LLDB_OPT_SET_1, false, "run-mode", 'm', required_argument, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."},
-{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', required_argument, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to step over."},
+{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', required_argument, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."},
+{ LLDB_OPT_SET_1, false, "step-in-target", 't', required_argument, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
};
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index 34b8600a815..7c5a0d7c2fc 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -1188,28 +1188,41 @@ Thread::QueueThreadPlanForStepSingleInstruction
}
ThreadPlan *
-Thread::QueueThreadPlanForStepRange
+Thread::QueueThreadPlanForStepOverRange
(
bool abort_other_plans,
- StepType type,
const AddressRange &range,
- const SymbolContext &addr_context,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_other_threads
+)
+{
+ ThreadPlanSP thread_plan_sp;
+ thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads));
+
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepInRange
+(
+ bool abort_other_plans,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_in_target,
lldb::RunMode stop_other_threads,
bool avoid_code_without_debug_info
)
{
ThreadPlanSP thread_plan_sp;
- if (type == eStepTypeInto)
- {
- ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads);
- if (avoid_code_without_debug_info)
- plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug);
- else
- plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug);
- thread_plan_sp.reset (plan);
- }
+ ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads);
+ if (avoid_code_without_debug_info)
+ plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug);
else
- thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads));
+ plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ if (step_in_target)
+ plan->SetStepInTarget(step_in_target);
+ thread_plan_sp.reset (plan);
QueueThreadPlan (thread_plan_sp, abort_other_plans);
return thread_plan_sp.get();
diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp
index f4339a45cd4..1e512452c9a 100644
--- a/lldb/source/Target/ThreadPlanStepInRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepInRange.cpp
@@ -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)
+ {
+ 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 ();
+ 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;
diff --git a/lldb/test/lang/c/stepping/TestStepAndBreakpoints.py b/lldb/test/lang/c/stepping/TestStepAndBreakpoints.py
index efecc9394a1..3f5a74f0a97 100644
--- a/lldb/test/lang/c/stepping/TestStepAndBreakpoints.py
+++ b/lldb/test/lang/c/stepping/TestStepAndBreakpoints.py
@@ -161,6 +161,71 @@ class TestObjCStepping(TestBase):
self.assertTrue (thread.GetFrameAtIndex(0).GetLineEntry().GetLine() == current_line)
self.assertTrue (thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec() == current_file)
+ # Now we are going to test step in targetting a function:
+
+ break_in_b.SetEnabled (False)
+
+ break_before_complex_1 = target.BreakpointCreateBySourceRegex ('// Stop here to try step in targetting b.', self.main_source_spec)
+ self.assertTrue(break_before_complex_1, VALID_BREAKPOINT)
+
+ break_before_complex_2 = target.BreakpointCreateBySourceRegex ('// Stop here to try step in targetting complex.', self.main_source_spec)
+ self.assertTrue(break_before_complex_2, VALID_BREAKPOINT)
+
+ break_before_complex_3 = target.BreakpointCreateBySourceRegex ('// Stop here to step targetting b and hitting breakpoint.', self.main_source_spec)
+ self.assertTrue(break_before_complex_3, VALID_BREAKPOINT)
+
+ break_before_complex_4 = target.BreakpointCreateBySourceRegex ('// Stop here to make sure bogus target steps over.', self.main_source_spec)
+ self.assertTrue(break_before_complex_4, VALID_BREAKPOINT)
+
+ threads = lldbutil.continue_to_breakpoint(process, break_before_complex_1)
+ self.assertTrue (len(threads) == 1)
+ thread = threads[0]
+ break_before_complex_1.SetEnabled(False)
+
+ thread.StepInto ("b")
+ self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "b")
+
+ # Now continue out and stop at the next call to complex. This time step all the way into complex:
+ threads = lldbutil.continue_to_breakpoint (process, break_before_complex_2)
+ self.assertTrue (len(threads) == 1)
+ thread = threads[0]
+ break_before_complex_2.SetEnabled(False)
+
+ thread.StepInto ("complex")
+ self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "complex")
+
+ # Now continue out and stop at the next call to complex. This time enable breakpoints in a and c and then step targetting b:
+ threads = lldbutil.continue_to_breakpoint (process, break_before_complex_3)
+ self.assertTrue (len(threads) == 1)
+ thread = threads[0]
+ break_before_complex_3.SetEnabled(False)
+
+ break_at_start_of_a = target.BreakpointCreateByName ('a')
+ break_at_start_of_c = target.BreakpointCreateByName ('c')
+
+ thread.StepInto ("b")
+ threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonBreakpoint);
+
+ self.assertTrue (len(threads) == 1)
+ thread = threads[0]
+ stop_break_id = thread.GetStopReasonDataAtIndex(0)
+ self.assertTrue(stop_break_id == break_at_start_of_a.GetID() or stop_break_id == break_at_start_of_c.GetID())
+
+ break_at_start_of_a.SetEnabled(False)
+ break_at_start_of_c.SetEnabled(False)
+
+ process.Continue()
+ self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "b")
+
+ # Now continue out and stop at the next call to complex. This time enable breakpoints in a and c and then step targetting b:
+ threads = lldbutil.continue_to_breakpoint (process, break_before_complex_4)
+ self.assertTrue (len(threads) == 1)
+ thread = threads[0]
+ break_before_complex_4.SetEnabled(False)
+
+ thread.StepInto("NoSuchFunction")
+ self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "main")
+
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
diff --git a/lldb/test/lang/c/stepping/main.c b/lldb/test/lang/c/stepping/main.c
index 624dcddbcfa..599139cfa0b 100644
--- a/lldb/test/lang/c/stepping/main.c
+++ b/lldb/test/lang/c/stepping/main.c
@@ -14,7 +14,7 @@ int c(int);
int a(int val)
{
- int return_value = val;
+ int return_value = val; // basic break at the start of b
if (val <= 1)
{
@@ -39,6 +39,11 @@ int c(int val)
return val + 3; // Find the line number of function "c" here.
}
+int complex (int first, int second, int third)
+{
+ return first + second + third; // Step in targetting complex should stop here
+}
+
int main (int argc, char const *argv[])
{
int A1 = a(1); // frame select 2, thread step-out while stopped at "c(1)"
@@ -50,5 +55,13 @@ int main (int argc, char const *argv[])
int A3 = a(3); // frame select 1, thread step-out while stopped at "c(3)"
printf("a(3) returns %d\n", A3);
+ int A4 = complex (a(1), b(2), c(3)); // Stop here to try step in targetting b.
+
+ int A5 = complex (a(2), b(3), c(4)); // Stop here to try step in targetting complex.
+
+ int A6 = complex (a(4), b(5), c(6)); // Stop here to step targetting b and hitting breakpoint.
+
+ int A7 = complex (a(5), b(6), c(7)); // Stop here to make sure bogus target steps over.
+
return 0;
}
OpenPOWER on IntegriCloud