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/API/SBThread.cpp b/source/API/SBThread.cpp
index 67ca2ff..2760e65 100644
--- a/source/API/SBThread.cpp
+++ b/source/API/SBThread.cpp
@@ -492,8 +492,53 @@
         bool abort_other_plans = true;
         bool stop_other_threads = true;
 
-        m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, stop_other_threads, eVoteYes, eVoteNoOpinion);
+        m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans, 
+                                                NULL, 
+                                                false, 
+                                                stop_other_threads, 
+                                                eVoteYes, 
+                                                eVoteNoOpinion,
+                                                0);
+        
+        Process &process = m_opaque_sp->GetProcess();
+        process.GetThreadList().SetSelectedThreadByID (m_opaque_sp->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);
+        }
+    }
+}
 
+void
+SBThread::StepOutOfFrame (lldb::SBFrame &sb_frame)
+{
+    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+    if (log)
+    {
+        SBStream frame_desc_strm;
+        sb_frame.GetDescription (frame_desc_strm);
+        log->Printf ("SBThread(%p)::StepOutOfFrame (frame = SBFrame(%p): %s)", m_opaque_sp.get(), sb_frame.get(), frame_desc_strm.GetData());
+    }
+
+    if (m_opaque_sp)
+    {
+        Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
+        bool abort_other_plans = true;
+        bool stop_other_threads = true;
+
+        m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans, 
+                                                NULL, 
+                                                false, 
+                                                stop_other_threads, 
+                                                eVoteYes, 
+                                                eVoteNoOpinion,
+                                                sb_frame->GetFrameIndex());
+        
         Process &process = m_opaque_sp->GetProcess();
         process.GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
         Error error (process.Resume());
@@ -559,9 +604,141 @@
                 process.WaitForProcessToStop (NULL);
         }
     }
-
 }
 
