diff options
Diffstat (limited to 'lldb')
| -rw-r--r-- | lldb/include/lldb/API/SBThread.h | 3 | ||||
| -rw-r--r-- | lldb/include/lldb/Target/Thread.h | 46 | ||||
| -rw-r--r-- | lldb/include/lldb/Target/ThreadPlanStepInRange.h | 22 | ||||
| -rw-r--r-- | lldb/include/lldb/Target/ThreadPlanStepOverRange.h | 7 | ||||
| -rw-r--r-- | lldb/scripts/Python/interface/SBThread.i | 3 | ||||
| -rw-r--r-- | lldb/source/API/SBThread.cpp | 34 | ||||
| -rw-r--r-- | lldb/source/Commands/CommandObjectThread.cpp | 27 | ||||
| -rw-r--r-- | lldb/source/Target/Thread.cpp | 39 | ||||
| -rw-r--r-- | lldb/source/Target/ThreadPlanStepInRange.cpp | 62 | ||||
| -rw-r--r-- | lldb/test/lang/c/stepping/TestStepAndBreakpoints.py | 65 | ||||
| -rw-r--r-- | lldb/test/lang/c/stepping/main.c | 15 |
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; } |

