[Lldb-commits] [lldb] r156529 - in /lldb/trunk: include/lldb/Target/ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/ source/Target/ test/lang/objc/objc-stepping/

Jim Ingham jingham at apple.com
Wed May 9 18:35:39 PDT 2012


Author: jingham
Date: Wed May  9 20:35:39 2012
New Revision: 156529

URL: http://llvm.org/viewvc/llvm-project?rev=156529&view=rev
Log:
If the ObjC Step Through Trampoline plan causes a target crash, properly propagate the error back to
the controlling plans so that they don't lose control.

Also change "ThreadPlanStepThrough" to take the return StackID for its backstop breakpoint as an argument
to the constructor rather than having it try to figure it out itself, since it might get it wrong whereas
the caller always knows where it is coming from.

rdar://problem/11402287

Modified:
    lldb/trunk/include/lldb/Target/Thread.h
    lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
    lldb/trunk/include/lldb/Target/ThreadPlanStepThrough.h
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
    lldb/trunk/source/Target/Thread.cpp
    lldb/trunk/source/Target/ThreadPlan.cpp
    lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
    lldb/trunk/source/Target/ThreadPlanStepInRange.cpp
    lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp
    lldb/trunk/source/Target/ThreadPlanStepThrough.cpp
    lldb/trunk/test/lang/objc/objc-stepping/TestObjCStepping.py
    lldb/trunk/test/lang/objc/objc-stepping/stepping-tests.m

Modified: lldb/trunk/include/lldb/Target/Thread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Thread.h (original)
+++ lldb/trunk/include/lldb/Target/Thread.h Wed May  9 20:35:39 2012
@@ -521,6 +521,11 @@
     /// Gets the plan used to step through the code that steps from a function
     /// call site at the current PC into the actual function call.
     ///
+    ///
+    /// @param[in] return_stack_id
+    ///    The stack id that we will return to (by setting backstop breakpoints on the return
+    ///    address to that frame) if we fail to step through.
+    ///
     /// @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.
@@ -532,7 +537,8 @@
     ///     A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
     //------------------------------------------------------------------
     virtual ThreadPlan *
-    QueueThreadPlanForStepThrough (bool abort_other_plans,
+    QueueThreadPlanForStepThrough (StackID &return_stack_id,
+                                   bool abort_other_plans,
                                    bool stop_other_threads);
 
     //------------------------------------------------------------------

Modified: lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h Wed May  9 20:35:39 2012
@@ -139,7 +139,7 @@
                       lldb::addr_t &function_load_addr);
 
     void
-    DoTakedown ();
+    DoTakedown (bool success);
     
     void
     SetBreakpoints ();

Modified: lldb/trunk/include/lldb/Target/ThreadPlanStepThrough.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanStepThrough.h?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanStepThrough.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlanStepThrough.h Wed May  9 20:35:39 2012
@@ -37,6 +37,7 @@
 
 protected:
     ThreadPlanStepThrough (Thread &thread,
+                           StackID &return_stack_id,
                            bool stop_others);
 
     void
@@ -47,14 +48,17 @@
 
 private:
     friend ThreadPlan *
-    Thread::QueueThreadPlanForStepThrough (bool abort_other_plans,
+    Thread::QueueThreadPlanForStepThrough (StackID &return_stack_id,
+                                           bool abort_other_plans,
                                            bool stop_others);
+                                           
+    void ClearBackstopBreakpoint();
 
     lldb::ThreadPlanSP m_sub_plan_sp;
     lldb::addr_t      m_start_address;
     lldb::break_id_t  m_backstop_bkpt_id;
     lldb::addr_t      m_backstop_addr;
-    StackID           m_stack_id;
+    StackID           m_return_stack_id;
     bool              m_stop_others;
 
     DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepThrough);

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp Wed May  9 20:35:39 2012
@@ -125,9 +125,10 @@
 bool
 AppleThreadPlanStepThroughObjCTrampoline::PlanExplainsStop ()
 {
-    // This plan should actually never stop when it is on the top of the plan
-    // stack, since it does all it's running in client plans.
-    return false;
+    // If we get asked to explain the stop it will be because something went
+    // wrong (like the implementation for selector function crashed...  We're going
+    // to figure out what to do about that, so we do explain the stop.
+    return true;
 }
 
 lldb::StateType
