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:
Jim Ingham 2012-03-09 04:10:47 +00:00
parent ef42902816
commit 564d8bc255
16 changed files with 334 additions and 178 deletions

View File

@ -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.

View File

@ -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();

View File

@ -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.

View File

@ -43,9 +43,6 @@ public:
void SetAvoidRegexp(const char *name);
virtual bool
PlanExplainsStop ();
static ThreadPlan *
DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton);

View File

@ -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

View File

@ -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);
};

View File

@ -90,6 +90,8 @@ protected:
Stream *
GetLogStream ();
virtual void Log();
private:

View File

@ -99,6 +99,7 @@ class InlineFunctionInfo;
class InputReader;
class InstanceSettings;
class Instruction;
class InstructionList;
class LanguageRuntime;
class LineTable;
class Listener;

View File

@ -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
{

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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()
{

View File

@ -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)

View File

@ -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

View File

@ -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