blob: fabf63b1e9d647200779d2b450c46d6e13a79654 [file] [log] [blame]
//===-- ThreadPlanStepInstruction.cpp ---------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Target/ThreadPlanStepInstruction.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// ThreadPlanStepInstruction: Step over the current instruction
//----------------------------------------------------------------------
ThreadPlanStepInstruction::ThreadPlanStepInstruction
(
Thread &thread,
bool step_over,
bool stop_other_threads,
Vote stop_vote,
Vote run_vote
) :
ThreadPlan (ThreadPlan::eKindStepInstruction, "Step over single instruction", thread, stop_vote, run_vote),
m_instruction_addr (0),
m_stop_other_threads (stop_other_threads),
m_step_over (step_over)
{
m_takes_iteration_count = true;
SetUpState();
}
ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
{
}
void
ThreadPlanStepInstruction::SetUpState()
{
m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0));
m_stack_id = start_frame_sp->GetStackID();
m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;
StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
if (parent_frame_sp)
m_parent_frame_id = parent_frame_sp->GetStackID();
}
void
ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
{
if (m_step_over)
s->Printf ("instruction step over");
else
s->Printf ("instruction step into");
}
else
{
s->Printf ("Stepping one instruction past ");
s->Address(m_instruction_addr, sizeof (addr_t));
if (!m_start_has_symbol)
s->Printf(" which has no symbol");
if (m_step_over)
s->Printf(" stepping over calls");
else
s->Printf(" stepping into calls");
}
}
bool
ThreadPlanStepInstruction::ValidatePlan (Stream *error)
{
// Since we read the instruction we're stepping over from the thread,
// this plan will always work.
return true;
}
bool
ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr)
{
StopInfoSP stop_info_sp = GetPrivateStopInfo ();
if (stop_info_sp)
{
StopReason reason = stop_info_sp->GetStopReason();
if (reason == eStopReasonTrace || reason == eStopReasonNone)
return true;
else
return false;
}
return false;
}
bool
ThreadPlanStepInstruction::IsPlanStale ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
if (cur_frame_id == m_stack_id)
{
if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
return true;
else
return false;
}
else if (cur_frame_id < m_stack_id)
{
// If the current frame is younger than the start frame and we are stepping over, then we need to continue,
// but if we are doing just one step, we're done.
if (m_step_over)
return false;
else
return true;
}
else
{
if (log)
{
log->Printf ("ThreadPlanStepInstruction::IsPlanStale - Current frame is older than start frame, plan is stale.");
}
return true;
}
}
bool
ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
if (m_step_over)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id)
{
if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
{
if (--m_iteration_count <= 0)
{
SetPlanComplete();
return true;
}
else
{
// We are still stepping, reset the start pc, and in case we've stepped out,
// reset the current stack id.
SetUpState();
return false;
}
}
else
return false;
}
else
{
// We've stepped in, step back out again:
StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
if (return_frame)
{
if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol)
{
if (log)
{
StreamString s;
s.PutCString ("Stepped in to: ");
addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
s.Address (stop_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
s.PutCString (" stepping out to: ");
addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
log->Printf("%s.", s.GetData());
}
// StepInstruction should probably have the tri-state RunMode, but for now it is safer to
// run others.
const bool stop_others = false;
m_thread.QueueThreadPlanForStepOutNoShouldStop(false,
NULL,
true,
stop_others,
eVoteNo,
eVoteNoOpinion,
0);
return false;
}
else
{
if (log)
{
log->PutCString("The stack id we are stepping in changed, but our parent frame did not when stepping from code with no symbols. "
"We are probably just confused about where we are, stopping.");
}
SetPlanComplete();
return true;
}
}
else
{
if (log)
log->Printf("Could not find previous frame, stopping.");
SetPlanComplete();
return true;
}
}
}
else
{
if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
{
if (--m_iteration_count <= 0)
{
SetPlanComplete();
return true;
}
else
{
// We are still stepping, reset the start pc, and in case we've stepped in or out,
// reset the current stack id.
SetUpState();
return false;
}
}
else
return false;
}
}
bool
ThreadPlanStepInstruction::StopOthers ()
{
return m_stop_other_threads;
}
StateType
ThreadPlanStepInstruction::GetPlanRunState ()
{
return eStateStepping;
}
bool
ThreadPlanStepInstruction::WillStop ()
{
return true;
}
bool
ThreadPlanStepInstruction::MischiefManaged ()
{
if (IsPlanComplete())
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
log->Printf("Completed single instruction step plan.");
ThreadPlan::MischiefManaged ();
return true;
}
else
{
return false;
}
}