blob: 95b0a352f2c30dc003f9999e596a16a2d19939fb [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{
Chris Lattner24943d22010-06-08 16:52:24 +000054 // Stash away our "until" addresses:
Greg Claytonf4124de2012-02-21 00:09:25 +000055 TargetSP target_sp (m_thread.CalculateTarget());
Chris Lattner24943d22010-06-08 16:52:24 +000056
Greg Clayton1ebdcc72011-01-21 06:11:58 +000057 StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
58 if (frame_sp)
Chris Lattner24943d22010-06-08 16:52:24 +000059 {
Greg Clayton1ebdcc72011-01-21 06:11:58 +000060 m_step_from_insn = frame_sp->GetStackID().GetPC();
61 lldb::user_id_t thread_id = m_thread.GetID();
Chris Lattner24943d22010-06-08 16:52:24 +000062
Greg Clayton1ebdcc72011-01-21 06:11:58 +000063 // Find the return address and set a breakpoint there:
64 // FIXME - can we do this more securely if we know first_insn?
Chris Lattner24943d22010-06-08 16:52:24 +000065
Greg Clayton1ebdcc72011-01-21 06:11:58 +000066 StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
67 if (return_frame_sp)
Chris Lattner24943d22010-06-08 16:52:24 +000068 {
Greg Clayton1ebdcc72011-01-21 06:11:58 +000069 // TODO: add inline functionality
70 m_return_addr = return_frame_sp->GetStackID().GetPC();
Greg Claytonf4124de2012-02-21 00:09:25 +000071 Breakpoint *return_bp = target_sp->CreateBreakpoint (m_return_addr, true).get();
Greg Clayton1ebdcc72011-01-21 06:11:58 +000072 if (return_bp != NULL)
73 {
74 return_bp->SetThreadID(thread_id);
75 m_return_bp_id = return_bp->GetID();
76 }
Chris Lattner24943d22010-06-08 16:52:24 +000077 }
Greg Clayton1ebdcc72011-01-21 06:11:58 +000078
Jim Ingham441e3b92012-03-01 00:50:50 +000079 m_stack_id = m_thread.GetStackFrameAtIndex(frame_idx)->GetStackID();
Greg Clayton1ebdcc72011-01-21 06:11:58 +000080
81 // Now set breakpoints on all our return addresses:
82 for (int i = 0; i < num_addresses; i++)
Chris Lattner24943d22010-06-08 16:52:24 +000083 {
Greg Claytonf4124de2012-02-21 00:09:25 +000084 Breakpoint *until_bp = target_sp->CreateBreakpoint (address_list[i], true).get();
Greg Clayton1ebdcc72011-01-21 06:11:58 +000085 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 }
Chris Lattner24943d22010-06-08 16:52:24 +000094 }
95 }
96}
97
98ThreadPlanStepUntil::~ThreadPlanStepUntil ()
99{
100 Clear();
101}
102
103void
104ThreadPlanStepUntil::Clear()
105{
Greg Claytonf4124de2012-02-21 00:09:25 +0000106 TargetSP target_sp (m_thread.CalculateTarget());
107 if (target_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000108 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000109 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
110 {
111 target_sp->RemoveBreakpointByID(m_return_bp_id);
112 m_return_bp_id = LLDB_INVALID_BREAK_ID;
113 }
Chris Lattner24943d22010-06-08 16:52:24 +0000114
Greg Claytonf4124de2012-02-21 00:09:25 +0000115 until_collection::iterator pos, end = m_until_points.end();
116 for (pos = m_until_points.begin(); pos != end; pos++)
117 {
118 target_sp->RemoveBreakpointByID((*pos).second);
119 }
Chris Lattner24943d22010-06-08 16:52:24 +0000120 }
121 m_until_points.clear();
122}
123
124void
125ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
126{
127 if (level == lldb::eDescriptionLevelBrief)
128 {
129 s->Printf ("step until");
130 if (m_stepped_out)
131 s->Printf (" - stepped out");
132 }
133 else
134 {
135 if (m_until_points.size() == 1)
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000136 s->Printf ("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64 " using breakpoint %d",
Chris Lattner24943d22010-06-08 16:52:24 +0000137 (uint64_t)m_step_from_insn,
138 (uint64_t) (*m_until_points.begin()).first,
139 (*m_until_points.begin()).second);
140 else
141 {
142 until_collection::iterator pos, end = m_until_points.end();
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000143 s->Printf ("Stepping from address 0x%" PRIx64 " until we reach one of:",
Chris Lattner24943d22010-06-08 16:52:24 +0000144 (uint64_t)m_step_from_insn);
145 for (pos = m_until_points.begin(); pos != end; pos++)
146 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000147 s->Printf ("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
Chris Lattner24943d22010-06-08 16:52:24 +0000148 }
149 }
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000150 s->Printf(" stepped out address is 0x%" PRIx64 ".", (uint64_t) m_return_addr);
Chris Lattner24943d22010-06-08 16:52:24 +0000151 }
152}
153
154bool
155ThreadPlanStepUntil::ValidatePlan (Stream *error)
156{
157 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
158 return false;
159 else
160 {
161 until_collection::iterator pos, end = m_until_points.end();
162 for (pos = m_until_points.begin(); pos != end; pos++)
163 {
164 if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
165 return false;
166 }
167 return true;
168 }
169}
170
171void
172ThreadPlanStepUntil::AnalyzeStop()
173{
174 if (m_ran_analyze)
175 return;
176
Jim Ingham6297a3a2010-10-20 00:39:53 +0000177 StopInfoSP stop_info_sp = GetPrivateStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +0000178 m_should_stop = true;
179 m_explains_stop = false;
180
Jim Ingham6297a3a2010-10-20 00:39:53 +0000181 if (stop_info_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000182 {
Jim Ingham6297a3a2010-10-20 00:39:53 +0000183 StopReason reason = stop_info_sp->GetStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +0000184
185 switch (reason)
186 {
187 case eStopReasonBreakpoint:
188 {
189 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
Greg Claytonf4124de2012-02-21 00:09:25 +0000190 BreakpointSiteSP this_site = m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue());
Chris Lattner24943d22010-06-08 16:52:24 +0000191 if (!this_site)
192 {
193 m_explains_stop = false;
194 return;
195 }
196
197 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
198 {
199 // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
200 // this is indeed our stop.
201 // If the stack depth has grown, then we've hit our step out breakpoint recursively.
202 // If we are the only breakpoint at that location, then we do explain the stop, and
203 // we'll just continue.
204 // If there was another breakpoint here, then we don't explain the stop, but we won't
205 // mark ourselves Completed, because maybe that breakpoint will continue, and then
206 // we'll finish the "until".
Jim Ingham441e3b92012-03-01 00:50:50 +0000207 bool done;
208 StackID cur_frame_zero_id;
209
210 if (m_stack_id < cur_frame_zero_id)
211 done = true;
212 else
213 done = false;
214
215 if (done)
Chris Lattner24943d22010-06-08 16:52:24 +0000216 {
217 m_stepped_out = true;
218 SetPlanComplete();
219 }
220 else
221 m_should_stop = false;
222
223 if (this_site->GetNumberOfOwners() == 1)
224 m_explains_stop = true;
225 else
226 m_explains_stop = false;
227 return;
228 }
229 else
230 {
231 // Check if we've hit one of our "until" breakpoints.
232 until_collection::iterator pos, end = m_until_points.end();
233 for (pos = m_until_points.begin(); pos != end; pos++)
234 {
235 if (this_site->IsBreakpointAtThisSite ((*pos).second))
236 {
237 // If we're at the right stack depth, then we're done.
Jim Ingham441e3b92012-03-01 00:50:50 +0000238
239 bool done;
240 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
241
242 if (frame_zero_id == m_stack_id)
243 done = true;
244 else if (frame_zero_id < m_stack_id)
245 done = false;
246 else
247 {
248 StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
249
250 // But if we can't even unwind one frame we should just get out of here & stop...
251 if (older_frame_sp)
252 {
253 const SymbolContext &older_context
254 = older_frame_sp->GetSymbolContext(eSymbolContextEverything);
255 SymbolContext stack_context;
256 m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(&stack_context);
257
258 if (older_context == stack_context)
259 done = true;
260 else
261 done = false;
262 }
263 else
264 done = false;
265 }
266
267 if (done)
Chris Lattner24943d22010-06-08 16:52:24 +0000268 SetPlanComplete();
269 else
270 m_should_stop = false;
271
272 // Otherwise we've hit this breakpoint recursively. If we're the
273 // only breakpoint here, then we do explain the stop, and we'll continue.
274 // If not then we should let higher plans handle this stop.
275 if (this_site->GetNumberOfOwners() == 1)
276 m_explains_stop = true;
277 else
278 {
279 m_should_stop = true;
280 m_explains_stop = false;
281 }
282 return;
283 }
284 }
285 }
286 // If we get here we haven't hit any of our breakpoints, so let the higher
287 // plans take care of the stop.
288 m_explains_stop = false;
289 return;
290 }
291 case eStopReasonWatchpoint:
292 case eStopReasonSignal:
293 case eStopReasonException:
Greg Clayton0bce9a22012-12-05 00:16:59 +0000294 case eStopReasonExec:
Chris Lattner24943d22010-06-08 16:52:24 +0000295 m_explains_stop = false;
296 break;
297 default:
298 m_explains_stop = true;
299 break;
300 }
301 }
302}
303
304bool
305ThreadPlanStepUntil::PlanExplainsStop ()
306{
307 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
308 // out will be handled by a child plan.
309 AnalyzeStop();
310 return m_explains_stop;
311}
312
313bool
314ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
315{
316 // If we've told our self in ExplainsStop that we plan to continue, then
317 // do so here. Otherwise, as long as this thread has stopped for a reason,
318 // we will stop.
319
Jim Ingham6297a3a2010-10-20 00:39:53 +0000320 StopInfoSP stop_info_sp = GetPrivateStopReason();
Sean Callananb386d822012-08-09 00:50:26 +0000321 if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
Chris Lattner24943d22010-06-08 16:52:24 +0000322 return false;
323
324 AnalyzeStop();
325 return m_should_stop;
326}
327
328bool
329ThreadPlanStepUntil::StopOthers ()
330{
331 return m_stop_others;
332}
333
334StateType
Jim Ingham745ac7a2010-11-11 19:26:09 +0000335ThreadPlanStepUntil::GetPlanRunState ()
Chris Lattner24943d22010-06-08 16:52:24 +0000336{
337 return eStateRunning;
338}
339
340bool
341ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
342{
343 ThreadPlan::WillResume (resume_state, current_plan);
344 if (current_plan)
345 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000346 TargetSP target_sp (m_thread.CalculateTarget());
347 if (target_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000348 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000349 Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
350 if (return_bp != NULL)
351 return_bp->SetEnabled (true);
352
353 until_collection::iterator pos, end = m_until_points.end();
354 for (pos = m_until_points.begin(); pos != end; pos++)
355 {
356 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
357 if (until_bp != NULL)
358 until_bp->SetEnabled (true);
359 }
Chris Lattner24943d22010-06-08 16:52:24 +0000360 }
361 }
362
363 m_should_stop = true;
364 m_ran_analyze = false;
365 m_explains_stop = false;
366 return true;
367}
368
369bool
370ThreadPlanStepUntil::WillStop ()
371{
Greg Claytonf4124de2012-02-21 00:09:25 +0000372 TargetSP target_sp (m_thread.CalculateTarget());
373 if (target_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000374 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000375 Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
376 if (return_bp != NULL)
377 return_bp->SetEnabled (false);
378
379 until_collection::iterator pos, end = m_until_points.end();
380 for (pos = m_until_points.begin(); pos != end; pos++)
381 {
382 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
383 if (until_bp != NULL)
384 until_bp->SetEnabled (false);
385 }
Chris Lattner24943d22010-06-08 16:52:24 +0000386 }
387 return true;
388}
389
390bool
391ThreadPlanStepUntil::MischiefManaged ()
392{
393
394 // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
395 bool done = false;
396 if (IsPlanComplete())
397 {
Greg Claytone005f2c2010-11-06 01:53:30 +0000398 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000399 if (log)
400 log->Printf("Completed step until plan.");
401
402 Clear();
403 done = true;
404 }
405 if (done)
406 ThreadPlan::MischiefManaged ();
407
408 return done;
409
410}
411