@@ -139,66 +140,83 @@
 bool
 AppleThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr)
 {
-    if (m_func_sp.get() == NULL || m_thread.IsThreadPlanDone(m_func_sp.get()))
+    // First stage: we are still handling the "call a function to get the target of the dispatch"
+    if (m_func_sp)
     {
-        m_func_sp.reset();
-        if (!m_run_to_sp) 
+        if (!m_func_sp->IsPlanComplete())
+        {
+            return false;
+        }
+        else
         {
-            Value target_addr_value;
-            ExecutionContext exc_ctx;
-            m_thread.CalculateExecutionContext(exc_ctx);
-            m_impl_function->FetchFunctionResults (exc_ctx, m_args_addr, target_addr_value);
-            m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr);
-            lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong();
-            Address target_so_addr;
-            target_so_addr.SetOpcodeLoadAddress(target_addr, exc_ctx.GetTargetPtr());
-            LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
-            if (target_addr == 0)
+            if (!m_func_sp->PlanSucceeded())
             {
-                if (log)
-                    log->Printf("Got target implementation of 0x0, stopping.");
-                SetPlanComplete();
+                SetPlanComplete(false);
                 return true;
             }
-            if (m_trampoline_handler->AddrIsMsgForward(target_addr))
-            {
-                if (log)
-                    log->Printf ("Implementation lookup returned msgForward function: 0x%llx, stopping.", target_addr);
-
-                SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(eSymbolContextEverything);
-                m_run_to_sp.reset(new ThreadPlanStepOut (m_thread, 
-                                                         &sc, 
-                                                         true, 
-                                                         m_stop_others, 
-                                                         eVoteNoOpinion, 
-                                                         eVoteNoOpinion,
-                                                         0));
-                m_thread.QueueThreadPlan(m_run_to_sp, false);
-                m_run_to_sp->SetPrivate(true);
-                return false;
-            }
-            
+            m_func_sp.reset();
+        }
+    }
+    
+    // Second stage, if all went well with the function calling, then fetch the target address, and
+    // queue up a "run to that address" plan.
+    if (!m_run_to_sp) 
+    {
+        Value target_addr_value;
+        ExecutionContext exc_ctx;
+        m_thread.CalculateExecutionContext(exc_ctx);
+        m_impl_function->FetchFunctionResults (exc_ctx, m_args_addr, target_addr_value);
+        m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr);
+        lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong();
+        Address target_so_addr;
+        target_so_addr.SetOpcodeLoadAddress(target_addr, exc_ctx.GetTargetPtr());
+        LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+        if (target_addr == 0)
+        {
             if (log)
-                log->Printf("Running to ObjC method implementation: 0x%llx", target_addr);
-            
-            ObjCLanguageRuntime *objc_runtime = GetThread().GetProcess()->GetObjCLanguageRuntime();
-            assert (objc_runtime != NULL);
-            objc_runtime->AddToMethodCache (m_isa_addr, m_sel_addr, target_addr);
+                log->Printf("Got target implementation of 0x0, stopping.");
+            SetPlanComplete();
+            return true;
+        }
+        if (m_trampoline_handler->AddrIsMsgForward(target_addr))
+        {
             if (log)
-                log->Printf("Adding {isa-addr=0x%llx, sel-addr=0x%llx} = addr=0x%llx to cache.", m_isa_addr, m_sel_addr, target_addr);
+                log->Printf ("Implementation lookup returned msgForward function: 0x%llx, stopping.", target_addr);
 
-            // Extract the target address from the value:
-            
-            m_run_to_sp.reset(new ThreadPlanRunToAddress(m_thread, target_so_addr, m_stop_others));
+            SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(eSymbolContextEverything);
+            m_run_to_sp.reset(new ThreadPlanStepOut (m_thread, 
+                                                     &sc, 
+                                                     true, 
+                                                     m_stop_others, 
+                                                     eVoteNoOpinion, 
+                                                     eVoteNoOpinion,
+                                                     0));
             m_thread.QueueThreadPlan(m_run_to_sp, false);
             m_run_to_sp->SetPrivate(true);
             return false;
         }
