First stage of implementing step by "run to next branch".  Doesn't work yet, is turned off.
<rdar://problem/10975912>


git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@152376 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/ThreadPlanStepRange.cpp b/source/Target/ThreadPlanStepRange.cpp
index b504e1f..59f760c 100644
--- a/source/Target/ThreadPlanStepRange.cpp
+++ b/source/Target/ThreadPlanStepRange.cpp
@@ -15,14 +15,18 @@
 // Project includes
 
 #include "lldb/lldb-private-log.h"
+#include "lldb/Core/Disassembler.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/Stream.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -53,6 +57,14 @@
 
 ThreadPlanStepRange::~ThreadPlanStepRange ()
 {
+    ClearNextBranchBreakpoint();
+}
+
+void
+ThreadPlanStepRange::DidPush ()
+{
+    // See if we can find a "next range" breakpoint:
+    SetNextBranchBreakpoint();
 }
 
 bool
@@ -79,6 +91,7 @@
     // condense the ranges if they overlap, though I don't think it is likely
     // to be very important.
     m_address_ranges.push_back (new_range);
+    m_instruction_ranges.push_back (DisassemblerSP());
 }
 
 void
@@ -230,6 +243,145 @@
         return false;
 }
 
+InstructionList *
+ThreadPlanStepRange::GetInstructionsForAddress(lldb::addr_t addr, size_t &range_index, size_t &insn_offset)
+{
+    size_t num_ranges = m_address_ranges.size();
+    for (size_t i = 0; i < num_ranges; i++)
+    {
+        if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget()))
+        {
+            // Some joker added a zero size range to the stepping range...
+            if (m_address_ranges[i].GetByteSize() == 0)
+                return NULL;
+
+            if (!m_instruction_ranges[i])
+            {
+                //Disassemble the address range given:
+                ExecutionContext exe_ctx (m_thread.GetProcess());
+                m_instruction_ranges[i] = Disassembler::DisassembleRange(GetTarget().GetArchitecture(),
+                                                                         NULL,
+                                                                         exe_ctx,
+                                                                         m_address_ranges[i]);
+                
+            }
+            if (!m_instruction_ranges[i])
+                return NULL;
+            else
+            {
+                // Find where we are in the instruction list as well.  If we aren't at an instruction,
+                // return NULL.  In this case, we're probably lost, and shouldn't try to do anything fancy.
+                
+                insn_offset = m_instruction_ranges[i]->GetInstructionList().GetIndexOfInstructionAtLoadAddress(addr, GetTarget());
+                if (insn_offset == UINT32_MAX)
+                    return NULL;
+                else
+                {
+                    range_index = i;
+                    return &m_instruction_ranges[i]->GetInstructionList();
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+void
+ThreadPlanStepRange::ClearNextBranchBreakpoint()
+{
+    if (m_next_branch_bp_sp)
+    {
+        GetTarget().RemoveBreakpointByID (m_next_branch_bp_sp->GetID());
+        m_next_branch_bp_sp.reset();
+    }
+}
+
+bool
+ThreadPlanStepRange::SetNextBranchBreakpoint ()
+{
+    // Stepping through ranges using breakpoints doesn't work yet, but with this off we fall back to instruction
+    // single stepping.
+    return false;
+    // Always clear the next branch breakpoint, we don't want to leave one of these stranded.
+    ClearNextBranchBreakpoint();
+    lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC();
+    // Find the current address in our address ranges, and fetch the disassembly if we haven't already:
+    size_t pc_index;
+    size_t range_index;
+    InstructionList *instructions = GetInstructionsForAddress (cur_addr, range_index, pc_index);
+    if (instructions == NULL)
+        return false;
+    else
+    {
+        uint32_t branch_index;
+        branch_index = instructions->GetIndexOfNextBranchInstruction (pc_index);
+        
+        Address run_to_address;
+        
+        // If we didn't find a branch, run to the end of the range.
+        if (branch_index == UINT32_MAX)
+        {
+            branch_index = instructions->GetSize() - 2;
+        }
+        if (branch_index - pc_index > 1)
+        {
+            const bool is_internal = true;
+            run_to_address = instructions->GetInstructionAtIndex(branch_index)->GetAddress();
+            m_next_branch_bp_sp = GetTarget().CreateBreakpoint(run_to_address, is_internal);
+            m_next_branch_bp_sp->SetThreadID(m_thread.GetID());
+            return true;
+        }
+    }
+    return false;
+}
+
+bool
+ThreadPlanStepRange::NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info_sp)
+{
+    if (!m_next_branch_bp_sp)
+        return false;
+    
+    break_id_t bp_site_id = stop_info_sp->GetValue();
+    BreakpointSiteSP bp_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id);
+    if (!bp_site_sp->IsBreakpointAtThisSite (m_next_branch_bp_sp->GetID()))
+        return false;
+    else
+        return bp_site_sp->GetNumberOfOwners() == 1;
+}
+
+bool
+ThreadPlanStepRange::PlanExplainsStop ()
+{
+    // We always explain a stop.  Either we've just done a single step, in which
+    // 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.
+    
+    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+    StopInfoSP stop_info_sp = GetPrivateStopReason();
+    if (stop_info_sp)
+    {
+        StopReason reason = stop_info_sp->GetStopReason();
+
+        switch (reason)
+        {
+        case eStopReasonBreakpoint:
+            if (NextRangeBreakpointExplainsStop(stop_info_sp))
+                return true;
+        case eStopReasonWatchpoint:
+        case eStopReasonSignal:
+        case eStopReasonException:
+            if (log)
+                log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
+            SetPlanComplete();
+            break;
+        default:
+            break;
+        }
+    }
+    return true;
+}
+
 bool
 ThreadPlanStepRange::WillStop ()
 {
@@ -239,7 +391,10 @@
 StateType
 ThreadPlanStepRange::GetPlanRunState ()
 {
-    return eStateStepping;
+    if (m_next_branch_bp_sp)
+        return eStateRunning;
+    else
+        return eStateStepping;
 }
 
 bool