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