blob: e05a8a440a1d006f30b45967036a992cdc1d5c53 [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"
21#include "lldb/Target/Target.h"
22
23using namespace lldb;
24using namespace lldb_private;
25
26//----------------------------------------------------------------------
27// ThreadPlanStepOut: Step out of the current frame
28//----------------------------------------------------------------------
29
30ThreadPlanStepOut::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 ("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
71ThreadPlanStepOut::~ThreadPlanStepOut ()
72{
73 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
74 m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id);
75}
76
77void
78ThreadPlanStepOut::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
91bool
92ThreadPlanStepOut::ValidatePlan (Stream *error)
93{
94 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
95 return false;
96 else
97 return true;
98}
99
100bool
101ThreadPlanStepOut::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
148bool
149ThreadPlanStepOut::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
162bool
163ThreadPlanStepOut::StopOthers ()
164{
165 return m_stop_others;
166}
167
168StateType
169ThreadPlanStepOut::RunState ()
170{
171 return eStateRunning;
172}
173
174bool
175ThreadPlanStepOut::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
190bool
191ThreadPlanStepOut::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
199bool
200ThreadPlanStepOut::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