-        else if (m_thread.IsThreadPlanDone(m_run_to_sp.get()))
-        {
-            SetPlanComplete();
-            return true;
-        }
+        
+        if (log)
+            log->Printf("Running to ObjC method implementation: 0x%llx", target_addr);
+        
+        ObjCLanguageRuntime *objc_runtime = GetThread().GetProcess()->GetObjCLanguageRuntime();
+        assert (objc_runtime != NULL);
+        objc_runtime->AddToMethodCache (m_isa_addr, m_sel_addr, target_addr);
+        if (log)
+            log->Printf("Adding {isa-addr=0x%llx, sel-addr=0x%llx} = addr=0x%llx to cache.", m_isa_addr, m_sel_addr, target_addr);
+
+        // Extract the target address from the value:
+        
+        m_run_to_sp.reset(new ThreadPlanRunToAddress(m_thread, target_so_addr, m_stop_others));
+        m_thread.QueueThreadPlan(m_run_to_sp, false);
+        m_run_to_sp->SetPrivate(true);
+        return false;
+    }
+    else if (m_thread.IsThreadPlanDone(m_run_to_sp.get()))
+    {
+        // Third stage, work the run to target plan.
+        SetPlanComplete();
+        return true;
     }
     return false;
 }

Modified: lldb/trunk/source/Target/Thread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Wed May  9 20:35:39 2012
@@ -976,9 +976,9 @@
 }
 
 ThreadPlan *
-Thread::QueueThreadPlanForStepThrough (bool abort_other_plans, bool stop_other_threads)
+Thread::QueueThreadPlanForStepThrough (StackID &return_stack_id, bool abort_other_plans, bool stop_other_threads)
 {
-    ThreadPlanSP thread_plan_sp(new ThreadPlanStepThrough (*this, stop_other_threads));
+    ThreadPlanSP thread_plan_sp(new ThreadPlanStepThrough (*this, return_stack_id, stop_other_threads));
     if (!thread_plan_sp || !thread_plan_sp->ValidatePlan (NULL))
         return NULL;
 

Modified: lldb/trunk/source/Target/ThreadPlan.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlan.cpp?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlan.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlan.cpp Wed May  9 20:35:39 2012
@@ -69,6 +69,7 @@
 ThreadPlan::MischiefManaged ()
 {
     Mutex::Locker locker(m_plan_complete_mutex);
+    // Mark the plan is complete, but don't override the success flag.
     m_plan_complete = true;
     return true;
 }

Modified: lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallFunction.cpp?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallFunction.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanCallFunction.cpp Wed May  9 20:35:39 2012
@@ -228,7 +228,7 @@
 
 ThreadPlanCallFunction::~ThreadPlanCallFunction ()
 {
-    DoTakedown();
+    DoTakedown(true);
 }
 
 void
@@ -260,7 +260,7 @@
 }
 
 void
