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