diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h index 327a3be662ec..343b32f9f72d 100644 --- a/lldb/include/lldb/API/SBThread.h +++ b/lldb/include/lldb/API/SBThread.h @@ -172,6 +172,11 @@ protected: void SetThread (const lldb::ThreadSP& lldb_object_sp); +#ifndef SWIG + SBError + ResumeNewPlan (lldb_private::ExecutionContext &exe_ctx, lldb_private::ThreadPlan *new_plan); +#endif + private: lldb::ExecutionContextRefSP m_opaque_sp; }; diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index 77eb0a8bfe65..ab3e9a9f1642 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -674,6 +674,9 @@ public: void DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp); + void + DiscardThreadPlansUpToPlan (ThreadPlan *up_to_plan_ptr); + //------------------------------------------------------------------ /// Prints the current plan stack. /// diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index 2cb6fea31c1d..42666cb5cb6d 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -115,12 +115,33 @@ namespace lldb_private { // figure out what to do about the plans below it in the stack. If the stop is recoverable, then the plan that // understands it can just do what it needs to set up to restart, and then continue. // Otherwise, the plan that understood the stop should call DiscardPlanStack to clean up the stack below it. -// In the normal case, this will just collapse the plan stack up to the point of the plan that understood +// +// Master plans: +// +// In the normal case, when we decide to stop, we will collapse the plan stack up to the point of the plan that understood // the stop reason. However, if a plan wishes to stay on the stack after an event it didn't directly handle // it can designate itself a "Master" plan by responding true to IsMasterPlan, and then if it wants not to be // discarded, it can return true to OkayToDiscard, and it and all its dependent plans will be preserved when // we resume execution. // +// The other effect of being a master plan is that when the Master plan is done , if it has set "OkayToDiscard" to false, +// then it will be popped & execution will stop and return to the user. Remember that if OkayToDiscard is false, the +// plan will be popped and control will be given to the next plan above it on the stack So setting OkayToDiscard to +// false means the user will regain control when the MasterPlan is completed. +// +// Between these two controls this allows things like: a MasterPlan/DontDiscard Step Over to hit a breakpoint, stop and +// return control to the user, but then when the user continues, the step out succeeds. +// Even more tricky, when the breakpoint is hit, the user can continue to step in/step over/etc, and finally when they +// continue, they will finish up the Step Over. +// +// FIXME: MasterPlan & OkayToDiscard aren't really orthogonal. MasterPlan designation means that this plan controls +// it's fate and the fate of plans below it. OkayToDiscard tells whether the MasterPlan wants to stay on the stack. I +// originally thought "MasterPlan-ness" would need to be a fixed characteristic of a ThreadPlan, in which case you needed +// the extra control. But that doesn't seem to be true. So we should be able to convert to only MasterPlan status to mean +// the current "MasterPlan/DontDiscard". Then no plans would be MasterPlans by default, and you would set the ones you +// wanted to be "user level" in this way. +// +// // Actually Stopping: // // If a plan says responds "true" to ShouldStop, then it is asked if it's job is complete by calling @@ -152,6 +173,18 @@ namespace lldb_private { // because of a crash or breakpoint hit, it wants to unship itself, because it isn't so useful to have step in keep going // after a breakpoint hit. But it can't be the reason for the stop or no-one would see that they had hit a breakpoint. // +// Cleaning up the plan stack: +// +// One of the complications of MasterPlans is that you may get past the limits of a plan without triggering it to clean +// itself up. For instance, if you are doing a MasterPlan StepOver, and hit a breakpoint in a called function, then +// step over enough times to step out of the initial StepOver range, each of the step overs will explain the stop & +// take themselves off the stack, but control would never be returned to the original StepOver. Eventually, the user +// will continue, and when that continue stops, the old stale StepOver plan that was left on the stack will get woken +// up and notice it is done. But that can leave junk on the stack for a while. To avoid that, the plans implement a +// "IsPlanStale" method, that can check whether it is relevant anymore. On stop, after the regular plan negotiation, +// the remaining plan stack is consulted and if any plan says it is stale, it and the plans below it are discarded from +// the stack. +// // Automatically Resuming: // // If ShouldStop for all threads returns "false", then the target process will resume. This then cycles back to @@ -408,6 +441,12 @@ public: void SetPlanComplete (bool success = true); + virtual bool + IsPlanStale () + { + return false; + } + bool PlanSucceeded () { diff --git a/lldb/include/lldb/Target/ThreadPlanStepOut.h b/lldb/include/lldb/Target/ThreadPlanStepOut.h index b08abfc24e7f..af1c68b96bbb 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepOut.h +++ b/lldb/include/lldb/Target/ThreadPlanStepOut.h @@ -42,6 +42,7 @@ public: virtual bool WillStop (); virtual bool MischiefManaged (); virtual void DidPush(); + virtual bool IsPlanStale(); virtual lldb::ValueObjectSP GetReturnValueObject() { diff --git a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h index 23e8e959bda8..21ede83ae6d2 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h +++ b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h @@ -28,8 +28,7 @@ public: ThreadPlanStepOverRange (Thread &thread, const AddressRange &range, const SymbolContext &addr_context, - lldb::RunMode stop_others, - bool okay_to_discard = false); + lldb::RunMode stop_others); virtual ~ThreadPlanStepOverRange (); diff --git a/lldb/include/lldb/Target/ThreadPlanStepRange.h b/lldb/include/lldb/Target/ThreadPlanStepRange.h index 3ca5b3a574dd..f53e4d86c372 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepRange.h +++ b/lldb/include/lldb/Target/ThreadPlanStepRange.h @@ -43,6 +43,7 @@ public: virtual bool WillStop (); virtual bool MischiefManaged (); virtual void DidPush (); + virtual bool IsPlanStale (); void AddRange(const AddressRange &new_range); diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 16fff466cf54..6e74c597ed1f 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -4082,10 +4082,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(NATIVE_ARCH)"; "ARCHS[sdk=iphoneos*]" = armv7; - "ARCHS[sdk=macosx*]" = ( - x86_64, - i386, - ); + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_C_LANGUAGE_STANDARD = gnu99; diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index 811096728fd1..7d8398daec79 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -474,6 +474,47 @@ SBThread::GetQueueName () const return name; } +SBError +SBThread::ResumeNewPlan (ExecutionContext &exe_ctx, ThreadPlan *new_plan) +{ + SBError sb_error; + + Process *process = exe_ctx.GetProcessPtr(); + if (!process) + { + sb_error.SetErrorString("No process in SBThread::ResumeNewPlan"); + return sb_error; + } + + Thread *thread = exe_ctx.GetThreadPtr(); + if (!thread) + { + sb_error.SetErrorString("No thread in SBThread::ResumeNewPlan"); + return sb_error; + } + + // User level plans should be Master Plans so they can be interrupted, other plans executed, and + // then a "continue" will resume the plan. + if (new_plan != NULL) + { + new_plan->SetIsMasterPlan(true); + new_plan->SetOkayToDiscard(false); + } + + // Why do we need to set the current thread by ID here??? + process->GetThreadList().SetSelectedThreadByID (thread->GetID()); + sb_error.ref() = process->Resume(); + + if (sb_error.Success()) + { + // If we are doing synchronous mode, then wait for the + // process to stop yet again! + if (process->GetTarget().GetDebugger().GetAsyncExecution () == false) + process->WaitForProcessToStop (NULL); + } + + return sb_error; +} void SBThread::StepOver (lldb::RunMode stop_other_threads) @@ -492,39 +533,31 @@ SBThread::StepOver (lldb::RunMode stop_other_threads) Thread *thread = exe_ctx.GetThreadPtr(); bool abort_other_plans = true; StackFrameSP frame_sp(thread->GetStackFrameAtIndex (0)); + ThreadPlan *new_plan = NULL; if (frame_sp) { if (frame_sp->HasDebugInformation ()) { SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); - thread->QueueThreadPlanForStepRange (abort_other_plans, - eStepTypeOver, - sc.line_entry.range, - sc, - stop_other_threads, - false); + new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, + eStepTypeOver, + sc.line_entry.range, + sc, + stop_other_threads, + false); } else { - thread->QueueThreadPlanForStepSingleInstruction (true, - abort_other_plans, - stop_other_threads); + new_plan = thread->QueueThreadPlanForStepSingleInstruction (true, + abort_other_plans, + stop_other_threads); } } - Process *process = exe_ctx.GetProcessPtr(); - // Why do we need to set the current thread by ID here??? - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - Error error (process->Resume()); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop yet again! - if (process->GetTarget().GetDebugger().GetAsyncExecution () == false) - process->WaitForProcessToStop (NULL); - } + // This returns an error, we should use it! + ResumeNewPlan (exe_ctx, new_plan); } } @@ -545,36 +578,28 @@ SBThread::StepInto (lldb::RunMode stop_other_threads) Thread *thread = exe_ctx.GetThreadPtr(); StackFrameSP frame_sp(thread->GetStackFrameAtIndex (0)); + ThreadPlan *new_plan = NULL; if (frame_sp && frame_sp->HasDebugInformation ()) { bool avoid_code_without_debug_info = true; SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); - thread->QueueThreadPlanForStepRange (abort_other_plans, - eStepTypeInto, - sc.line_entry.range, - sc, - stop_other_threads, - avoid_code_without_debug_info); + new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, + eStepTypeInto, + sc.line_entry.range, + sc, + stop_other_threads, + avoid_code_without_debug_info); } else { - thread->QueueThreadPlanForStepSingleInstruction (false, - abort_other_plans, - stop_other_threads); - } - - Process *process = exe_ctx.GetProcessPtr(); - // Why do we need to set the current thread by ID here??? - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - Error error (process->Resume()); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop yet again! - if (process->GetTarget().GetDebugger().GetAsyncExecution () == false) - process->WaitForProcessToStop (NULL); + new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, + abort_other_plans, + stop_other_threads); } + + // This returns an error, we should use it! + ResumeNewPlan (exe_ctx, new_plan); } } @@ -596,24 +621,16 @@ SBThread::StepOut () Thread *thread = exe_ctx.GetThreadPtr(); - thread->QueueThreadPlanForStepOut (abort_other_plans, - NULL, - false, - stop_other_threads, - eVoteYes, - eVoteNoOpinion, - 0); - - Process *process = exe_ctx.GetProcessPtr(); - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - Error error (process->Resume()); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop yet again! - if (process->GetTarget().GetDebugger().GetAsyncExecution () == false) - process->WaitForProcessToStop (NULL); - } + ThreadPlan *new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, + NULL, + false, + stop_other_threads, + eVoteYes, + eVoteNoOpinion, + 0); + + // This returns an error, we should use it! + ResumeNewPlan (exe_ctx, new_plan); } } @@ -638,24 +655,16 @@ SBThread::StepOutOfFrame (lldb::SBFrame &sb_frame) bool stop_other_threads = true; Thread *thread = exe_ctx.GetThreadPtr(); - thread->QueueThreadPlanForStepOut (abort_other_plans, - NULL, - false, - stop_other_threads, - eVoteYes, - eVoteNoOpinion, - frame_sp->GetFrameIndex()); - - Process *process = exe_ctx.GetProcessPtr(); - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - Error error (process->Resume()); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop yet again! - if (process->GetTarget().GetDebugger().GetAsyncExecution () == false) - process->WaitForProcessToStop (NULL); - } + ThreadPlan *new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, + NULL, + false, + stop_other_threads, + eVoteYes, + eVoteNoOpinion, + frame_sp->GetFrameIndex()); + + // This returns an error, we should use it! + ResumeNewPlan (exe_ctx, new_plan); } } @@ -674,17 +683,10 @@ SBThread::StepInstruction (bool step_over) { Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); Thread *thread = exe_ctx.GetThreadPtr(); - Process *process = exe_ctx.GetProcessPtr(); - thread->QueueThreadPlanForStepSingleInstruction (step_over, true, true); - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - Error error (process->Resume()); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop yet again! - if (process->GetTarget().GetDebugger().GetAsyncExecution () == false) - process->WaitForProcessToStop (NULL); - } + ThreadPlan *new_plan = thread->QueueThreadPlanForStepSingleInstruction (step_over, true, true); + + // This returns an error, we should use it! + ResumeNewPlan (exe_ctx, new_plan); } } @@ -707,18 +709,11 @@ SBThread::RunToAddress (lldb::addr_t addr) Address target_addr (addr); Thread *thread = exe_ctx.GetThreadPtr(); - Process *process = exe_ctx.GetProcessPtr(); - thread->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads); - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - Error error (process->Resume()); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop yet again! - if (process->GetTarget().GetDebugger().GetAsyncExecution () == false) - process->WaitForProcessToStop (NULL); - } + ThreadPlan *new_plan = thread->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads); + + // This returns an error, we should use it! + ResumeNewPlan (exe_ctx, new_plan); } } @@ -854,23 +849,13 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame, } else { - thread->QueueThreadPlanForStepUntil (abort_other_plans, - &step_over_until_addrs[0], - step_over_until_addrs.size(), - stop_other_threads, - frame_sp->GetFrameIndex()); + ThreadPlan *new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, + &step_over_until_addrs[0], + step_over_until_addrs.size(), + stop_other_threads, + frame_sp->GetFrameIndex()); - Process *process = exe_ctx.GetProcessPtr(); - - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - sb_error.ref() = process->Resume(); - if (sb_error->Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop yet again! - if (process->GetTarget().GetDebugger().GetAsyncExecution () == false) - process->WaitForProcessToStop (NULL); - } + sb_error = ResumeNewPlan (exe_ctx, new_plan); } } else diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index d6a9670fe0f3..73cc9a2eb1ca 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -451,10 +451,11 @@ public: else bool_stop_other_threads = true; + ThreadPlan *new_plan = NULL; + if (m_step_type == eStepTypeInto) { StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); - ThreadPlan *new_plan; if (frame->HasDebugInformation ()) { @@ -471,14 +472,11 @@ public: } else new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads); - - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - process->Resume (); + } else if (m_step_type == eStepTypeOver) { StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); - ThreadPlan *new_plan; if (frame->HasDebugInformation()) new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, @@ -492,29 +490,17 @@ public: abort_other_plans, bool_stop_other_threads); - // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over. - // Maybe there should be a parameter to control this. - new_plan->SetOkayToDiscard(false); - - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - process->Resume (); } else if (m_step_type == eStepTypeTrace) { - thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads); - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - process->Resume (); + new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads); } else if (m_step_type == eStepTypeTraceOver) { - thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads); - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - process->Resume (); + new_plan = thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads); } else if (m_step_type == eStepTypeOut) { - ThreadPlan *new_plan; - new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, @@ -522,32 +508,46 @@ public: eVoteYes, eVoteNoOpinion, thread->GetSelectedFrameIndex()); - // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over. - // Maybe there should be a parameter to control this. - new_plan->SetOkayToDiscard(false); - - process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - process->Resume (); } else { result.AppendError ("step type is not supported"); result.SetStatus (eReturnStatusFailed); + return false; } - if (synchronous_execution) + + // If we got a new plan, then set it to be a master plan (User level Plans should be master plans + // so that they can be interruptible). Then resume the process. + + if (new_plan != NULL) { - StateType state = process->WaitForProcessToStop (NULL); - - //EventSP event_sp; - //StateType state = process->WaitForStateChangedEvents (NULL, event_sp); - //while (! StateIsStoppedState (state)) - // { - // state = process->WaitForStateChangedEvents (NULL, event_sp); - // } + new_plan->SetIsMasterPlan (true); + new_plan->SetOkayToDiscard (false); + process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - result.SetDidChangeProcessState (true); - result.AppendMessageWithFormat ("Process %llu %s\n", process->GetID(), StateAsCString (state)); - result.SetStatus (eReturnStatusSuccessFinishNoResult); + process->Resume (); + + + if (synchronous_execution) + { + StateType state = process->WaitForProcessToStop (NULL); + + //EventSP event_sp; + //StateType state = process->WaitForStateChangedEvents (NULL, event_sp); + //while (! StateIsStoppedState (state)) + // { + // state = process->WaitForStateChangedEvents (NULL, event_sp); + // } + process->GetThreadList().SetSelectedThreadByID (thread->GetID()); + result.SetDidChangeProcessState (true); + result.AppendMessageWithFormat ("Process %llu %s\n", process->GetID(), StateAsCString (state)); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + else + { + result.AppendError ("Couldn't find thread plan to implement step type."); + result.SetStatus (eReturnStatusFailed); } } return result.Succeeded(); @@ -959,7 +959,7 @@ public: return false; } - ThreadPlan *new_plan; + ThreadPlan *new_plan = NULL; if (frame->HasDebugInformation ()) { @@ -1027,6 +1027,10 @@ public: address_list.size(), m_options.m_stop_others, thread->GetSelectedFrameIndex ()); + // User level plans should be master plans so they can be interrupted (e.g. by hitting a breakpoint) + // and other plans executed by the user (stepping around the breakpoint) and then a "continue" + // will resume the original plan. + new_plan->SetIsMasterPlan (true); new_plan->SetOkayToDiscard(false); } else diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index aaec66576d20..9429bfdb623b 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -455,8 +455,33 @@ Thread::ShouldStop (Event* event_ptr) } } } + if (over_ride_stop) should_stop = false; + + // One other potential problem is that we set up a master plan, then stop in before it is complete - for instance + // by hitting a breakpoint during a step-over - then do some step/finish/etc operations that wind up + // past the end point condition of the initial plan. We don't want to strand the original plan on the stack, + // This code clears stale plans off the stack. + + if (should_stop) + { + ThreadPlan *plan_ptr = GetCurrentPlan(); + while (!PlanIsBasePlan(plan_ptr)) + { + bool stale = plan_ptr->IsPlanStale (); + ThreadPlan *examined_plan = plan_ptr; + plan_ptr = GetPreviousPlan (examined_plan); + + if (stale) + { + if (log) + log->Printf("Plan %s being discarded in cleanup, it says it is already done.", examined_plan->GetName()); + DiscardThreadPlansUpToPlan(examined_plan); + } + } + } + } if (log) @@ -749,11 +774,17 @@ Thread::SetTracer (lldb::ThreadPlanTracerSP &tracer_sp) void Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp) +{ + DiscardThreadPlansUpToPlan (up_to_plan_sp.get()); +} + +void +Thread::DiscardThreadPlansUpToPlan (ThreadPlan *up_to_plan_ptr) { LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); if (log) { - log->Printf("Discarding thread plans for thread tid = 0x%4.4llx, up to %p", GetID(), up_to_plan_sp.get()); + log->Printf("Discarding thread plans for thread tid = 0x%4.4llx, up to %p", GetID(), up_to_plan_ptr); } int stack_size = m_plan_stack.size(); @@ -761,7 +792,7 @@ Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp) // If the input plan is NULL, discard all plans. Otherwise make sure this plan is in the // stack, and if so discard up to and including it. - if (up_to_plan_sp.get() == NULL) + if (up_to_plan_ptr == NULL) { for (int i = stack_size - 1; i > 0; i--) DiscardPlan(); @@ -771,7 +802,7 @@ Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp) bool found_it = false; for (int i = stack_size - 1; i > 0; i--) { - if (m_plan_stack[i] == up_to_plan_sp) + if (m_plan_stack[i].get() == up_to_plan_ptr) found_it = true; } if (found_it) @@ -779,7 +810,7 @@ Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp) bool last_one = false; for (int i = stack_size - 1; i > 0 && !last_one ; i--) { - if (GetCurrentPlan() == up_to_plan_sp.get()) + if (GetCurrentPlan() == up_to_plan_ptr) last_one = true; DiscardPlan(); } diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index 22c2fc4b8ffc..f8c675bc6642 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -36,7 +36,7 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vo m_plan_complete_mutex (Mutex::eMutexTypeRecursive), m_plan_complete (false), m_plan_private (false), - m_okay_to_discard (false), + m_okay_to_discard (true), m_is_master_plan (false), m_plan_succeeded(true) { diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp index c4b9ccac1f3f..a7ae41650cf7 100644 --- a/lldb/source/Target/ThreadPlanStepInstruction.cpp +++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp @@ -131,7 +131,13 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr) s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); log->Printf("%s.", s.GetData()); } - m_thread.QueueThreadPlanForStepOut(false, NULL, true, m_stop_other_threads, eVoteNo, eVoteNoOpinion, 0); + m_thread.QueueThreadPlanForStepOut(false, + NULL, + true, + m_stop_other_threads, + eVoteNo, + eVoteNoOpinion, + 0); return false; } else diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index 58507a80e601..3687f9aca256 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -81,7 +81,6 @@ ThreadPlanStepOut::ThreadPlanStepOut eVoteNoOpinion, eVoteNoOpinion, frame_idx - 1)); - m_step_out_plan_sp->SetOkayToDiscard(true); } else { @@ -468,3 +467,17 @@ ThreadPlanStepOut::CalculateReturnValue () } } } + +bool +ThreadPlanStepOut::IsPlanStale() +{ + // If we are still lower on the stack than the frame we are returning to, then + // there's something for us to do. Otherwise, we're stale. + + StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + if (frame_zero_id < m_step_out_to_id) + return false; + else + return true; +} + diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp index 933983bb7d12..1bbbfb3cb5a1 100644 --- a/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -38,15 +38,10 @@ ThreadPlanStepOverRange::ThreadPlanStepOverRange Thread &thread, const AddressRange &range, const SymbolContext &addr_context, - lldb::RunMode stop_others, - bool okay_to_discard + lldb::RunMode stop_others ) : ThreadPlanStepRange (ThreadPlan::eKindStepOverRange, "Step range stepping over", thread, range, addr_context, stop_others) { - // Step over range plans can be master plans, since you could hit a breakpoint while stepping over, step around - // a bit, then continue to finish up the step over. - SetIsMasterPlan (true); - SetOkayToDiscard (okay_to_discard); } ThreadPlanStepOverRange::~ThreadPlanStepOverRange () diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 91fc998fbaa4..14ed8b660750 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -403,3 +403,30 @@ ThreadPlanStepRange::MischiefManaged () } } + +bool +ThreadPlanStepRange::IsPlanStale () +{ + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + FrameComparison frame_order = CompareCurrentFrameToStartFrame(); + + if (frame_order == eFrameCompareOlder) + { + if (log) + { + log->Printf("ThreadPlanStepRange::IsPlanStale returning true, we've stepped out."); + } + return true; + } + else if (frame_order == eFrameCompareEqual && InSymbol()) + { + // If we are not in a place we should step through, we've gotten stale. + // One tricky bit here is that some stubs don't push a frame, so we should. + // check that we are in the same symbol. + if (!InRange()) + { + return true; + } + } + return false; +} diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp index 3c418f20aca9..ae0047af9910 100644 --- a/lldb/source/Target/ThreadPlanStepUntil.cpp +++ b/lldb/source/Target/ThreadPlanStepUntil.cpp @@ -51,12 +51,6 @@ ThreadPlanStepUntil::ThreadPlanStepUntil m_until_points (), m_stop_others (stop_others) { - - // Step until plans can be master plans, since you could hit a breakpoint while stepping to the stop point, step around - // a bit, then continue to finish up the step until. - SetIsMasterPlan (true); - SetOkayToDiscard(true); - // Stash away our "until" addresses: TargetSP target_sp (m_thread.CalculateTarget()); diff --git a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj index 972d643306fb..9983afe5aa8d 100644 --- a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj +++ b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj @@ -514,10 +514,7 @@ armv7, armv7s, ); - "ARCHS[sdk=macosx*]" = ( - x86_64, - i386, - ); + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; CURRENT_PROJECT_VERSION = 186; DEAD_CODE_STRIPPING = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0;