-ThreadPlanCallFunction::DoTakedown ()
+ThreadPlanCallFunction::DoTakedown (bool success)
 {
     LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
     
@@ -274,21 +274,23 @@
     
     if (!m_takedown_done)
     {
-        ProcessSP process_sp (m_thread.GetProcess());
-        const ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
-        if (abi && m_return_type.IsValid())
+        if (success)
         {
-            const bool persistent = false;
-            m_return_valobj_sp = abi->GetReturnValueObject (m_thread, m_return_type, persistent);
+            ProcessSP process_sp (m_thread.GetProcess());
+            const ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+            if (abi && m_return_type.IsValid())
+            {
+                const bool persistent = false;
+                m_return_valobj_sp = abi->GetReturnValueObject (m_thread, m_return_type, persistent);
+            }
         }
-
         if (log)
             log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4llx, m_valid: %d complete: %d.\n", this, m_thread.GetID(), m_valid, IsPlanComplete());
         m_takedown_done = true;
         m_stop_address = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
         m_real_stop_info_sp = GetPrivateStopReason();
         m_thread.RestoreThreadStateFromCheckpoint(m_stored_thread_state);
-        SetPlanComplete();
+        SetPlanComplete(success);
         ClearBreakpoints();
         if (log && log->GetVerbose())
             ReportRegisterState ("Restoring thread state after function call.  Restored register state:");
@@ -304,7 +306,7 @@
 void
 ThreadPlanCallFunction::WillPop ()
 {
-    DoTakedown();
+    DoTakedown(true);
 }
 
 void
@@ -342,7 +344,13 @@
     
     // Check if the breakpoint is one of ours.
     
-    if (BreakpointsExplainStop())
+    StopReason stop_reason;
+    if (!m_real_stop_info_sp)
+        stop_reason = eStopReasonNone;
+    else
+        stop_reason = m_real_stop_info_sp->GetStopReason();
+
+    if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop())
         return true;
     
     // If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
@@ -352,7 +360,8 @@
     // Otherwise, check the case where we stopped for an internal breakpoint, in that case, continue on.
     // If it is not an internal breakpoint, consult OkayToDiscard.
     
-    if (m_real_stop_info_sp && m_real_stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
+    
+    if (stop_reason == eStopReasonBreakpoint)
     {
         ProcessSP process_sp (m_thread.CalculateProcess());
         uint64_t break_site_id = m_real_stop_info_sp->GetValue();
@@ -385,7 +394,18 @@
         // If we want to discard the plan, then we say we explain the stop
         // but if we are going to be discarded, let whoever is above us
         // explain the stop.
-        return ((m_subplan_sp.get() != NULL) && !OkayToDiscard());
+        if (m_subplan_sp != NULL)
+        {
+            if (OkayToDiscard())
+            {
+                DoTakedown(false);
+                return true;
+            }
+            else
+                return false;
+        }
+        else
+            return false;
     }
 }
 
@@ -396,7 +416,7 @@
     {
         ReportRegisterState ("Function completed.  Register state was:");
         
-        DoTakedown();
+        DoTakedown(true);
         
         return true;
     }

Modified: lldb/trunk/source/Target/ThreadPlanStepInRange.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanStepInRange.cpp?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanStepInRange.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanStepInRange.cpp Wed May  9 20:35:39 2012
@@ -104,7 +104,7 @@
         // A caveat to this is if we think the frame is older but we're actually in a trampoline.
         // I'm going to make the assumption that you wouldn't RETURN to a trampoline.  So if we are
         // in a trampoline we think the frame is older because the trampoline confused the backtracer.
-        new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+        new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
         if (new_plan == NULL)
             return true;
         else if (log)
@@ -140,7 +140,7 @@
     // We may have set the plan up above in the FrameIsOlder section:
     
     if (new_plan == NULL)
-        new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+        new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
     
     if (log)
     {

Modified: lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp Wed May  9 20:35:39 2012
@@ -95,7 +95,7 @@
         // in a trampoline we think the frame is older because the trampoline confused the backtracer.
         // As below, we step through first, and then try to figure out how to get back out again.
         
-        new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+        new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
 
         if (new_plan != NULL && log)
             log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
@@ -122,7 +122,7 @@
             }
             else 
             {
-                new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+                new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
                 
             }
         }
@@ -143,7 +143,7 @@
             // in which case we need to get out of there.  But if we are in a stub then it's 
             // likely going to be hard to get out from here.  It is probably easiest to step into the
             // stub, and then it will be straight-forward to step out.        
-            new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+            new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
         }
     }
 

Modified: lldb/trunk/source/Target/ThreadPlanStepThrough.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanStepThrough.cpp?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanStepThrough.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanStepThrough.cpp Wed May  9 20:35:39 2012
@@ -32,11 +32,12 @@
 // FIXME: At present only handles DYLD trampolines.
 //----------------------------------------------------------------------
 
-ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, bool stop_others) :
+ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, StackID &m_stack_id, bool stop_others) :
     ThreadPlan (ThreadPlan::eKindStepThrough, "Step through trampolines and prologues", thread, eVoteNoOpinion, eVoteNoOpinion),
     m_start_address (0),
     m_backstop_bkpt_id (LLDB_INVALID_BREAK_ID),
     m_backstop_addr(LLDB_INVALID_ADDRESS),
