Added support for stepping out of a frame. If you have 10 stack frames, and you 
select frame #3, you can then do a step out and be able to go directly to the
frame above frame #3! 

Added StepOverUntil and StepOutOfFrame to the SBThread API to allow more powerful
stepping.



git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@123970 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index 48a11a2..2c544a2 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -661,7 +661,12 @@
 }
 
 ThreadPlan *
-Thread::QueueThreadPlanForStepSingleInstruction (bool step_over, bool abort_other_plans, bool stop_other_threads)
+Thread::QueueThreadPlanForStepSingleInstruction
+(
+    bool step_over, 
+    bool abort_other_plans, 
+    bool stop_other_threads
+)
 {
     ThreadPlanSP thread_plan_sp (new ThreadPlanStepInstruction (*this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion));
     QueueThreadPlan (thread_plan_sp, abort_other_plans);
@@ -706,10 +711,24 @@
 }
 
 ThreadPlan *
-Thread::QueueThreadPlanForStepOut (bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
-        bool stop_other_threads, Vote stop_vote, Vote run_vote)
+Thread::QueueThreadPlanForStepOut 
+(
+    bool abort_other_plans, 
+    SymbolContext *addr_context, 
+    bool first_insn,
+    bool stop_other_threads, 
+    Vote stop_vote, 
+    Vote run_vote,
+    uint32_t frame_idx
+)
 {
-    ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote));
+    ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this, 
+                                                        addr_context, 
+                                                        first_insn, 
+                                                        stop_other_threads, 
+                                                        stop_vote, 
+                                                        run_vote, 
+                                                        frame_idx));
     QueueThreadPlan (thread_plan_sp, abort_other_plans);
     return thread_plan_sp.get();
 }
@@ -761,11 +780,12 @@
 
 ThreadPlan *
 Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
-                                       lldb::addr_t *address_list,
-                                       size_t num_addresses,
-                                       bool stop_other_threads)
+                                     lldb::addr_t *address_list,
+                                     size_t num_addresses,
+                                     bool stop_other_threads,
+                                     uint32_t frame_idx)
 {
-    ThreadPlanSP thread_plan_sp (new ThreadPlanStepUntil (*this, address_list, num_addresses, stop_other_threads));
+    ThreadPlanSP thread_plan_sp (new ThreadPlanStepUntil (*this, address_list, num_addresses, stop_other_threads, frame_idx));
     QueueThreadPlan (thread_plan_sp, abort_other_plans);
     return thread_plan_sp.get();
 
diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp
index 9ee8b56..2930d3d 100644
--- a/source/Target/ThreadPlanStepInRange.cpp
+++ b/source/Target/ThreadPlanStepInRange.cpp
@@ -270,9 +270,13 @@
     if (should_step_out)
     {
         // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
-        return current_plan->GetThread().QueueThreadPlanForStepOut (false, NULL, true, 
+        return current_plan->GetThread().QueueThreadPlanForStepOut (false, 
+                                                                    NULL, 
+                                                                    true, 
                                                                     current_plan->StopOthers(), 
-                                                                    eVoteNo, eVoteNoOpinion);
+                                                                    eVoteNo, 
+                                                                    eVoteNoOpinion,
+                                                                    0); // Frame index
     }
 
     return NULL;
diff --git a/source/Target/ThreadPlanStepInstruction.cpp b/source/Target/ThreadPlanStepInstruction.cpp
index a3dc1a8..5d744c4 100644
--- a/source/Target/ThreadPlanStepInstruction.cpp
+++ b/source/Target/ThreadPlanStepInstruction.cpp
@@ -129,7 +129,7 @@
                     s.Address (return_addr, m_thread.GetProcess().GetAddressByteSize());
                     log->Printf("%s.", s.GetData());
                 }
-                m_thread.QueueThreadPlanForStepOut(false, NULL, true, m_stop_other_threads, eVoteNo, eVoteNoOpinion);
+                m_thread.QueueThreadPlanForStepOut(false, NULL, true, m_stop_other_threads, eVoteNo, eVoteNoOpinion, 0);
                 return false;
             }
             else
diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp
index 690a43c..5b343bb 100644
--- a/source/Target/ThreadPlanStepOut.cpp
+++ b/source/Target/ThreadPlanStepOut.cpp
@@ -35,7 +35,8 @@
     bool first_insn,
     bool stop_others,
     Vote stop_vote,
-    Vote run_vote
+    Vote run_vote,
+    uint32_t frame_idx
 ) :
     ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
     m_step_from_context (context),
@@ -50,24 +51,20 @@
     // Find the return address and set a breakpoint there:
     // FIXME - can we do this more securely if we know first_insn?
 
-    StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
-    if (return_frame)
+    StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
+    if (return_frame_sp)
     {
         // TODO: check for inlined frames and do the right thing...
-        m_return_addr = return_frame->GetRegisterContext()->GetPC();
+        m_return_addr = return_frame_sp->GetRegisterContext()->GetPC();
         Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get();
         if (return_bp != NULL)
         {
             return_bp->SetThreadID(m_thread.GetID());
             m_return_bp_id = return_bp->GetID();
         }
-        else
-        {
-            m_return_bp_id = LLDB_INVALID_BREAK_ID;
-        }
     }
 
