blob: d146b6ae5cd7b9ed4f827df4f5ce9c28c7e4918f [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- ThreadPlanStepUntil.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//m_should_stop
10
11//
12//===----------------------------------------------------------------------===//
13
14#include "lldb/Target/ThreadPlanStepUntil.h"
15
16// C Includes
17// C++ Includes
18// Other libraries and framework includes
19// Project includes
20#include "lldb/Breakpoint/Breakpoint.h"
21#include "lldb/lldb-private-log.h"
22#include "lldb/Core/Log.h"
23#include "lldb/Target/Process.h"
24#include "lldb/Target/RegisterContext.h"
25#include "lldb/Target/Target.h"
26
27using namespace lldb;
28using namespace lldb_private;
29
30//----------------------------------------------------------------------
31// ThreadPlanStepUntil: Run until we reach a given line number or step out of the current frame
32//----------------------------------------------------------------------
33
34ThreadPlanStepUntil::ThreadPlanStepUntil
35(
36 Thread &thread,
37 lldb::addr_t *address_list,
38 size_t num_addresses,
39 bool stop_others
40) :
Jim Ingham5a47e8b2010-06-19 04:45:32 +000041 ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion),
Chris Lattner24943d22010-06-08 16:52:24 +000042 m_step_from_insn (LLDB_INVALID_ADDRESS),
43 m_return_addr (LLDB_INVALID_ADDRESS),
44 m_return_bp_id(LLDB_INVALID_BREAK_ID),
45 m_stepped_out(false),
46 m_should_stop(false),
47 m_explains_stop(false),
48 m_ran_analyze (false),
49 m_stop_others (stop_others)
50{
51
52 SetOkayToDiscard(true);
53 // Stash away our "until" addresses:
54 Target &target = m_thread.GetProcess().GetTarget();
55
56 m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
57 lldb::user_id_t thread_id = m_thread.GetID();
58
59 // Find the return address and set a breakpoint there:
60 // FIXME - can we do this more securely if we know first_insn?
61
62 StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
63 m_return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
64 Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
65 if (return_bp != NULL)
66 {
67 return_bp->SetThreadID(thread_id);
68 m_return_bp_id = return_bp->GetID();
69 }
70 else
71 {
72 m_return_bp_id = LLDB_INVALID_BREAK_ID;
73 }
74
75 m_stack_depth = m_thread.GetStackFrameCount();
76
77 // Now set breakpoints on all our return addresses:
78 for (int i = 0; i < num_addresses; i++)
79 {
80 Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
81 if (until_bp != NULL)
82 {
83 until_bp->SetThreadID(thread_id);
84 m_until_points[address_list[i]] = until_bp->GetID();
85 }
86 else
87 {
88 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
89 }
90 }
91}
92
93ThreadPlanStepUntil::~ThreadPlanStepUntil ()
94{
95 Clear();
96}
97
98void
99ThreadPlanStepUntil::Clear()
100{
101 Target &target = m_thread.GetProcess().GetTarget();
102 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
103 {
104 target.RemoveBreakpointByID(m_return_bp_id);
105 m_return_bp_id = LLDB_INVALID_BREAK_ID;
106 }
107
108 until_collection::iterator pos, end = m_until_points.end();
109 for (pos = m_until_points.begin(); pos != end; pos++)
110 {
111 target.RemoveBreakpointByID((*pos).second);
112 }
113 m_until_points.clear();
114}
115
116void
117ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
118{
119 if (level == lldb::eDescriptionLevelBrief)
120 {
121 s->Printf ("step until");
122 if (m_stepped_out)
123 s->Printf (" - stepped out");
124 }
125 else
126 {
127 if (m_until_points.size() == 1)
128 s->Printf ("Stepping from address 0x%llx until we reach 0x%llx using breakpoint %d",
129 (uint64_t)m_step_from_insn,
130 (uint64_t) (*m_until_points.begin()).first,
131 (*m_until_points.begin()).second);
132 else
133 {
134 until_collection::iterator pos, end = m_until_points.end();
135 s->Printf ("Stepping from address 0x%llx until we reach one of:",
136 (uint64_t)m_step_from_insn);
137 for (pos = m_until_points.begin(); pos != end; pos++)
138 {
139 s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
140 }
141 }
142 s->Printf(" stepped out address is 0x%lx.", (uint64_t) m_return_addr);
143 }
144}
145
146bool
147ThreadPlanStepUntil::ValidatePlan (Stream *error)
148{
149 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
150 return false;
151 else
152 {
153 until_collection::iterator pos, end = m_until_points.end();
154 for (pos = m_until_points.begin(); pos != end; pos++)
155 {
156 if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
157 return false;
158 }
159 return true;
160 }
161}
162
163void
164ThreadPlanStepUntil::AnalyzeStop()
165{
166 if (m_ran_analyze)
167 return;
168
169 Thread::StopInfo info;
170 m_should_stop = true;
171 m_explains_stop = false;
172
173 if (m_thread.GetStopInfo (&info))
174 {
175 StopReason reason = info.GetStopReason();
176
177 switch (reason)
178 {
179 case eStopReasonBreakpoint:
180 {
181 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
182 BreakpointSiteSP this_site = m_thread.GetProcess().GetBreakpointSiteList().FindByID (info.GetBreakpointSiteID());
183 if (!this_site)
184 {
185 m_explains_stop = false;
186 return;
187 }
188
189 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
190 {
191 // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
192 // this is indeed our stop.
193 // If the stack depth has grown, then we've hit our step out breakpoint recursively.
194 // If we are the only breakpoint at that location, then we do explain the stop, and
195 // we'll just continue.
196 // If there was another breakpoint here, then we don't explain the stop, but we won't
197 // mark ourselves Completed, because maybe that breakpoint will continue, and then
198 // we'll finish the "until".
199 if (m_stack_depth > m_thread.GetStackFrameCount())
200 {
201 m_stepped_out = true;
202 SetPlanComplete();
203 }
204 else
205 m_should_stop = false;
206
207 if (this_site->GetNumberOfOwners() == 1)
208 m_explains_stop = true;
209 else
210 m_explains_stop = false;
211 return;
212 }
213 else
214 {
215 // Check if we've hit one of our "until" breakpoints.
216 until_collection::iterator pos, end = m_until_points.end();
217 for (pos = m_until_points.begin(); pos != end; pos++)
218 {
219 if (this_site->IsBreakpointAtThisSite ((*pos).second))
220 {
221 // If we're at the right stack depth, then we're done.
222 if (m_stack_depth == m_thread.GetStackFrameCount())
223 SetPlanComplete();
224 else
225 m_should_stop = false;
226
227 // Otherwise we've hit this breakpoint recursively. If we're the
228 // only breakpoint here, then we do explain the stop, and we'll continue.
229 // If not then we should let higher plans handle this stop.
230 if (this_site->GetNumberOfOwners() == 1)
231 m_explains_stop = true;
232 else
233 {
234 m_should_stop = true;
235 m_explains_stop = false;
236 }
237 return;
238 }
239 }
240 }
241 // If we get here we haven't hit any of our breakpoints, so let the higher
242 // plans take care of the stop.
243 m_explains_stop = false;
244 return;
245 }
246 case eStopReasonWatchpoint:
247 case eStopReasonSignal:
248 case eStopReasonException:
249 m_explains_stop = false;
250 break;
251 default:
252 m_explains_stop = true;
253 break;
254 }
255 }
256}
257
258bool
259ThreadPlanStepUntil::PlanExplainsStop ()
260{
261 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
262 // out will be handled by a child plan.
263 AnalyzeStop();
264 return m_explains_stop;
265}
266
267bool
268ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
269{
270 // If we've told our self in ExplainsStop that we plan to continue, then
271 // do so here. Otherwise, as long as this thread has stopped for a reason,
272 // we will stop.
273
274 Thread::StopInfo stop_info (&m_thread);
275 if (!m_thread.GetStopInfo(&stop_info)
276 || stop_info.GetStopReason() == eStopReasonNone)
277 return false;
278
279 AnalyzeStop();
280 return m_should_stop;
281}
282
283bool
284ThreadPlanStepUntil::StopOthers ()
285{
286 return m_stop_others;
287}
288
289StateType
290ThreadPlanStepUntil::RunState ()
291{
292 return eStateRunning;
293}
294
295bool
296ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
297{
298 ThreadPlan::WillResume (resume_state, current_plan);
299 if (current_plan)
300 {
301 Target &target = m_thread.GetProcess().GetTarget();
302 Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
303 if (return_bp != NULL)
304 return_bp->SetEnabled (true);
305
306 until_collection::iterator pos, end = m_until_points.end();
307 for (pos = m_until_points.begin(); pos != end; pos++)
308 {
309 Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
310 if (until_bp != NULL)
311 until_bp->SetEnabled (true);
312 }
313 }
314
315 m_should_stop = true;
316 m_ran_analyze = false;
317 m_explains_stop = false;
318 return true;
319}
320
321bool
322ThreadPlanStepUntil::WillStop ()
323{
324 Target &target = m_thread.GetProcess().GetTarget();
325 Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
326 if (return_bp != NULL)
327 return_bp->SetEnabled (false);
328
329 until_collection::iterator pos, end = m_until_points.end();
330 for (pos = m_until_points.begin(); pos != end; pos++)
331 {
332 Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
333 if (until_bp != NULL)
334 until_bp->SetEnabled (false);
335 }
336 return true;
337}
338
339bool
340ThreadPlanStepUntil::MischiefManaged ()
341{
342
343 // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
344 bool done = false;
345 if (IsPlanComplete())
346 {
347 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
348 if (log)
349 log->Printf("Completed step until plan.");
350
351 Clear();
352 done = true;
353 }
354 if (done)
355 ThreadPlan::MischiefManaged ();
356
357 return done;
358
359}
360