+    m_return_stack_id (m_stack_id),
     m_stop_others (stop_others)
 {
 
@@ -46,12 +47,11 @@
     if (m_sub_plan_sp)
     {
         m_start_address = GetThread().GetRegisterContext()->GetPC(0);
-        m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
                 
         // We are going to return back to the concrete frame 1, we might pass by some inlined code that we're in 
         // the middle of by doing this, but it's easier than trying to figure out where the inlined code might return to.
             
-        StackFrameSP return_frame_sp (m_thread.GetFrameWithConcreteFrameIndex(1));
+        StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID (m_stack_id);
         
         if (return_frame_sp)
         {
@@ -73,11 +73,7 @@
 
 ThreadPlanStepThrough::~ThreadPlanStepThrough ()
 {
-    if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
-    {
-        m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id);
-        m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
-    }
+    ClearBackstopBreakpoint ();
 }
 
 void
@@ -161,6 +157,13 @@
     if (IsPlanComplete())
         return true;
         
+    // First, did we hit the backstop breakpoint?
+    if (HitOurBackstopBreakpoint())
+    {
+        SetPlanComplete(false);
+        return true;
+    }
+
     // If we don't have a sub-plan, then we're also done (can't see how we would ever get here
     // without a plan, but just in case.
     
@@ -170,20 +173,27 @@
         return true;
     }
     
-    // First, did we hit the backstop breakpoint?
-    if (HitOurBackstopBreakpoint())
-    {
-        SetPlanComplete();
-        return true;
-    }
-
-
     // If the current sub plan is not done, we don't want to stop.  Actually, we probably won't
     // ever get here in this state, since we generally won't get asked any questions if out
     // current sub-plan is not done...
     if (!m_sub_plan_sp->IsPlanComplete())
+        return false;
+    
+    // If our current sub plan failed, then let's just run to our backstop.  If we can't do that then just stop.
+    if (!m_sub_plan_sp->PlanSucceeded())
+    {
+        if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
+        {
+            m_sub_plan_sp.reset();
             return false;
-            
+        }
+        else
+        {
+            SetPlanComplete(false);
+            return true;
+        }
+    }
+        
     // Next see if there is a specific step through plan at our current pc (these might 
     // chain, for instance stepping through a dylib trampoline to the objc dispatch function...)
     LookForPlanToStepThroughFromCurrentPC();
@@ -208,7 +218,7 @@
 StateType
 ThreadPlanStepThrough::GetPlanRunState ()
 {
-    return eStateStepping;
+    return eStateRunning;
 }
 
 bool
@@ -224,14 +234,21 @@
     return true;
 }
 
+void
+ThreadPlanStepThrough::ClearBackstopBreakpoint ()
+{
+    if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
+    {
+        m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id);
+        m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
+    }
+}
+
 bool
 ThreadPlanStepThrough::MischiefManaged ()
 {
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
 
-    // ShouldStop will call HappyToStopHere, which will set the plan to complete if
-    // we're done.  So we can just check that here.
-
     if (!IsPlanComplete())
     {
         return false;
@@ -240,12 +257,9 @@
     {
         if (log)
             log->Printf("Completed step through step plan.");
+            
+        ClearBackstopBreakpoint ();
         ThreadPlan::MischiefManaged ();
-        if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
-        {
-            m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id);
-            m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
-        }
         return true;
     }
 }