-    m_stack_depth = m_thread.GetStackFrameCount();
+    m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
 }
 
 ThreadPlanStepOut::~ThreadPlanStepOut ()
@@ -116,6 +113,10 @@
             BreakpointSiteSP site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()));
             if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id))
             {
+                const uint32_t num_frames = m_thread.GetStackFrameCount();
+                if (m_stack_depth > num_frames);
+                    SetPlanComplete();
+
                 // If there was only one owner, then we're done.  But if we also hit some
                 // user breakpoint on our way out, we should mark ourselves as done, but
                 // also not claim to explain the stop, since it is more important to report
@@ -124,7 +125,6 @@
                 if (site_sp->GetNumberOfOwners() == 1)
                     return true;
                 
-                SetPlanComplete();
             }
             return false;
         }
@@ -143,9 +143,7 @@
 bool
 ThreadPlanStepOut::ShouldStop (Event *event_ptr)
 {
-    if (IsPlanComplete()
-        || m_thread.GetRegisterContext()->GetPC() == m_return_addr
-        || m_stack_depth > m_thread.GetStackFrameCount())
+    if (IsPlanComplete() || m_stack_depth > m_thread.GetStackFrameCount())
     {
         SetPlanComplete();
         return true;
diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp
index 5b37290..2d6f030 100644
--- a/source/Target/ThreadPlanStepOverRange.cpp
+++ b/source/Target/ThreadPlanStepOverRange.cpp
@@ -104,7 +104,13 @@
     }
     else if (FrameIsYounger())
     {
-        new_plan = m_thread.QueueThreadPlanForStepOut (false, NULL, true, stop_others, lldb::eVoteNo, lldb::eVoteNoOpinion);
+        new_plan = m_thread.QueueThreadPlanForStepOut (false, 
+                                                       NULL, 
+                                                       true, 
+                                                       stop_others, 
+                                                       lldb::eVoteNo, 
+                                                       lldb::eVoteNoOpinion,
+                                                       0);
     }
     else if (!InSymbol())
     {
diff --git a/source/Target/ThreadPlanStepUntil.cpp b/source/Target/ThreadPlanStepUntil.cpp
index 8fca234..5ad0940 100644
--- a/source/Target/ThreadPlanStepUntil.cpp
+++ b/source/Target/ThreadPlanStepUntil.cpp
@@ -37,7 +37,8 @@
     Thread &thread,
     lldb::addr_t *address_list,
     size_t num_addresses,
-    bool stop_others
+    bool stop_others,
+    uint32_t frame_idx
 ) :
     ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion),
     m_stack_depth (0),
@@ -56,40 +57,43 @@
     // Stash away our "until" addresses:
     Target &target = m_thread.GetProcess().GetTarget();
 
-    m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
-    lldb::user_id_t thread_id = m_thread.GetID();
-
-    // Find the return address and set a breakpoint there:
-    // FIXME - can we do this more securely if we know first_insn?
-
-    StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
-    // TODO: add inline functionality
-    m_return_addr = return_frame->GetRegisterContext()->GetPC();
-    Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
-    if (return_bp != NULL)
+    StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
+    if (frame_sp)
     {
-        return_bp->SetThreadID(thread_id);
-        m_return_bp_id = return_bp->GetID();
-    }
-    else
-    {
-        m_return_bp_id = LLDB_INVALID_BREAK_ID;
-    }
+        m_step_from_insn = frame_sp->GetStackID().GetPC();
+        lldb::user_id_t thread_id = m_thread.GetID();
 
-    m_stack_depth = m_thread.GetStackFrameCount();
+        // Find the return address and set a breakpoint there:
+        // FIXME - can we do this more securely if we know first_insn?
 
-    // Now set breakpoints on all our return addresses:
-    for (int i = 0; i < num_addresses; i++)
-    {
-        Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
-        if (until_bp != NULL)
+        StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
+        if (return_frame_sp)
         {
-            until_bp->SetThreadID(thread_id);
-            m_until_points[address_list[i]] = until_bp->GetID();
+            // TODO: add inline functionality
+            m_return_addr = return_frame_sp->GetStackID().GetPC();
+            Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
+            if (return_bp != NULL)
+            {
+                return_bp->SetThreadID(thread_id);
+                m_return_bp_id = return_bp->GetID();
+            }
         }
-        else
+
+        m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
+
+        // Now set breakpoints on all our return addresses:
+        for (int i = 0; i < num_addresses; i++)
         {
-            m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
+            Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
+            if (until_bp != NULL)
+            {
+                until_bp->SetThreadID(thread_id);
+                m_until_points[address_list[i]] = until_bp->GetID();
+            }
+            else
+            {
+                m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
+            }
         }
     }
 }