ThreadPlanStepOut.cpp [plain text]
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
ThreadPlanStepOut::ThreadPlanStepOut
(
Thread &thread,
SymbolContext *context,
bool first_insn,
bool stop_others,
Vote stop_vote,
Vote run_vote,
uint32_t frame_idx
) :
ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
m_step_from_context (context),
m_step_from_insn (LLDB_INVALID_ADDRESS),
m_return_bp_id (LLDB_INVALID_BREAK_ID),
m_return_addr (LLDB_INVALID_ADDRESS),
m_first_insn (first_insn),
m_stop_others (stop_others)
{
m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
if (return_frame_sp)
{
m_return_addr = return_frame_sp->GetRegisterContext()->GetPC();
Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get();
if (return_bp != NULL)
{
return_bp->SetThreadID(m_thread.GetID());
m_return_bp_id = return_bp->GetID();
}
}
m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
}
ThreadPlanStepOut::~ThreadPlanStepOut ()
{
if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id);
}
void
ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
s->Printf ("step out");
else
{
s->Printf ("Stepping out from address 0x%llx to return address 0x%llx using breakpoint site %d",
(uint64_t)m_step_from_insn,
(uint64_t)m_return_addr,
m_return_bp_id);
}
}
bool
ThreadPlanStepOut::ValidatePlan (Stream *error)
{
if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
return false;
else
return true;
}
bool
ThreadPlanStepOut::PlanExplainsStop ()
{
StopInfoSP stop_info_sp = GetPrivateStopReason();
if (stop_info_sp)
{
StopReason reason = stop_info_sp->GetStopReason();
switch (reason)
{
case eStopReasonBreakpoint:
{
BreakpointSiteSP site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()));
if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id))
{
const uint32_t num_frames = m_thread.GetStackFrameCount();
if (m_stack_depth > num_frames)
SetPlanComplete();
if (site_sp->GetNumberOfOwners() == 1)
return true;
}
return false;
}
case eStopReasonWatchpoint:
case eStopReasonSignal:
case eStopReasonException:
return false;
default:
return true;
}
}
return true;
}
bool
ThreadPlanStepOut::ShouldStop (Event *event_ptr)
{
if (IsPlanComplete() || m_stack_depth > m_thread.GetStackFrameCount())
{
SetPlanComplete();
return true;
}
else
return false;
}
bool
ThreadPlanStepOut::StopOthers ()
{
return m_stop_others;
}
StateType
ThreadPlanStepOut::GetPlanRunState ()
{
return eStateRunning;
}
bool
ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan)
{
ThreadPlan::WillResume (resume_state, current_plan);
if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
return false;
if (current_plan)
{
Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
if (return_bp != NULL)
return_bp->SetEnabled (true);
}
return true;
}
bool
ThreadPlanStepOut::WillStop ()
{
Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
if (return_bp != NULL)
return_bp->SetEnabled (false);
return true;
}
bool
ThreadPlanStepOut::MischiefManaged ()
{
if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
{
return true;
}
else if (IsPlanComplete())
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
log->Printf("Completed step out plan.");
m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_return_bp_id);
m_return_bp_id = LLDB_INVALID_BREAK_ID;
ThreadPlan::MischiefManaged ();
return true;
}
else
{
return false;
}
}