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