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