blob: f54bf46d877b700770ef7aa84c415ebc3ed481d1 [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),
Greg Clayton54e7afa2010-07-09 20:39:50 +000044 m_stack_depth (0),
Chris Lattner24943d22010-06-08 16:52:24 +000045 m_step_from_insn (LLDB_INVALID_ADDRESS),
Chris Lattner24943d22010-06-08 16:52:24 +000046 m_return_bp_id(LLDB_INVALID_BREAK_ID),
Greg Clayton54e7afa2010-07-09 20:39:50 +000047 m_return_addr (LLDB_INVALID_ADDRESS),
Chris Lattner24943d22010-06-08 16:52:24 +000048 m_stepped_out(false),
49 m_should_stop(false),
Chris Lattner24943d22010-06-08 16:52:24 +000050 m_ran_analyze (false),
Greg Clayton54e7afa2010-07-09 20:39:50 +000051 m_explains_stop(false),
52 m_until_points(),
Chris Lattner24943d22010-06-08 16:52:24 +000053 m_stop_others (stop_others)
54{
55
56 SetOkayToDiscard(true);
57 // Stash away our "until" addresses:
58 Target &target = m_thread.GetProcess().GetTarget();
59
Greg Clayton1ebdcc72011-01-21 06:11:58 +000060 StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
61 if (frame_sp)
Chris Lattner24943d22010-06-08 16:52:24 +000062 {
Greg Clayton1ebdcc72011-01-21 06:11:58 +000063 m_step_from_insn = frame_sp->GetStackID().GetPC();
64 lldb::user_id_t thread_id = m_thread.GetID();
Chris Lattner24943d22010-06-08 16:52:24 +000065
Greg Clayton1ebdcc72011-01-21 06:11:58 +000066 // Find the return address and set a breakpoint there:
67 // FIXME - can we do this more securely if we know first_insn?
Chris Lattner24943d22010-06-08 16:52:24 +000068
Greg Clayton1ebdcc72011-01-21 06:11:58 +000069 StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
70 if (return_frame_sp)
Chris Lattner24943d22010-06-08 16:52:24 +000071 {
Greg Clayton1ebdcc72011-01-21 06:11:58 +000072 // TODO: add inline functionality
73 m_return_addr = return_frame_sp->GetStackID().GetPC();
74 Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
75 if (return_bp != NULL)
76 {
77 return_bp->SetThreadID(thread_id);
78 m_return_bp_id = return_bp->GetID();
79 }
Chris Lattner24943d22010-06-08 16:52:24 +000080 }
Greg Clayton1ebdcc72011-01-21 06:11:58 +000081
82 m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
83
84 // Now set breakpoints on all our return addresses:
85 for (int i = 0; i < num_addresses; i++)
Chris Lattner24943d22010-06-08 16:52:24 +000086 {
Greg Clayton1ebdcc72011-01-21 06:11:58 +000087 Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
88 if (until_bp != NULL)
89 {
90 until_bp->SetThreadID(thread_id);
91 m_until_points[address_list[i]] = until_bp->GetID();
92 }
93 else
94 {
95 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
96 }
Chris Lattner24943d22010-06-08 16:52:24 +000097 }
98 }
99}
100
101ThreadPlanStepUntil::~ThreadPlanStepUntil ()
102{
103 Clear();
104}
105
106void
107ThreadPlanStepUntil::Clear()
108{
109 Target &target = m_thread.GetProcess().GetTarget();
110 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
111 {
112 target.RemoveBreakpointByID(m_return_bp_id);
113 m_return_bp_id = LLDB_INVALID_BREAK_ID;
114 }
115
116 until_collection::iterator pos, end = m_until_points.end();
117 for (pos = m_until_points.begin(); pos != end; pos++)
118 {
119 target.RemoveBreakpointByID((*pos).second);
120 }
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)
136 s->Printf ("Stepping from address 0x%llx until we reach 0x%llx using breakpoint %d",
137 (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();
143 s->Printf ("Stepping from address 0x%llx until we reach one of:",
144 (uint64_t)m_step_from_insn);
145 for (pos = m_until_points.begin(); pos != end; pos++)
146 {
147 s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
148 }
149 }
Jason Molenda7e5fa7f2011-09-20 21:44:10 +0000150 s->Printf(" stepped out address is 0x%llx.", (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...
Jim Ingham6297a3a2010-10-20 00:39:53 +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".
207 if (m_stack_depth > m_thread.GetStackFrameCount())
208 {
209 m_stepped_out = true;
210 SetPlanComplete();
211 }
212 else
213 m_should_stop = false;
214
215 if (this_site->GetNumberOfOwners() == 1)
216 m_explains_stop = true;
217 else
218 m_explains_stop = false;
219 return;
220 }
221 else
222 {
223 // Check if we've hit one of our "until" breakpoints.
224 until_collection::iterator pos, end = m_until_points.end();
225 for (pos = m_until_points.begin(); pos != end; pos++)
226 {
227 if (this_site->IsBreakpointAtThisSite ((*pos).second))
228 {
229 // If we're at the right stack depth, then we're done.
230 if (m_stack_depth == m_thread.GetStackFrameCount())
231 SetPlanComplete();
232 else
233 m_should_stop = false;
234
235 // Otherwise we've hit this breakpoint recursively. If we're the
236 // only breakpoint here, then we do explain the stop, and we'll continue.
237 // If not then we should let higher plans handle this stop.
238 if (this_site->GetNumberOfOwners() == 1)
239 m_explains_stop = true;
240 else
241 {
242 m_should_stop = true;
243 m_explains_stop = false;
244 }
245 return;
246 }
247 }
248 }
249 // If we get here we haven't hit any of our breakpoints, so let the higher
250 // plans take care of the stop.
251 m_explains_stop = false;
252 return;
253 }
254 case eStopReasonWatchpoint:
255 case eStopReasonSignal:
256 case eStopReasonException:
257 m_explains_stop = false;
258 break;
259 default:
260 m_explains_stop = true;
261 break;
262 }
263 }
264}
265
266bool
267ThreadPlanStepUntil::PlanExplainsStop ()
268{
269 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
270 // out will be handled by a child plan.
271 AnalyzeStop();
272 return m_explains_stop;
273}
274
275bool
276ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
277{
278 // If we've told our self in ExplainsStop that we plan to continue, then
279 // do so here. Otherwise, as long as this thread has stopped for a reason,
280 // we will stop.
281
Jim Ingham6297a3a2010-10-20 00:39:53 +0000282 StopInfoSP stop_info_sp = GetPrivateStopReason();
283 if (stop_info_sp == NULL || stop_info_sp->GetStopReason() == eStopReasonNone)
Chris Lattner24943d22010-06-08 16:52:24 +0000284 return false;
285
286 AnalyzeStop();
287 return m_should_stop;
288}
289
290bool
291ThreadPlanStepUntil::StopOthers ()
292{
293 return m_stop_others;
294}
295
296StateType
Jim Ingham745ac7a2010-11-11 19:26:09 +0000297ThreadPlanStepUntil::GetPlanRunState ()
Chris Lattner24943d22010-06-08 16:52:24 +0000298{
299 return eStateRunning;
300}
301
302bool
303ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
304{
305 ThreadPlan::WillResume (resume_state, current_plan);
306 if (current_plan)
307 {
308 Target &target = m_thread.GetProcess().GetTarget();
309 Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
310 if (return_bp != NULL)
311 return_bp->SetEnabled (true);
312
313 until_collection::iterator pos, end = m_until_points.end();
314 for (pos = m_until_points.begin(); pos != end; pos++)
315 {
316 Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
317 if (until_bp != NULL)
318 until_bp->SetEnabled (true);
319 }
320 }
321
322 m_should_stop = true;
323 m_ran_analyze = false;
324 m_explains_stop = false;
325 return true;
326}
327
328bool
329ThreadPlanStepUntil::WillStop ()
330{
331 Target &target = m_thread.GetProcess().GetTarget();
332 Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
333 if (return_bp != NULL)
334 return_bp->SetEnabled (false);
335
336 until_collection::iterator pos, end = m_until_points.end();
337 for (pos = m_until_points.begin(); pos != end; pos++)
338 {
339 Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
340 if (until_bp != NULL)
341 until_bp->SetEnabled (false);
342 }
343 return true;
344}
345
346bool
347ThreadPlanStepUntil::MischiefManaged ()
348{
349
350 // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
351 bool done = false;
352 if (IsPlanComplete())
353 {
Greg Claytone005f2c2010-11-06 01:53:30 +0000354 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000355 if (log)
356 log->Printf("Completed step until plan.");
357
358 Clear();
359 done = true;
360 }
361 if (done)
362 ThreadPlan::MischiefManaged ();
363
364 return done;
365
366}
367