1//===-- ThreadPlanStepInstruction.cpp ---------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10
11#include "lldb/Target/ThreadPlanStepInstruction.h"
12
13// C Includes
14// C++ Includes
15// Other libraries and framework includes
16// Project includes
17#include "lldb/lldb-private-log.h"
18#include "lldb/Core/Log.h"
19#include "lldb/Core/Stream.h"
20#include "lldb/Target/Process.h"
21#include "lldb/Target/RegisterContext.h"
22#include "lldb/Target/RegisterContext.h"
23#include "lldb/Target/StopInfo.h"
24#include "lldb/Target/Target.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29//----------------------------------------------------------------------
30// ThreadPlanStepInstruction: Step over the current instruction
31//----------------------------------------------------------------------
32
33ThreadPlanStepInstruction::ThreadPlanStepInstruction
34(
35    Thread &thread,
36    bool step_over,
37    bool stop_other_threads,
38    Vote stop_vote,
39    Vote run_vote
40) :
41    ThreadPlan (ThreadPlan::eKindStepInstruction, "Step over single instruction", thread, stop_vote, run_vote),
42    m_instruction_addr (0),
43    m_stop_other_threads (stop_other_threads),
44    m_step_over (step_over)
45{
46    m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
47    StackFrameSP m_start_frame_sp(m_thread.GetStackFrameAtIndex(0));
48    m_stack_id = m_start_frame_sp->GetStackID();
49
50    m_start_has_symbol = m_start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;
51
52    StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
53    if (parent_frame_sp)
54        m_parent_frame_id = parent_frame_sp->GetStackID();
55}
56
57ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
58{
59}
60
61void
62ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
63{
64    if (level == lldb::eDescriptionLevelBrief)
65    {
66        if (m_step_over)
67            s->Printf ("instruction step over");
68        else
69            s->Printf ("instruction step into");
70    }
71    else
72    {
73        s->Printf ("Stepping one instruction past ");
74        s->Address(m_instruction_addr, sizeof (addr_t));
75        if (!m_start_has_symbol)
76            s->Printf(" which has no symbol");
77
78        if (m_step_over)
79            s->Printf(" stepping over calls");
80        else
81            s->Printf(" stepping into calls");
82    }
83}
84
85bool
86ThreadPlanStepInstruction::ValidatePlan (Stream *error)
87{
88    // Since we read the instruction we're stepping over from the thread,
89    // this plan will always work.
90    return true;
91}
92
93bool
94ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr)
95{
96    StopInfoSP stop_info_sp = GetPrivateStopInfo ();
97    if (stop_info_sp)
98    {
99        StopReason reason = stop_info_sp->GetStopReason();
100        if (reason == eStopReasonTrace || reason == eStopReasonNone)
101            return true;
102        else
103            return false;
104    }
105    return false;
106}
107
108bool
109ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
110{
111    if (m_step_over)
112    {
113        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
114
115        StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
116
117        if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id)
118        {
119            if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
120            {
121                SetPlanComplete();
122                return true;
123            }
124            else
125                return false;
126        }
127        else
128        {
129            // We've stepped in, step back out again:
130            StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
131            if (return_frame)
132            {
133                if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol)
134                {
135                    if (log)
136                    {
137                        StreamString s;
138                        s.PutCString ("Stepped in to: ");
139                        addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
140                        s.Address (stop_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
141                        s.PutCString (" stepping out to: ");
142                        addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
143                        s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
144                        log->Printf("%s.", s.GetData());
145                    }
146
147                    // StepInstruction should probably have the tri-state RunMode, but for now it is safer to
148                    // run others.
149                    const bool stop_others = false;
150                    m_thread.QueueThreadPlanForStepOut(false,
151                                                       NULL,
152                                                       true,
153                                                       stop_others,
154                                                       eVoteNo,
155                                                       eVoteNoOpinion,
156                                                       0);
157                    return false;
158                }
159                else
160                {
161                    if (log)
162                    {
163                        log->PutCString("The stack id we are stepping in changed, but our parent frame did not when stepping from code with no symbols.  "
164                        "We are probably just confused about where we are, stopping.");
165                    }
166                    SetPlanComplete();
167                    return true;
168                }
169            }
170            else
171            {
172                if (log)
173                    log->Printf("Could not find previous frame, stopping.");
174                SetPlanComplete();
175                return true;
176            }
177
178        }
179
180    }
181    else
182    {
183        if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
184        {
185            SetPlanComplete();
186            return true;
187        }
188        else
189            return false;
190    }
191}
192
193bool
194ThreadPlanStepInstruction::StopOthers ()
195{
196    return m_stop_other_threads;
197}
198
199StateType
200ThreadPlanStepInstruction::GetPlanRunState ()
201{
202    return eStateStepping;
203}
204
205bool
206ThreadPlanStepInstruction::WillStop ()
207{
208    return true;
209}
210
211bool
212ThreadPlanStepInstruction::MischiefManaged ()
213{
214    if (IsPlanComplete())
215    {
216        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
217        if (log)
218            log->Printf("Completed single instruction step plan.");
219        ThreadPlan::MischiefManaged ();
220        return true;
221    }
222    else
223    {
224        return false;
225    }
226}
227
228