1 //===-- ThreadPlanStepOut.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 #include "lldb/Target/ThreadPlanStepOut.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Breakpoint/Breakpoint.h"
17 #include "lldb/lldb-private-log.h"
18 #include "lldb/Core/Log.h"
19 #include "lldb/Target/Process.h"
20 #include "lldb/Target/RegisterContext.h"
21 #include "lldb/Target/Target.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 //----------------------------------------------------------------------
27 // ThreadPlanStepOut: Step out of the current frame
28 //----------------------------------------------------------------------
29 
30 ThreadPlanStepOut::ThreadPlanStepOut
31 (
32     Thread &thread,
33     SymbolContext *context,
34     bool first_insn,
35     bool stop_others,
36     Vote stop_vote,
37     Vote run_vote
38 ) :
39     ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
40     m_step_from_context (context),
41     m_step_from_insn (LLDB_INVALID_ADDRESS),
42     m_return_addr (LLDB_INVALID_ADDRESS),
43     m_first_insn (first_insn),
44     m_return_bp_id(LLDB_INVALID_BREAK_ID),
45     m_stop_others (stop_others)
46 {
47     m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
48 
49     // Find the return address and set a breakpoint there:
50     // FIXME - can we do this more securely if we know first_insn?
51 
52     StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
53     if (return_frame)
54     {
55         m_return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
56         Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get();
57         if (return_bp != NULL)
58         {
59             return_bp->SetThreadID(m_thread.GetID());
60             m_return_bp_id = return_bp->GetID();
61         }
62         else
63         {
64             m_return_bp_id = LLDB_INVALID_BREAK_ID;
65         }
66     }
67 
68     m_stack_depth = m_thread.GetStackFrameCount();
69 }
70 
71 ThreadPlanStepOut::~ThreadPlanStepOut ()
72 {
73     if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
74         m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id);
75 }
76 
77 void
78 ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
79 {
80     if (level == lldb::eDescriptionLevelBrief)
81         s->Printf ("step out");
82     else
83     {
84         s->Printf ("Stepping out from address 0x%llx to return address 0x%llx using breakpoint site %d",
85                    (uint64_t)m_step_from_insn,
86                    (uint64_t)m_return_addr,
87                    m_return_bp_id);
88     }
89 }
90 
91 bool
92 ThreadPlanStepOut::ValidatePlan (Stream *error)
93 {
94     if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
95         return false;
96     else
97         return true;
98 }
99 
100 bool
101 ThreadPlanStepOut::PlanExplainsStop ()
102 {
103     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
104     // out will be handled by a child plan.
105     Thread::StopInfo info;
106     if (m_thread.GetStopInfo (&info))
107     {
108         StopReason reason = info.GetStopReason();
109 
110         switch (reason)
111         {
112             case eStopReasonBreakpoint:
113             {
114                 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
115                 BreakpointSiteSP this_site = m_thread.GetProcess().GetBreakpointSiteList().FindByID (info.GetBreakpointSiteID());
116                 if (!this_site)
117                     return false;
118 
119                 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
120                 {
121                     // If there was only one owner, then we're done.  But if we also hit some
122                     // user breakpoint on our way out, we should mark ourselves as done, but
123                     // also not claim to explain the stop, since it is more important to report
124                     // the user breakpoint than the step out completion.
125 
126                     if (this_site->GetNumberOfOwners() == 1)
127                         return true;
128                     else
129                     {
130                         SetPlanComplete();
131                         return false;
132                     }
133                 }
134                 else
135                     return false;
136             }
137             case eStopReasonWatchpoint:
138             case eStopReasonSignal:
139             case eStopReasonException:
140                 return false;
141             default:
142                 return true;
143         }
144     }
145     return true;
146 }
147 
148 bool
149 ThreadPlanStepOut::ShouldStop (Event *event_ptr)
150 {
151     if (IsPlanComplete()
152         || m_thread.GetRegisterContext()->GetPC() == m_return_addr
153         || m_stack_depth > m_thread.GetStackFrameCount())
154     {
155         SetPlanComplete();
156         return true;
157     }
158     else
159         return false;
160 }
161 
162 bool
163 ThreadPlanStepOut::StopOthers ()
164 {
165     return m_stop_others;
166 }
167 
168 StateType
169 ThreadPlanStepOut::RunState ()
170 {
171     return eStateRunning;
172 }
173 
174 bool
175 ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan)
176 {
177     ThreadPlan::WillResume (resume_state, current_plan);
178     if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
179         return false;
180 
181     if (current_plan)
182     {
183         Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
184         if (return_bp != NULL)
185             return_bp->SetEnabled (true);
186     }
187     return true;
188 }
189 
190 bool
191 ThreadPlanStepOut::WillStop ()
192 {
193     Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
194     if (return_bp != NULL)
195         return_bp->SetEnabled (false);
196     return true;
197 }
198 
199 bool
200 ThreadPlanStepOut::MischiefManaged ()
201 {
202     if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
203     {
204         // If I couldn't set this breakpoint, then I'm just going to jettison myself.
205         return true;
206     }
207     else if (IsPlanComplete())
208     {
209         // Did I reach my breakpoint?  If so I'm done.
210         //
211         // I also check the stack depth, since if we've blown past the breakpoint for some
212         // reason and we're now stopping for some other reason altogether, then we're done
213         // with this step out operation.
214 
215         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
216         if (log)
217             log->Printf("Completed step out plan.");
218         m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_return_bp_id);
219         m_return_bp_id = LLDB_INVALID_BREAK_ID;
220         ThreadPlan::MischiefManaged ();
221         return true;
222     }
223     else
224     {
225         return false;
226     }
227 }
228 
229