@@ -262,7 +276,7 @@
         {
             StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
             
-            if (cur_frame_zero_id == m_stack_id)
+            if (cur_frame_zero_id == m_return_stack_id)
             {
                 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
                 if (log)

Modified: lldb/trunk/test/lang/objc/objc-stepping/TestObjCStepping.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/objc/objc-stepping/TestObjCStepping.py?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/test/lang/objc/objc-stepping/TestObjCStepping.py (original)
+++ lldb/trunk/test/lang/objc/objc-stepping/TestObjCStepping.py Wed May  9 20:35:39 2012
@@ -34,6 +34,7 @@
         self.sourceBase_randomMethod_line = line_number (self.main_source, '// SourceBase randomMethod start line.')
         self.source_returnsStruct_start_line = line_number (self.main_source, '// Source returnsStruct start line.')
         self.sourceBase_returnsStruct_start_line = line_number (self.main_source, '// SourceBase returnsStruct start line.')
+        self.stepped_past_nil_line = line_number (self.main_source, '// Step over nil should stop here.')
 
     def objc_stepping(self):
         """Use Python APIs to test stepping into ObjC methods."""
@@ -43,23 +44,35 @@
         self.assertTrue(target, VALID_TARGET)
 
         self.main_source_spec = lldb.SBFileSpec (self.main_source)
+
+        breakpoints_to_disable = []
+
         break1 = target.BreakpointCreateBySourceRegex ("// Set first breakpoint here.", self.main_source_spec)
         self.assertTrue(break1, VALID_BREAKPOINT)
+        breakpoints_to_disable.append (break1)
 
         break2 = target.BreakpointCreateBySourceRegex ("// Set second breakpoint here.", self.main_source_spec)
         self.assertTrue(break2, VALID_BREAKPOINT)
+        breakpoints_to_disable.append (break2)
 
         break3 = target.BreakpointCreateBySourceRegex ('// Set third breakpoint here.', self.main_source_spec)
         self.assertTrue(break3, VALID_BREAKPOINT)
+        breakpoints_to_disable.append (break3)
 
         break4 = target.BreakpointCreateBySourceRegex ('// Set fourth breakpoint here.', self.main_source_spec)
         self.assertTrue(break4, VALID_BREAKPOINT)
+        breakpoints_to_disable.append (break4)
 
         break5 = target.BreakpointCreateBySourceRegex ('// Set fifth breakpoint here.', self.main_source_spec)
         self.assertTrue(break5, VALID_BREAKPOINT)
+        breakpoints_to_disable.append (break5)
 
         break_returnStruct_call_super = target.BreakpointCreateBySourceRegex ('// Source returnsStruct call line.', self.main_source_spec)
         self.assertTrue(break_returnStruct_call_super, VALID_BREAKPOINT)
+        breakpoints_to_disable.append (break_returnStruct_call_super)
+
+        break_step_nil = target.BreakpointCreateBySourceRegex ('// Set nil step breakpoint here.', self.main_source_spec)
+        self.assertTrue(break_step_nil, VALID_BREAKPOINT)
 
         # Now launch the process, and do not stop at entry point.
         process = target.LaunchSimple (None, None, os.getcwd())
@@ -155,6 +168,15 @@
         line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
         self.assertTrue (line_number == self.sourceBase_returnsStruct_start_line, "Stepped through super into SourceBase returnsStruct in swizzled object.")
 
+        for bkpt in breakpoints_to_disable:
+            bkpt.SetEnabled(False)
+
+        threads = lldbutil.continue_to_breakpoint (process, break_step_nil)
+        self.assertTrue (len(threads) == 1, "Continued to step nil breakpoint.")
+
+        thread.StepInto()
+        line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
+        self.assertTrue (line_number == self.stepped_past_nil_line, "Step in over dispatch to nil stepped over.")
 
 if __name__ == '__main__':
     import atexit

Modified: lldb/trunk/test/lang/objc/objc-stepping/stepping-tests.m
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/objc/objc-stepping/stepping-tests.m?rev=156529&r1=156528&r2=156529&view=diff
==============================================================================
--- lldb/trunk/test/lang/objc/objc-stepping/stepping-tests.m (original)
+++ lldb/trunk/test/lang/objc/objc-stepping/stepping-tests.m Wed May  9 20:35:39 2012
@@ -127,7 +127,12 @@
   ret_val = [mySource returnsStruct];   // Set fourth breakpoint here.
   [mySource setProperty: 5];            // Set fifth breakpoint here.
 
-  [pool release];
+  // We also had a bug where stepping into a method dispatch to nil turned
+  // into continue.  So make sure that works here:
+
+  mySource = nil;
+  [mySource randomMethod];             // Set nil step breakpoint here.
+  [pool release];                      // Step over nil should stop here.
   return 0;
 
 }





More information about the lldb-commits mailing list