blob: 5b343bb3394761cdf15d6e6498c9e1ff8d43c772 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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"
Greg Clayton643ee732010-08-04 01:40:35 +000021#include "lldb/Target/StopInfo.h"
Chris Lattner24943d22010-06-08 16:52:24 +000022#include "lldb/Target/Target.h"
23
24using namespace lldb;
25using namespace lldb_private;
26
27//----------------------------------------------------------------------
28// ThreadPlanStepOut: Step out of the current frame
29//----------------------------------------------------------------------
30
31ThreadPlanStepOut::ThreadPlanStepOut
32(
33 Thread &thread,
34 SymbolContext *context,
35 bool first_insn,
36 bool stop_others,
37 Vote stop_vote,
Greg Clayton1ebdcc72011-01-21 06:11:58 +000038 Vote run_vote,
39 uint32_t frame_idx
Chris Lattner24943d22010-06-08 16:52:24 +000040) :
Jim Ingham5a47e8b2010-06-19 04:45:32 +000041 ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
Chris Lattner24943d22010-06-08 16:52:24 +000042 m_step_from_context (context),
43 m_step_from_insn (LLDB_INVALID_ADDRESS),
Benjamin Kramer36a08102010-07-16 12:32:33 +000044 m_return_bp_id (LLDB_INVALID_BREAK_ID),
Chris Lattner24943d22010-06-08 16:52:24 +000045 m_return_addr (LLDB_INVALID_ADDRESS),
46 m_first_insn (first_insn),
Chris Lattner24943d22010-06-08 16:52:24 +000047 m_stop_others (stop_others)
48{
49 m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
50
51 // Find the return address and set a breakpoint there:
52 // FIXME - can we do this more securely if we know first_insn?
53
Greg Clayton1ebdcc72011-01-21 06:11:58 +000054 StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
55 if (return_frame_sp)
Chris Lattner24943d22010-06-08 16:52:24 +000056 {
Greg Claytonb04e7a82010-08-24 21:05:24 +000057 // TODO: check for inlined frames and do the right thing...
Greg Clayton1ebdcc72011-01-21 06:11:58 +000058 m_return_addr = return_frame_sp->GetRegisterContext()->GetPC();
Chris Lattner24943d22010-06-08 16:52:24 +000059 Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get();
60 if (return_bp != NULL)
61 {
62 return_bp->SetThreadID(m_thread.GetID());
63 m_return_bp_id = return_bp->GetID();
64 }
Chris Lattner24943d22010-06-08 16:52:24 +000065 }
66
Greg Clayton1ebdcc72011-01-21 06:11:58 +000067 m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
Chris Lattner24943d22010-06-08 16:52:24 +000068}
69
70ThreadPlanStepOut::~ThreadPlanStepOut ()
71{
72 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
73 m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id);
74}
75
76void
77ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
78{
79 if (level == lldb::eDescriptionLevelBrief)
80 s->Printf ("step out");
81 else
82 {
83 s->Printf ("Stepping out from address 0x%llx to return address 0x%llx using breakpoint site %d",
84 (uint64_t)m_step_from_insn,
85 (uint64_t)m_return_addr,
86 m_return_bp_id);
87 }
88}
89
90bool
91ThreadPlanStepOut::ValidatePlan (Stream *error)
92{
93 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
94 return false;
95 else
96 return true;
97}
98
99bool
100ThreadPlanStepOut::PlanExplainsStop ()
101{
102 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
103 // out will be handled by a child plan.
Jim Ingham6297a3a2010-10-20 00:39:53 +0000104 StopInfoSP stop_info_sp = GetPrivateStopReason();
105 if (stop_info_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000106 {
Jim Ingham6297a3a2010-10-20 00:39:53 +0000107 StopReason reason = stop_info_sp->GetStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +0000108 switch (reason)
109 {
Greg Clayton643ee732010-08-04 01:40:35 +0000110 case eStopReasonBreakpoint:
111 {
112 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
Jim Ingham6297a3a2010-10-20 00:39:53 +0000113 BreakpointSiteSP site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()));
Greg Clayton643ee732010-08-04 01:40:35 +0000114 if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id))
Chris Lattner24943d22010-06-08 16:52:24 +0000115 {
Greg Clayton1ebdcc72011-01-21 06:11:58 +0000116 const uint32_t num_frames = m_thread.GetStackFrameCount();
117 if (m_stack_depth > num_frames);
118 SetPlanComplete();
119
Greg Clayton643ee732010-08-04 01:40:35 +0000120 // If there was only one owner, then we're done. But if we also hit some
121 // user breakpoint on our way out, we should mark ourselves as done, but
122 // also not claim to explain the stop, since it is more important to report
123 // the user breakpoint than the step out completion.
Chris Lattner24943d22010-06-08 16:52:24 +0000124
Greg Clayton643ee732010-08-04 01:40:35 +0000125 if (site_sp->GetNumberOfOwners() == 1)
126 return true;
127
Chris Lattner24943d22010-06-08 16:52:24 +0000128 }
Greg Clayton643ee732010-08-04 01:40:35 +0000129 return false;
130 }
131 case eStopReasonWatchpoint:
132 case eStopReasonSignal:
133 case eStopReasonException:
134 return false;
135
136 default:
137 return true;
Chris Lattner24943d22010-06-08 16:52:24 +0000138 }
139 }
140 return true;
141}
142
143bool
144ThreadPlanStepOut::ShouldStop (Event *event_ptr)
145{
Greg Clayton1ebdcc72011-01-21 06:11:58 +0000146 if (IsPlanComplete() || m_stack_depth > m_thread.GetStackFrameCount())
Chris Lattner24943d22010-06-08 16:52:24 +0000147 {
148 SetPlanComplete();
149 return true;
150 }
151 else
152 return false;
153}
154
155bool
156ThreadPlanStepOut::StopOthers ()
157{
158 return m_stop_others;
159}
160
161StateType
Jim Ingham745ac7a2010-11-11 19:26:09 +0000162ThreadPlanStepOut::GetPlanRunState ()
Chris Lattner24943d22010-06-08 16:52:24 +0000163{
164 return eStateRunning;
165}
166
167bool
168ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan)
169{
170 ThreadPlan::WillResume (resume_state, current_plan);
171 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
172 return false;
173
174 if (current_plan)
175 {
176 Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
177 if (return_bp != NULL)
178 return_bp->SetEnabled (true);
179 }
180 return true;
181}
182
183bool
184ThreadPlanStepOut::WillStop ()
185{
186 Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
187 if (return_bp != NULL)
188 return_bp->SetEnabled (false);
189 return true;
190}
191
192bool
193ThreadPlanStepOut::MischiefManaged ()
194{
195 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
196 {
197 // If I couldn't set this breakpoint, then I'm just going to jettison myself.
198 return true;
199 }
200 else if (IsPlanComplete())
201 {
202 // Did I reach my breakpoint? If so I'm done.
203 //
204 // I also check the stack depth, since if we've blown past the breakpoint for some
205 // reason and we're now stopping for some other reason altogether, then we're done
206 // with this step out operation.
207
Greg Claytone005f2c2010-11-06 01:53:30 +0000208 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000209 if (log)
210 log->Printf("Completed step out plan.");
211 m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_return_bp_id);
212 m_return_bp_id = LLDB_INVALID_BREAK_ID;
213 ThreadPlan::MischiefManaged ();
214 return true;
215 }
216 else
217 {
218 return false;
219 }
220}
221