blob: 8c0748bce33001c17d95506d166be62c2314a877 [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();
66 m_return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
67 Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
68 if (return_bp != NULL)
69 {
70 return_bp->SetThreadID(thread_id);
71 m_return_bp_id = return_bp->GetID();
72 }
73 else
74 {
75 m_return_bp_id = LLDB_INVALID_BREAK_ID;
76 }
77
78 m_stack_depth = m_thread.GetStackFrameCount();
79
80 // Now set breakpoints on all our return addresses:
81 for (int i = 0; i < num_addresses; i++)
82 {
83 Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
84 if (until_bp != NULL)
85 {
86 until_bp->SetThreadID(thread_id);
87 m_until_points[address_list[i]] = until_bp->GetID();
88 }
89 else
90 {
91 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
92 }
93 }
94}
95
96ThreadPlanStepUntil::~ThreadPlanStepUntil ()
97{
98 Clear();
99}
100
101void
102ThreadPlanStepUntil::Clear()
103{
104 Target &target = m_thread.GetProcess().GetTarget();
105 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
106 {
107 target.RemoveBreakpointByID(m_return_bp_id);
108 m_return_bp_id = LLDB_INVALID_BREAK_ID;
109 }
110
111 until_collection::iterator pos, end = m_until_points.end();
112 for (pos = m_until_points.begin(); pos != end; pos++)
113 {
114 target.RemoveBreakpointByID((*pos).second);
115 }
116 m_until_points.clear();
117}
118
119void
120ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
121{
122 if (level == lldb::eDescriptionLevelBrief)
123 {
124 s->Printf ("step until");
125 if (m_stepped_out)
126 s->Printf (" - stepped out");
127 }
128 else
129 {
130 if (m_until_points.size() == 1)
131 s->Printf ("Stepping from address 0x%llx until we reach 0x%llx using breakpoint %d",
132 (uint64_t)m_step_from_insn,
133 (uint64_t) (*m_until_points.begin()).first,
134 (*m_until_points.begin()).second);
135 else
136 {
137 until_collection::iterator pos, end = m_until_points.end();
138 s->Printf ("Stepping from address 0x%llx until we reach one of:",
139 (uint64_t)m_step_from_insn);
140 for (pos = m_until_points.begin(); pos != end; pos++)
141 {
142 s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
143 }
144 }
145 s->Printf(" stepped out address is 0x%lx.", (uint64_t) m_return_addr);
146 }
147}
148
149bool
150ThreadPlanStepUntil::ValidatePlan (Stream *error)
151{
152 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
153 return false;
154 else
155 {
156 until_collection::iterator pos, end = m_until_points.end();
157 for (pos = m_until_points.begin(); pos != end; pos++)
158 {
159 if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
160 return false;
161 }
162 return true;
163 }
164}
165
166void
167ThreadPlanStepUntil::AnalyzeStop()
168{
169 if (m_ran_analyze)
170 return;
171
Greg Clayton643ee732010-08-04 01:40:35 +0000172 StopInfo *stop_info = m_thread.GetStopInfo();
Chris Lattner24943d22010-06-08 16:52:24 +0000173 m_should_stop = true;
174 m_explains_stop = false;
175
Greg Clayton643ee732010-08-04 01:40:35 +0000176 if (stop_info)
Chris Lattner24943d22010-06-08 16:52:24 +0000177 {
Greg Clayton643ee732010-08-04 01:40:35 +0000178 StopReason reason = stop_info->GetStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +0000179
180 switch (reason)
181 {
182 case eStopReasonBreakpoint:
183 {
184 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
Greg Clayton643ee732010-08-04 01:40:35 +0000185 BreakpointSiteSP this_site = m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info->GetValue());
Chris Lattner24943d22010-06-08 16:52:24 +0000186 if (!this_site)
187 {
188 m_explains_stop = false;
189 return;
190 }
191
192 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
193 {
194 // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
195 // this is indeed our stop.
196 // If the stack depth has grown, then we've hit our step out breakpoint recursively.
197 // If we are the only breakpoint at that location, then we do explain the stop, and
198 // we'll just continue.
199 // If there was another breakpoint here, then we don't explain the stop, but we won't
200 // mark ourselves Completed, because maybe that breakpoint will continue, and then
201 // we'll finish the "until".
202 if (m_stack_depth > m_thread.GetStackFrameCount())
203 {
204 m_stepped_out = true;
205 SetPlanComplete();
206 }
207 else
208 m_should_stop = false;
209
210 if (this_site->GetNumberOfOwners() == 1)
211 m_explains_stop = true;
212 else
213 m_explains_stop = false;
214 return;
215 }
216 else
217 {
218 // Check if we've hit one of our "until" breakpoints.
219 until_collection::iterator pos, end = m_until_points.end();
220 for (pos = m_until_points.begin(); pos != end; pos++)
221 {
222 if (this_site->IsBreakpointAtThisSite ((*pos).second))
223 {
224 // If we're at the right stack depth, then we're done.
225 if (m_stack_depth == m_thread.GetStackFrameCount())
226 SetPlanComplete();
227 else
228 m_should_stop = false;
229
230 // Otherwise we've hit this breakpoint recursively. If we're the
231 // only breakpoint here, then we do explain the stop, and we'll continue.
232 // If not then we should let higher plans handle this stop.
233 if (this_site->GetNumberOfOwners() == 1)
234 m_explains_stop = true;
235 else
236 {
237 m_should_stop = true;
238 m_explains_stop = false;
239 }
240 return;
241 }
242 }
243 }
244 // If we get here we haven't hit any of our breakpoints, so let the higher
245 // plans take care of the stop.
246 m_explains_stop = false;
247 return;
248 }
249 case eStopReasonWatchpoint:
250 case eStopReasonSignal:
251 case eStopReasonException:
252 m_explains_stop = false;
253 break;
254 default:
255 m_explains_stop = true;
256 break;
257 }
258 }
259}
260
261bool
262ThreadPlanStepUntil::PlanExplainsStop ()
263{
264 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
265 // out will be handled by a child plan.
266 AnalyzeStop();
267 return m_explains_stop;
268}
269
270bool
271ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
272{
273 // If we've told our self in ExplainsStop that we plan to continue, then
274 // do so here. Otherwise, as long as this thread has stopped for a reason,
275 // we will stop.
276
Greg Clayton643ee732010-08-04 01:40:35 +0000277 StopInfo *stop_info = m_thread.GetStopInfo ();
278 if (stop_info == NULL || stop_info->GetStopReason() == eStopReasonNone)
Chris Lattner24943d22010-06-08 16:52:24 +0000279 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