aboutsummaryrefslogtreecommitdiff
path: root/source/Target/ThreadPlanStepInstruction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Target/ThreadPlanStepInstruction.cpp')
-rw-r--r--source/Target/ThreadPlanStepInstruction.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/source/Target/ThreadPlanStepInstruction.cpp b/source/Target/ThreadPlanStepInstruction.cpp
new file mode 100644
index 000000000000..f644ee88f701
--- /dev/null
+++ b/source/Target/ThreadPlanStepInstruction.cpp
@@ -0,0 +1,227 @@
+//===-- 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_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
+ StackFrameSP m_start_frame_sp(m_thread.GetStackFrameAtIndex(0));
+ m_stack_id = m_start_frame_sp->GetStackID();
+
+ m_start_has_symbol = m_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();
+}
+
+ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
+{
+}
+
+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::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)
+ {
+ SetPlanComplete();
+ return true;
+ }
+ 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.QueueThreadPlanForStepOut(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)
+ {
+ SetPlanComplete();
+ return true;
+ }
+ 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;
+ }
+}
+