+SBError
+SBThread::StepOverUntil (lldb::SBFrame &sb_frame, 
+                         lldb::SBFileSpec &sb_file_spec, 
+                         uint32_t line)
+{
+    SBError sb_error;
+    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+    char path[PATH_MAX];
+
+    if (log)
+    {
+        SBStream frame_desc_strm;
+        sb_frame.GetDescription (frame_desc_strm);
+        sb_file_spec->GetPath (path, sizeof(path));
+        log->Printf ("SBThread(%p)::StepOverUntil (frame = SBFrame(%p): %s, file+line = %s:%u)", 
+                     m_opaque_sp.get(), 
+                     sb_frame.get(), 
+                     frame_desc_strm.GetData(),
+                     path, line);
+    }
+    
+    if (m_opaque_sp)
+    {
+        Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
+
+        if (line == 0)
+        {
+            sb_error.SetErrorString("invalid line argument");
+            return sb_error;
+        }
+        
+        StackFrameSP frame_sp;
+        if (sb_frame.IsValid())
+            frame_sp = sb_frame.get_sp();
+        else
+        {
+            frame_sp = m_opaque_sp->GetSelectedFrame ();
+            if (!frame_sp)
+                frame_sp = m_opaque_sp->GetStackFrameAtIndex (0);
+        }
+    
+        SymbolContext frame_sc;
+        if (!frame_sp)        
+        {
+            sb_error.SetErrorString("no valid frames in thread to step");
+            return sb_error;
+        }
+
+        // If we have a frame, get its line
+        frame_sc = frame_sp->GetSymbolContext (eSymbolContextCompUnit  |
+                                               eSymbolContextFunction  | 
+                                               eSymbolContextLineEntry | 
+                                               eSymbolContextSymbol    );
+                                               
+        if (frame_sc.comp_unit == NULL)
+        {
+            sb_error.SetErrorStringWithFormat("frame %u doesn't have debug information", frame_sp->GetFrameIndex());
+            return sb_error;
+        }
+        
+        FileSpec step_file_spec;
+        if (sb_file_spec.IsValid())
+        {
+            // The file spec passed in was valid, so use it
+            step_file_spec = sb_file_spec.ref();
+        }
+        else
+        {
+            if (frame_sc.line_entry.IsValid())
+                step_file_spec = frame_sc.line_entry.file;
+            else
+            {
+                sb_error.SetErrorString("invalid file argument or no file for frame");
+                return sb_error;
+            }
+        }
+    
+        std::vector<addr_t> step_over_until_addrs;
+        const bool abort_other_plans = true;
+        const bool stop_other_threads = true;
+        const bool check_inlines = true;
+        const bool exact = false;
+
+        SymbolContextList sc_list;
+        const uint32_t num_matches = frame_sc.comp_unit->ResolveSymbolContext (step_file_spec, line, check_inlines, exact, eSymbolContextLineEntry, sc_list);
+        if (num_matches > 0)
+        {
+            SymbolContext sc;
+            for (uint32_t i=0; i<num_matches; ++i)
+            {
+                if (sc_list.GetContextAtIndex(i, sc))
+                {
+                    addr_t step_addr = sc.line_entry.range.GetBaseAddress().GetLoadAddress(&m_opaque_sp->GetProcess().GetTarget());
+                    if (step_addr != LLDB_INVALID_ADDRESS)
+                    {
+                        step_over_until_addrs.push_back(step_addr);
+                    }
+                }
+            }
+        }
+
+        if (step_over_until_addrs.empty())
+        {
+            step_file_spec.GetPath (path, sizeof(path));
+            sb_error.SetErrorStringWithFormat("No line entries for %s:u", path, line);
+        }
+        else
+        {
+            m_opaque_sp->QueueThreadPlanForStepUntil (abort_other_plans, 
+                                                      &step_over_until_addrs[0],
+                                                      step_over_until_addrs.size(),
+                                                      stop_other_threads,
+                                                      frame_sp->GetFrameIndex());      
+
+            m_opaque_sp->GetProcess().GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
+            sb_error.ref() = m_opaque_sp->GetProcess().Resume();
+            if (sb_error->Success())
+            {
+                // If we are doing synchronous mode, then wait for the
+                // process to stop yet again!
+                if (m_opaque_sp->GetProcess().GetTarget().GetDebugger().GetAsyncExecution () == false)
+                    m_opaque_sp->GetProcess().WaitForProcessToStop (NULL);
+            }
+        }
+    }
+    else
+    {
+        sb_error.SetErrorString("this SBThread object is invalid");
+    }
+    return sb_error;
+}
+
+
 bool
 SBThread::Suspend()
 {
@@ -606,10 +783,10 @@
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     if (log)
     {
-        SBStream sstr;
-        process.GetDescription (sstr);
+        SBStream frame_desc_strm;
+        process.GetDescription (frame_desc_strm);
         log->Printf ("SBThread(%p)::GetProcess () => SBProcess(%p): %s", m_opaque_sp.get(),
-                     process.get(), sstr.GetData());
+                     process.get(), frame_desc_strm.GetData());
     }
 
     return process;
@@ -647,10 +824,10 @@
 
     if (log)
     {
-        SBStream sstr;
-        sb_frame.GetDescription (sstr);
+        SBStream frame_desc_strm;
+        sb_frame.GetDescription (frame_desc_strm);
         log->Printf ("SBThread(%p)::GetFrameAtIndex (idx=%d) => SBFrame(%p): %s", 
-                     m_opaque_sp.get(), idx, sb_frame.get(), sstr.GetData());
+                     m_opaque_sp.get(), idx, sb_frame.get(), frame_desc_strm.GetData());
     }
 
     return sb_frame;
@@ -670,10 +847,10 @@
 
     if (log)
     {
-        SBStream sstr;
-        sb_frame.GetDescription (sstr);
+        SBStream frame_desc_strm;
+        sb_frame.GetDescription (frame_desc_strm);
         log->Printf ("SBThread(%p)::GetSelectedFrame () => SBFrame(%p): %s", 
-                     m_opaque_sp.get(), sb_frame.get(), sstr.GetData());
+                     m_opaque_sp.get(), sb_frame.get(), frame_desc_strm.GetData());
     }
 
     return sb_frame;
@@ -698,10 +875,10 @@
 
     if (log)
     {
-        SBStream sstr;
-        sb_frame.GetDescription (sstr);
+        SBStream frame_desc_strm;
+        sb_frame.GetDescription (frame_desc_strm);
         log->Printf ("SBThread(%p)::SetSelectedFrame (idx=%u) => SBFrame(%p): %s", 
-                     m_opaque_sp.get(), idx, sb_frame.get(), sstr.GetData());
+                     m_opaque_sp.get(), idx, sb_frame.get(), frame_desc_strm.GetData());
     }
     return sb_frame;
 }