blob: 3c418f20aca9301ad3333a5ea84b03d67808ad31 [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,
Greg Clayton1ebdcc72011-01-21 06:11:58 +000040 bool stop_others,
41 uint32_t frame_idx
Chris Lattner24943d22010-06-08 16:52:24 +000042) :
Jim Ingham5a47e8b2010-06-19 04:45:32 +000043 ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion),
Chris Lattner24943d22010-06-08 16:52:24 +000044 m_step_from_insn (LLDB_INVALID_ADDRESS),
Jim Ingham441e3b92012-03-01 00:50:50 +000045 m_return_bp_id (LLDB_INVALID_BREAK_ID),
Greg Clayton54e7afa2010-07-09 20:39:50 +000046 m_return_addr (LLDB_INVALID_ADDRESS),
Jim Ingham441e3b92012-03-01 00:50:50 +000047 m_stepped_out (false),
48 m_should_stop (false),
Chris Lattner24943d22010-06-08 16:52:24 +000049 m_ran_analyze (false),
Jim Ingham441e3b92012-03-01 00:50: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
Jim Ingham2bcbaf62012-04-09 22:37:39 +000055 // Step until plans can be master plans, since you could hit a breakpoint while stepping to the stop point, step around
56 // a bit, then continue to finish up the step until.
57 SetIsMasterPlan (true);
Chris Lattner24943d22010-06-08 16:52:24 +000058 SetOkayToDiscard(true);
Jim Ingham2bcbaf62012-04-09 22:37:39 +000059
Chris Lattner24943d22010-06-08 16:52:24 +000060 // Stash away our "until" addresses:
Greg Claytonf4124de2012-02-21 00:09:25 +000061 TargetSP target_sp (m_thread.CalculateTarget());
Chris Lattner24943d22010-06-08 16:52:24 +000062
Greg Clayton1ebdcc72011-01-21 06:11:58 +000063 StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
64 if (frame_sp)
Chris Lattner24943d22010-06-08 16:52:24 +000065 {
Greg Clayton1ebdcc72011-01-21 06:11:58 +000066 m_step_from_insn = frame_sp->GetStackID().GetPC();
67 lldb::user_id_t thread_id = m_thread.GetID();
Chris Lattner24943d22010-06-08 16:52:24 +000068
Greg Clayton1ebdcc72011-01-21 06:11:58 +000069 // Find the return address and set a breakpoint there:
70 // FIXME - can we do this more securely if we know first_insn?
Chris Lattner24943d22010-06-08 16:52:24 +000071
Greg Clayton1ebdcc72011-01-21 06:11:58 +000072 StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
73 if (return_frame_sp)
Chris Lattner24943d22010-06-08 16:52:24 +000074 {
Greg Clayton1ebdcc72011-01-21 06:11:58 +000075 // TODO: add inline functionality
76 m_return_addr = return_frame_sp->GetStackID().GetPC();
Greg Claytonf4124de2012-02-21 00:09:25 +000077 Breakpoint *return_bp = target_sp->CreateBreakpoint (m_return_addr, true).get();
Greg Clayton1ebdcc72011-01-21 06:11:58 +000078 if (return_bp != NULL)
79 {
80 return_bp->SetThreadID(thread_id);
81 m_return_bp_id = return_bp->GetID();
82 }
Chris Lattner24943d22010-06-08 16:52:24 +000083 }
Greg Clayton1ebdcc72011-01-21 06:11:58 +000084
Jim Ingham441e3b92012-03-01 00:50:50 +000085 m_stack_id = m_thread.GetStackFrameAtIndex(frame_idx)->GetStackID();
Greg Clayton1ebdcc72011-01-21 06:11:58 +000086
87 // Now set breakpoints on all our return addresses:
88 for (int i = 0; i < num_addresses; i++)
Chris Lattner24943d22010-06-08 16:52:24 +000089 {
Greg Claytonf4124de2012-02-21 00:09:25 +000090 Breakpoint *until_bp = target_sp->CreateBreakpoint (address_list[i], true).get();
Greg Clayton1ebdcc72011-01-21 06:11:58 +000091 if (until_bp != NULL)
92 {
93 until_bp->SetThreadID(thread_id);
94 m_until_points[address_list[i]] = until_bp->GetID();
95 }
96 else
97 {
98 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
99 }
Chris Lattner24943d22010-06-08 16:52:24 +0000100 }
101 }
102}
103
104ThreadPlanStepUntil::~ThreadPlanStepUntil ()
105{
106 Clear();
107}
108
109void
110ThreadPlanStepUntil::Clear()
111{
Greg Claytonf4124de2012-02-21 00:09:25 +0000112 TargetSP target_sp (m_thread.CalculateTarget());
113 if (target_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000114 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000115 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
116 {
117 target_sp->RemoveBreakpointByID(m_return_bp_id);
118 m_return_bp_id = LLDB_INVALID_BREAK_ID;
119 }
Chris Lattner24943d22010-06-08 16:52:24 +0000120
Greg Claytonf4124de2012-02-21 00:09:25 +0000121 until_collection::iterator pos, end = m_until_points.end();
122 for (pos = m_until_points.begin(); pos != end; pos++)
123 {
124 target_sp->RemoveBreakpointByID((*pos).second);
125 }
Chris Lattner24943d22010-06-08 16:52:24 +0000126 }
127 m_until_points.clear();
128}
129
130void
131ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
132{
133 if (level == lldb::eDescriptionLevelBrief)
134 {
135 s->Printf ("step until");
136 if (m_stepped_out)
137 s->Printf (" - stepped out");
138 }
139 else
140 {
141 if (m_until_points.size() == 1)
142 s->Printf ("Stepping from address 0x%llx until we reach 0x%llx using breakpoint %d",
143 (uint64_t)m_step_from_insn,
144 (uint64_t) (*m_until_points.begin()).first,
145 (*m_until_points.begin()).second);
146 else
147 {
148 until_collection::iterator pos, end = m_until_points.end();
149 s->Printf ("Stepping from address 0x%llx until we reach one of:",
150 (uint64_t)m_step_from_insn);
151 for (pos = m_until_points.begin(); pos != end; pos++)
152 {
153 s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
154 }
155 }
Jason Molenda7e5fa7f2011-09-20 21:44:10 +0000156 s->Printf(" stepped out address is 0x%llx.", (uint64_t) m_return_addr);
Chris Lattner24943d22010-06-08 16:52:24 +0000157 }
158}
159
160bool
161ThreadPlanStepUntil::ValidatePlan (Stream *error)
162{
163 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
164 return false;
165 else
166 {
167 until_collection::iterator pos, end = m_until_points.end();
168 for (pos = m_until_points.begin(); pos != end; pos++)
169 {
170 if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
171 return false;
172 }
173 return true;
174 }
175}
176
177void
178ThreadPlanStepUntil::AnalyzeStop()
179{
180 if (m_ran_analyze)
181 return;
182
Jim Ingham6297a3a2010-10-20 00:39:53 +0000183 StopInfoSP stop_info_sp = GetPrivateStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +0000184 m_should_stop = true;
185 m_explains_stop = false;
186
Jim Ingham6297a3a2010-10-20 00:39:53 +0000187 if (stop_info_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000188 {
Jim Ingham6297a3a2010-10-20 00:39:53 +0000189 StopReason reason = stop_info_sp->GetStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +0000190
191 switch (reason)
192 {
193 case eStopReasonBreakpoint:
194 {
195 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
Greg Claytonf4124de2012-02-21 00:09:25 +0000196 BreakpointSiteSP this_site = m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue());
Chris Lattner24943d22010-06-08 16:52:24 +0000197 if (!this_site)
198 {
199 m_explains_stop = false;
200 return;
201 }
202
203 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
204 {
205 // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
206 // this is indeed our stop.
207 // If the stack depth has grown, then we've hit our step out breakpoint recursively.
208 // If we are the only breakpoint at that location, then we do explain the stop, and
209 // we'll just continue.
210 // If there was another breakpoint here, then we don't explain the stop, but we won't
211 // mark ourselves Completed, because maybe that breakpoint will continue, and then
212 // we'll finish the "until".
Jim Ingham441e3b92012-03-01 00:50:50 +0000213 bool done;
214 StackID cur_frame_zero_id;
215
216 if (m_stack_id < cur_frame_zero_id)
217 done = true;
218 else
219 done = false;
220
221 if (done)
Chris Lattner24943d22010-06-08 16:52:24 +0000222 {
223 m_stepped_out = true;
224 SetPlanComplete();
225 }
226 else
227 m_should_stop = false;
228
229 if (this_site->GetNumberOfOwners() == 1)
230 m_explains_stop = true;
231 else
232 m_explains_stop = false;
233 return;
234 }
235 else
236 {
237 // Check if we've hit one of our "until" breakpoints.
238 until_collection::iterator pos, end = m_until_points.end();
239 for (pos = m_until_points.begin(); pos != end; pos++)
240 {
241 if (this_site->IsBreakpointAtThisSite ((*pos).second))
242 {
243 // If we're at the right stack depth, then we're done.
Jim Ingham441e3b92012-03-01 00:50:50 +0000244
245 bool done;
246 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
247
248 if (frame_zero_id == m_stack_id)
249 done = true;
250 else if (frame_zero_id < m_stack_id)
251 done = false;
252 else
253 {
254 StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
255
256 // But if we can't even unwind one frame we should just get out of here & stop...
257 if (older_frame_sp)
258 {
259 const SymbolContext &older_context
260 = older_frame_sp->GetSymbolContext(eSymbolContextEverything);
261 SymbolContext stack_context;
262 m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(&stack_context);
263
264 if (older_context == stack_context)
265 done = true;
266 else
267 done = false;
268 }
269 else
270 done = false;
271 }
272
273 if (done)
Chris Lattner24943d22010-06-08 16:52:24 +0000274 SetPlanComplete();
275 else
276 m_should_stop = false;
277
278 // Otherwise we've hit this breakpoint recursively. If we're the
279 // only breakpoint here, then we do explain the stop, and we'll continue.
280 // If not then we should let higher plans handle this stop.
281 if (this_site->GetNumberOfOwners() == 1)
282 m_explains_stop = true;
283 else
284 {
285 m_should_stop = true;
286 m_explains_stop = false;
287 }
288 return;
289 }
290 }
291 }
292 // If we get here we haven't hit any of our breakpoints, so let the higher
293 // plans take care of the stop.
294 m_explains_stop = false;
295 return;
296 }
297 case eStopReasonWatchpoint:
298 case eStopReasonSignal:
299 case eStopReasonException:
300 m_explains_stop = false;
301 break;
302 default:
303 m_explains_stop = true;
304 break;
305 }
306 }
307}
308
309bool
310ThreadPlanStepUntil::PlanExplainsStop ()
311{
312 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
313 // out will be handled by a child plan.
314 AnalyzeStop();
315 return m_explains_stop;
316}
317
318bool
319ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
320{
321 // If we've told our self in ExplainsStop that we plan to continue, then
322 // do so here. Otherwise, as long as this thread has stopped for a reason,
323 // we will stop.
324
Jim Ingham6297a3a2010-10-20 00:39:53 +0000325 StopInfoSP stop_info_sp = GetPrivateStopReason();
326 if (stop_info_sp == NULL || stop_info_sp->GetStopReason() == eStopReasonNone)
Chris Lattner24943d22010-06-08 16:52:24 +0000327 return false;
328
329 AnalyzeStop();
330 return m_should_stop;
331}
332
333bool
334ThreadPlanStepUntil::StopOthers ()
335{
336 return m_stop_others;
337}
338
339StateType
Jim Ingham745ac7a2010-11-11 19:26:09 +0000340ThreadPlanStepUntil::GetPlanRunState ()
Chris Lattner24943d22010-06-08 16:52:24 +0000341{
342 return eStateRunning;
343}
344
345bool
346ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
347{
348 ThreadPlan::WillResume (resume_state, current_plan);
349 if (current_plan)
350 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000351 TargetSP target_sp (m_thread.CalculateTarget());
352 if (target_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000353 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000354 Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
355 if (return_bp != NULL)
356 return_bp->SetEnabled (true);
357
358 until_collection::iterator pos, end = m_until_points.end();
359 for (pos = m_until_points.begin(); pos != end; pos++)
360 {
361 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
362 if (until_bp != NULL)
363 until_bp->SetEnabled (true);
364 }
Chris Lattner24943d22010-06-08 16:52:24 +0000365 }
366 }
367
368 m_should_stop = true;
369 m_ran_analyze = false;
370 m_explains_stop = false;
371 return true;
372}
373
374bool
375ThreadPlanStepUntil::WillStop ()
376{
Greg Claytonf4124de2012-02-21 00:09:25 +0000377 TargetSP target_sp (m_thread.CalculateTarget());
378 if (target_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000379 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000380 Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
381 if (return_bp != NULL)
382 return_bp->SetEnabled (false);
383
384 until_collection::iterator pos, end = m_until_points.end();
385 for (pos = m_until_points.begin(); pos != end; pos++)
386 {
387 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
388 if (until_bp != NULL)
389 until_bp->SetEnabled (false);
390 }
Chris Lattner24943d22010-06-08 16:52:24 +0000391 }
392 return true;
393}
394
395bool
396ThreadPlanStepUntil::MischiefManaged ()
397{
398
399 // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
400 bool done = false;
401 if (IsPlanComplete())
402 {
Greg Claytone005f2c2010-11-06 01:53:30 +0000403 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000404 if (log)
405 log->Printf("Completed step until plan.");
406
407 Clear();
408 done = true;
409 }
410 if (done)
411 ThreadPlan::MischiefManaged ();
412
413 return done;
414
415}
416