forked from OSchip/llvm-project
First stage of implementing step by "run to next branch". Doesn't work yet, is turned off.
<rdar://problem/10975912> llvm-svn: 152376
This commit is contained in:
parent
ef42902816
commit
564d8bc255
|
@ -112,6 +112,23 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
lldb::break_id_t
|
||||
FindIDByAddress (lldb::addr_t addr);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Returns whether the breakpoint site \a bp_site_id has \a bp_id
|
||||
// as one of its owners.
|
||||
///
|
||||
/// @param[in] bp_site_id
|
||||
/// The breakpoint site id to query.
|
||||
///
|
||||
/// @param[in] bp_id
|
||||
/// The breakpoint id to look for in \a bp_site_id.
|
||||
///
|
||||
/// @result
|
||||
/// True if \a bp_site_id exists in the site list AND \a bp_id is one of the
|
||||
/// owners of that site.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
BreakpointSiteContainsBreakpoint (lldb::break_id_t bp_site_id, lldb::break_id_t bp_id);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Returns a shared pointer to the breakpoint site with index \a i.
|
||||
|
|
|
@ -163,6 +163,12 @@ public:
|
|||
|
||||
lldb::InstructionSP
|
||||
GetInstructionAtIndex (uint32_t idx) const;
|
||||
|
||||
uint32_t
|
||||
GetIndexOfNextBranchInstruction(uint32_t start) const;
|
||||
|
||||
uint32_t
|
||||
GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target);
|
||||
|
||||
void
|
||||
Clear();
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Core/UserID.h"
|
||||
#include "lldb/Host/Mutex.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
#include "lldb/Target/ThreadPlanTracer.h"
|
||||
#include "lldb/Target/StopInfo.h"
|
||||
|
@ -223,8 +225,11 @@ public:
|
|||
/// A const char * pointer to the thread plan's name.
|
||||
//------------------------------------------------------------------
|
||||
const char *
|
||||
GetName () const;
|
||||
|
||||
GetName () const
|
||||
{
|
||||
return m_name.c_str();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Returns the Thread that is using this thread plan.
|
||||
///
|
||||
|
@ -232,10 +237,28 @@ public:
|
|||
/// A pointer to the thread plan's owning thread.
|
||||
//------------------------------------------------------------------
|
||||
Thread &
|
||||
GetThread();
|
||||
GetThread()
|
||||
{
|
||||
return m_thread;
|
||||
}
|
||||
|
||||
const Thread &
|
||||
GetThread() const;
|
||||
GetThread() const
|
||||
{
|
||||
return m_thread;
|
||||
}
|
||||
|
||||
Target &
|
||||
GetTarget()
|
||||
{
|
||||
return m_thread.GetProcess()->GetTarget();
|
||||
}
|
||||
|
||||
const Target &
|
||||
GetTarget() const
|
||||
{
|
||||
return m_thread.GetProcess()->GetTarget();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Print a description of this thread to the stream \a s.
|
||||
|
@ -332,10 +355,16 @@ public:
|
|||
MischiefManaged ();
|
||||
|
||||
bool
|
||||
GetPrivate ();
|
||||
GetPrivate ()
|
||||
{
|
||||
return m_plan_private;
|
||||
}
|
||||
|
||||
void
|
||||
SetPrivate (bool input);
|
||||
SetPrivate (bool input)
|
||||
{
|
||||
m_plan_private = input;
|
||||
}
|
||||
|
||||
virtual void
|
||||
DidPush();
|
||||
|
@ -345,7 +374,10 @@ public:
|
|||
|
||||
// This pushes \a plan onto the plan stack of the current plan's thread.
|
||||
void
|
||||
PushPlan (lldb::ThreadPlanSP &thread_plan_sp);
|
||||
PushPlan (lldb::ThreadPlanSP &thread_plan_sp)
|
||||
{
|
||||
m_thread.PushPlan (thread_plan_sp);
|
||||
}
|
||||
|
||||
ThreadPlanKind GetKind() const
|
||||
{
|
||||
|
@ -403,7 +435,10 @@ protected:
|
|||
// GetPreviousPlan protected, but only friend ThreadPlan to thread.
|
||||
|
||||
ThreadPlan *
|
||||
GetPreviousPlan ();
|
||||
GetPreviousPlan ()
|
||||
{
|
||||
return m_thread.GetPreviousPlan (this);
|
||||
}
|
||||
|
||||
// This forwards the private Thread::GetPrivateStopReason which is generally what
|
||||
// ThreadPlan's need to know.
|
||||
|
|
|
@ -43,9 +43,6 @@ public:
|
|||
|
||||
void SetAvoidRegexp(const char *name);
|
||||
|
||||
virtual bool
|
||||
PlanExplainsStop ();
|
||||
|
||||
static ThreadPlan *
|
||||
DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton);
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ public:
|
|||
|
||||
virtual ~ThreadPlanStepOverRange ();
|
||||
|
||||
virtual bool PlanExplainsStop ();
|
||||
virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
|
||||
virtual bool ShouldStop (Event *event_ptr);
|
||||
virtual bool
|
||||
|
|
|
@ -42,6 +42,9 @@ public:
|
|||
virtual lldb::StateType GetPlanRunState ();
|
||||
virtual bool WillStop ();
|
||||
virtual bool MischiefManaged ();
|
||||
virtual bool PlanExplainsStop ();
|
||||
virtual void DidPush ();
|
||||
|
||||
|
||||
void AddRange(const AddressRange &new_range);
|
||||
|
||||
|
@ -52,15 +55,35 @@ protected:
|
|||
bool InSymbol();
|
||||
void DumpRanges (Stream *s);
|
||||
|
||||
SymbolContext m_addr_context;
|
||||
Disassembler *
|
||||
GetDisassembler ();
|
||||
|
||||
InstructionList *
|
||||
GetInstructionsForAddress(lldb::addr_t addr, size_t &range_index, size_t &insn_offset);
|
||||
|
||||
// Pushes a plan to proceed through the next section of instructions in the range - usually just a RunToAddress
|
||||
// plan to run to the next branch. Returns true if it pushed such a plan. If there was no available 'quick run'
|
||||
// plan, then just single step.
|
||||
bool
|
||||
SetNextBranchBreakpoint ();
|
||||
|
||||
void
|
||||
ClearNextBranchBreakpoint();
|
||||
|
||||
bool
|
||||
NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info_sp);
|
||||
|
||||
SymbolContext m_addr_context;
|
||||
std::vector<AddressRange> m_address_ranges;
|
||||
lldb::RunMode m_stop_others;
|
||||
StackID m_stack_id; // Use the stack ID so we can tell step out from step in.
|
||||
bool m_no_more_plans; // Need this one so we can tell if we stepped into a call, but can't continue,
|
||||
// in which case we are done.
|
||||
bool m_first_run_event; // We want to broadcast only one running event, our first.
|
||||
lldb::RunMode m_stop_others;
|
||||
StackID m_stack_id; // Use the stack ID so we can tell step out from step in.
|
||||
bool m_no_more_plans; // Need this one so we can tell if we stepped into a call,
|
||||
// but can't continue, in which case we are done.
|
||||
bool m_first_run_event; // We want to broadcast only one running event, our first.
|
||||
lldb::BreakpointSP m_next_branch_bp_sp;
|
||||
|
||||
private:
|
||||
std::vector<lldb::DisassemblerSP> m_instruction_ranges;
|
||||
DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepRange);
|
||||
|
||||
};
|
||||
|
|
|
@ -90,6 +90,8 @@ protected:
|
|||
Stream *
|
||||
GetLogStream ();
|
||||
|
||||
|
||||
|
||||
virtual void Log();
|
||||
|
||||
private:
|
||||
|
|
|
@ -99,6 +99,7 @@ class InlineFunctionInfo;
|
|||
class InputReader;
|
||||
class InstanceSettings;
|
||||
class Instruction;
|
||||
class InstructionList;
|
||||
class LanguageRuntime;
|
||||
class LineTable;
|
||||
class Listener;
|
||||
|
|
|
@ -164,6 +164,16 @@ BreakpointSiteList::FindByAddress (lldb::addr_t addr)
|
|||
return found_sp;
|
||||
}
|
||||
|
||||
bool
|
||||
BreakpointSiteList::BreakpointSiteContainsBreakpoint (lldb::break_id_t bp_site_id, lldb::break_id_t bp_id)
|
||||
{
|
||||
collection::const_iterator pos = GetIDConstIterator(bp_site_id);
|
||||
if (pos != m_bp_site_list.end())
|
||||
pos->second->IsBreakpointAtThisSite (bp_id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
BreakpointSiteList::Dump (Stream *s) const
|
||||
{
|
||||
|
|
|
@ -902,6 +902,40 @@ InstructionList::Append (lldb::InstructionSP &inst_sp)
|
|||
m_instructions.push_back(inst_sp);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const
|
||||
{
|
||||
size_t num_instructions = m_instructions.size();
|
||||
|
||||
uint32_t next_branch = UINT32_MAX;
|
||||
for (size_t i = start; i < num_instructions; i++)
|
||||
{
|
||||
if (m_instructions[i]->DoesBranch())
|
||||
{
|
||||
next_branch = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return next_branch;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
InstructionList::GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target)
|
||||
{
|
||||
Address address;
|
||||
address.SetLoadAddress(load_addr, &target);
|
||||
uint32_t num_instructions = m_instructions.size();
|
||||
uint32_t index = UINT32_MAX;
|
||||
for (int i = 0; i < num_instructions; i++)
|
||||
{
|
||||
if (m_instructions[i]->GetAddress() == address)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
size_t
|
||||
Disassembler::ParseInstructions
|
||||
|
|
|
@ -364,27 +364,7 @@ ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP sto
|
|||
return false;
|
||||
|
||||
uint64_t break_site_id = stop_reason->GetValue();
|
||||
lldb::BreakpointSiteSP bp_site_sp = m_process->GetBreakpointSiteList().FindByID(break_site_id);
|
||||
return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint(break_site_id,
|
||||
m_cxx_exception_bp_sp->GetID());
|
||||
|
||||
if (!bp_site_sp)
|
||||
return false;
|
||||
|
||||
uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
|
||||
|
||||
break_id_t cxx_exception_bid;
|
||||
|
||||
if (!m_cxx_exception_bp_sp)
|
||||
return false;
|
||||
|
||||
cxx_exception_bid = m_cxx_exception_bp_sp->GetID();
|
||||
|
||||
for (uint32_t i = 0; i < num_owners; i++)
|
||||
{
|
||||
break_id_t bid = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().GetID();
|
||||
|
||||
if (bid == cxx_exception_bid)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -328,29 +328,8 @@ AppleObjCRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason)
|
|||
return false;
|
||||
|
||||
uint64_t break_site_id = stop_reason->GetValue();
|
||||
lldb::BreakpointSiteSP bp_site_sp = m_process->GetBreakpointSiteList().FindByID(break_site_id);
|
||||
|
||||
if (!bp_site_sp)
|
||||
return false;
|
||||
|
||||
uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
|
||||
|
||||
break_id_t objc_exception_bid;
|
||||
|
||||
if (!m_objc_exception_bp_sp)
|
||||
return false;
|
||||
|
||||
objc_exception_bid = m_objc_exception_bp_sp->GetID();
|
||||
|
||||
for (uint32_t i = 0; i < num_owners; i++)
|
||||
{
|
||||
break_id_t bid = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().GetID();
|
||||
|
||||
if (bid == objc_exception_bid)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint (break_site_id,
|
||||
m_objc_exception_bp_sp->GetID());
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -48,25 +48,6 @@ ThreadPlan::~ThreadPlan()
|
|||
{
|
||||
}
|
||||
|
||||
const char *
|
||||
ThreadPlan::GetName () const
|
||||
{
|
||||
return m_name.c_str();
|
||||
}
|
||||
|
||||
Thread &
|
||||
ThreadPlan::GetThread()
|
||||
{
|
||||
return m_thread;
|
||||
}
|
||||
|
||||
|
||||
const Thread &
|
||||
ThreadPlan::GetThread() const
|
||||
{
|
||||
return m_thread;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPlan::IsPlanComplete ()
|
||||
{
|
||||
|
@ -187,30 +168,6 @@ ThreadPlan::WillPop()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
ThreadPlan::PushPlan (ThreadPlanSP &thread_plan_sp)
|
||||
{
|
||||
m_thread.PushPlan (thread_plan_sp);
|
||||
}
|
||||
|
||||
ThreadPlan *
|
||||
ThreadPlan::GetPreviousPlan ()
|
||||
{
|
||||
return m_thread.GetPreviousPlan (this);
|
||||
}
|
||||
|
||||
void
|
||||
ThreadPlan::SetPrivate (bool input)
|
||||
{
|
||||
m_plan_private = input;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPlan::GetPrivate (void)
|
||||
{
|
||||
return m_plan_private;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPlan::OkayToDiscard()
|
||||
{
|
||||
|
|
|
@ -67,37 +67,6 @@ ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPlanStepInRange::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:
|
||||
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
|
||||
ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
|
||||
{
|
||||
|
@ -115,10 +84,6 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
|
|||
if (IsPlanComplete())
|
||||
return true;
|
||||
|
||||
// If we're still in the range, keep going.
|
||||
if (InRange())
|
||||
return false;
|
||||
|
||||
ThreadPlan* new_plan = NULL;
|
||||
|
||||
// Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
|
||||
|
@ -148,7 +113,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
|
|||
}
|
||||
|
||||
}
|
||||
else if (frame_order != eFrameCompareYounger && InSymbol())
|
||||
else if (frame_order == eFrameCompareEqual && InSymbol())
|
||||
{
|
||||
// If we are not in a place we should step through, we're done.
|
||||
// One tricky bit here is that some stubs don't push a frame, so we have to check
|
||||
|
@ -156,11 +121,22 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
|
|||
// However, if the frame is the same, and we are still in the symbol we started
|
||||
// in, the we don't need to do this. This first check isn't strictly necessary,
|
||||
// but it is more efficient.
|
||||
|
||||
// If we're still in the range, keep going, either by running to the next branch breakpoint, or by
|
||||
// stepping.
|
||||
if (InRange())
|
||||
{
|
||||
SetNextBranchBreakpoint();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetPlanComplete();
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
|
||||
ClearNextBranchBreakpoint();
|
||||
|
||||
// We may have set the plan up above in the FrameIsOlder section:
|
||||
|
||||
if (new_plan == NULL)
|
||||
|
|
|
@ -62,31 +62,6 @@ ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPlanStepOverRange::PlanExplainsStop ()
|
||||
{
|
||||
// We don't explain signals or breakpoints (breakpoints that handle stepping in or
|
||||
// out will be handled by a child plan.
|
||||
StopInfoSP stop_info_sp = GetPrivateStopReason();
|
||||
if (stop_info_sp)
|
||||
{
|
||||
StopReason reason = stop_info_sp->GetStopReason();
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case eStopReasonBreakpoint:
|
||||
case eStopReasonWatchpoint:
|
||||
case eStopReasonSignal:
|
||||
case eStopReasonException:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
|
||||
{
|
||||
|
@ -100,10 +75,6 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
|
|||
log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData());
|
||||
}
|
||||
|
||||
// If we're still in the range, keep going.
|
||||
if (InRange())
|
||||
return false;
|
||||
|
||||
// If we're out of the range but in the same frame or in our caller's frame
|
||||
// then we should stop.
|
||||
// When stepping out we only step if we are forcing running one thread.
|
||||
|
@ -158,15 +129,29 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (!InSymbol())
|
||||
else
|
||||
{
|
||||
// This one is a little tricky. Sometimes we may be in a stub or something similar,
|
||||
// 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);
|
||||
// If we're still in the range, keep going.
|
||||
if (InRange())
|
||||
{
|
||||
SetNextBranchBreakpoint();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!InSymbol())
|
||||
{
|
||||
// This one is a little tricky. Sometimes we may be in a stub or something similar,
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
|
||||
ClearNextBranchBreakpoint();
|
||||
|
||||
if (new_plan == NULL)
|
||||
m_no_more_plans = true;
|
||||
else
|
||||
|
|
|
@ -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 (ThreadPlanKind kind,
|
|||
|
||||
ThreadPlanStepRange::~ThreadPlanStepRange ()
|
||||
{
|
||||
ClearNextBranchBreakpoint();
|
||||
}
|
||||
|
||||
void
|
||||
ThreadPlanStepRange::DidPush ()
|
||||
{
|
||||
// See if we can find a "next range" breakpoint:
|
||||
SetNextBranchBreakpoint();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -79,6 +91,7 @@ ThreadPlanStepRange::AddRange(const AddressRange &new_range)
|
|||
// 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 @@ ThreadPlanStepRange::StopOthers ()
|
|||
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 @@ ThreadPlanStepRange::WillStop ()
|
|||
StateType
|
||||
ThreadPlanStepRange::GetPlanRunState ()
|
||||
{
|
||||
return eStateStepping;
|
||||
if (m_next_branch_bp_sp)
|
||||
return eStateRunning;
|
||||
else
|
||||
return eStateStepping;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
Loading…
Reference in New Issue