blob: 1d5f4330754f48ed91f6838d83c5a2a68a4aa110 [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:
Greg Claytonf4124de2012-02-21 00:09:25 +000058 TargetSP target_sp (m_thread.CalculateTarget());
Chris Lattner24943d22010-06-08 16:52:24 +000059
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();
Greg Claytonf4124de2012-02-21 00:09:25 +000074 Breakpoint *return_bp = target_sp->CreateBreakpoint (m_return_addr, true).get();
Greg Clayton1ebdcc72011-01-21 06:11:58 +000075 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 Claytonf4124de2012-02-21 00:09:25 +000087 Breakpoint *until_bp = target_sp->CreateBreakpoint (address_list[i], true).get();
Greg Clayton1ebdcc72011-01-21 06:11:58 +000088 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{
Greg Claytonf4124de2012-02-21 00:09:25 +0000109 TargetSP target_sp (m_thread.CalculateTarget());
110 if (target_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000111 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000112 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
113 {
114 target_sp->RemoveBreakpointByID(m_return_bp_id);
115 m_return_bp_id = LLDB_INVALID_BREAK_ID;
116 }
Chris Lattner24943d22010-06-08 16:52:24 +0000117
Greg Claytonf4124de2012-02-21 00:09:25 +0000118 until_collection::iterator pos, end = m_until_points.end();
119 for (pos = m_until_points.begin(); pos != end; pos++)
120 {
121 target_sp->RemoveBreakpointByID((*pos).second);
122 }
Chris Lattner24943d22010-06-08 16:52:24 +0000123 }
124 m_until_points.clear();
125}
126
127void
128ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
129{
130 if (level == lldb::eDescriptionLevelBrief)
131 {
132 s->Printf ("step until");
133 if (m_stepped_out)
134 s->Printf (" - stepped out");
135 }
136 else
137 {
138 if (m_until_points.size() == 1)
139 s->Printf ("Stepping from address 0x%llx until we reach 0x%llx using breakpoint %d",
140 (uint64_t)m_step_from_insn,
141 (uint64_t) (*m_until_points.begin()).first,
142 (*m_until_points.begin()).second);
143 else
144 {
145 until_collection::iterator pos, end = m_until_points.end();
146 s->Printf ("Stepping from address 0x%llx until we reach one of:",
147 (uint64_t)m_step_from_insn);
148 for (pos = m_until_points.begin(); pos != end; pos++)
149 {
150 s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
151 }
152 }
Jason Molenda7e5fa7f2011-09-20 21:44:10 +0000153 s->Printf(" stepped out address is 0x%llx.", (uint64_t) m_return_addr);
Chris Lattner24943d22010-06-08 16:52:24 +0000154 }
155}
156
157bool
158ThreadPlanStepUntil::ValidatePlan (Stream *error)
159{
160 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
161 return false;
162 else
163 {
164 until_collection::iterator pos, end = m_until_points.end();
165 for (pos = m_until_points.begin(); pos != end; pos++)
166 {
167 if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
168 return false;
169 }
170 return true;
171 }
172}
173
174void
175ThreadPlanStepUntil::AnalyzeStop()
176{
177 if (m_ran_analyze)
178 return;
179
Jim Ingham6297a3a2010-10-20 00:39:53 +0000180 StopInfoSP stop_info_sp = GetPrivateStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +0000181 m_should_stop = true;
182 m_explains_stop = false;
183
Jim Ingham6297a3a2010-10-20 00:39:53 +0000184 if (stop_info_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000185 {
Jim Ingham6297a3a2010-10-20 00:39:53 +0000186 StopReason reason = stop_info_sp->GetStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +0000187
188 switch (reason)
189 {
190 case eStopReasonBreakpoint:
191 {
192 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
Greg Claytonf4124de2012-02-21 00:09:25 +0000193 BreakpointSiteSP this_site = m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue());
Chris Lattner24943d22010-06-08 16:52:24 +0000194 if (!this_site)
195 {
196 m_explains_stop = false;
197 return;
198 }
199
200 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
201 {
202 // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
203 // this is indeed our stop.
204 // If the stack depth has grown, then we've hit our step out breakpoint recursively.
205 // If we are the only breakpoint at that location, then we do explain the stop, and
206 // we'll just continue.
207 // If there was another breakpoint here, then we don't explain the stop, but we won't
208 // mark ourselves Completed, because maybe that breakpoint will continue, and then
209 // we'll finish the "until".
210 if (m_stack_depth > m_thread.GetStackFrameCount())
211 {
212 m_stepped_out = true;
213 SetPlanComplete();
214 }
215 else
216 m_should_stop = false;
217
218 if (this_site->GetNumberOfOwners() == 1)
219 m_explains_stop = true;
220 else
221 m_explains_stop = false;
222 return;
223 }
224 else
225 {
226 // Check if we've hit one of our "until" breakpoints.
227 until_collection::iterator pos, end = m_until_points.end();
228 for (pos = m_until_points.begin(); pos != end; pos++)
229 {
230 if (this_site->IsBreakpointAtThisSite ((*pos).second))
231 {
232 // If we're at the right stack depth, then we're done.
233 if (m_stack_depth == m_thread.GetStackFrameCount())
234 SetPlanComplete();
235 else
236 m_should_stop = false;
237
238 // Otherwise we've hit this breakpoint recursively. If we're the
239 // only breakpoint here, then we do explain the stop, and we'll continue.
240 // If not then we should let higher plans handle this stop.
241 if (this_site->GetNumberOfOwners() == 1)
242 m_explains_stop = true;
243 else
244 {
245 m_should_stop = true;
246 m_explains_stop = false;
247 }
248 return;
249 }
250 }
251 }
252 // If we get here we haven't hit any of our breakpoints, so let the higher
253 // plans take care of the stop.
254 m_explains_stop = false;
255 return;
256 }
257 case eStopReasonWatchpoint:
258 case eStopReasonSignal:
259 case eStopReasonException:
260 m_explains_stop = false;
261 break;
262 default:
263 m_explains_stop = true;
264 break;
265 }
266 }
267}
268
269bool
270ThreadPlanStepUntil::PlanExplainsStop ()
271{
272 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
273 // out will be handled by a child plan.
274 AnalyzeStop();
275 return m_explains_stop;
276}
277
278bool
279ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
280{
281 // If we've told our self in ExplainsStop that we plan to continue, then
282 // do so here. Otherwise, as long as this thread has stopped for a reason,
283 // we will stop.
284
Jim Ingham6297a3a2010-10-20 00:39:53 +0000285 StopInfoSP stop_info_sp = GetPrivateStopReason();
286 if (stop_info_sp == NULL || stop_info_sp->GetStopReason() == eStopReasonNone)
Chris Lattner24943d22010-06-08 16:52:24 +0000287 return false;
288
289 AnalyzeStop();
290 return m_should_stop;
291}
292
293bool
294ThreadPlanStepUntil::StopOthers ()
295{
296 return m_stop_others;
297}
298
299StateType
Jim Ingham745ac7a2010-11-11 19:26:09 +0000300ThreadPlanStepUntil::GetPlanRunState ()
Chris Lattner24943d22010-06-08 16:52:24 +0000301{
302 return eStateRunning;
303}
304
305bool
306ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
307{
308 ThreadPlan::WillResume (resume_state, current_plan);
309 if (current_plan)
310 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000311 TargetSP target_sp (m_thread.CalculateTarget());
312 if (target_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000313 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000314 Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
315 if (return_bp != NULL)
316 return_bp->SetEnabled (true);
317
318 until_collection::iterator pos, end = m_until_points.end();
319 for (pos = m_until_points.begin(); pos != end; pos++)
320 {
321 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
322 if (until_bp != NULL)
323 until_bp->SetEnabled (true);
324 }
Chris Lattner24943d22010-06-08 16:52:24 +0000325 }
326 }
327
328 m_should_stop = true;
329 m_ran_analyze = false;
330 m_explains_stop = false;
331 return true;
332}
333
334bool
335ThreadPlanStepUntil::WillStop ()
336{
Greg Claytonf4124de2012-02-21 00:09:25 +0000337 TargetSP target_sp (m_thread.CalculateTarget());
338 if (target_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000339 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000340 Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
341 if (return_bp != NULL)
342 return_bp->SetEnabled (false);
343
344 until_collection::iterator pos, end = m_until_points.end();
345 for (pos = m_until_points.begin(); pos != end; pos++)
346 {
347 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
348 if (until_bp != NULL)
349 until_bp->SetEnabled (false);
350 }
Chris Lattner24943d22010-06-08 16:52:24 +0000351 }
352 return true;
353}
354
355bool
356ThreadPlanStepUntil::MischiefManaged ()
357{
358
359 // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
360 bool done = false;
361 if (IsPlanComplete())
362 {
Greg Claytone005f2c2010-11-06 01:53:30 +0000363 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000364 if (log)
365 log->Printf("Completed step until plan.");
366
367 Clear();
368 done = true;
369 }
370 if (done)
371 ThreadPlan::MischiefManaged ();
372
373 return done;
374
375}
376