blob: 536efad527cc84583efc771fab9c114becc27aa4 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- ThreadPlanStepOut.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
10#include "lldb/Target/ThreadPlanStepOut.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Breakpoint/Breakpoint.h"
17#include "lldb/lldb-private-log.h"
18#include "lldb/Core/Log.h"
Jim Ingham1586d972011-12-17 01:35:57 +000019#include "lldb/Core/Value.h"
20#include "lldb/Core/ValueObjectConstResult.h"
Greg Clayton49ce8962012-08-29 21:13:06 +000021#include "lldb/Symbol/Block.h"
22#include "lldb/Symbol/Function.h"
23#include "lldb/Symbol/Type.h"
Chris Lattner24943d22010-06-08 16:52:24 +000024#include "lldb/Target/Process.h"
25#include "lldb/Target/RegisterContext.h"
Greg Clayton643ee732010-08-04 01:40:35 +000026#include "lldb/Target/StopInfo.h"
Chris Lattner24943d22010-06-08 16:52:24 +000027#include "lldb/Target/Target.h"
Jim Ingham43d39062011-10-15 00:57:28 +000028#include "lldb/Target/ThreadPlanStepOverRange.h"
Chris Lattner24943d22010-06-08 16:52:24 +000029
30using namespace lldb;
31using namespace lldb_private;
32
33//----------------------------------------------------------------------
34// ThreadPlanStepOut: Step out of the current frame
35//----------------------------------------------------------------------
Chris Lattner24943d22010-06-08 16:52:24 +000036ThreadPlanStepOut::ThreadPlanStepOut
37(
38 Thread &thread,
39 SymbolContext *context,
40 bool first_insn,
41 bool stop_others,
42 Vote stop_vote,
Greg Clayton1ebdcc72011-01-21 06:11:58 +000043 Vote run_vote,
44 uint32_t frame_idx
Chris Lattner24943d22010-06-08 16:52:24 +000045) :
Jim Ingham5a47e8b2010-06-19 04:45:32 +000046 ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
Chris Lattner24943d22010-06-08 16:52:24 +000047 m_step_from_context (context),
48 m_step_from_insn (LLDB_INVALID_ADDRESS),
Benjamin Kramer36a08102010-07-16 12:32:33 +000049 m_return_bp_id (LLDB_INVALID_BREAK_ID),
Chris Lattner24943d22010-06-08 16:52:24 +000050 m_return_addr (LLDB_INVALID_ADDRESS),
51 m_first_insn (first_insn),
Jim Ingham43d39062011-10-15 00:57:28 +000052 m_stop_others (stop_others),
53 m_step_through_inline_plan_sp(),
Jim Ingham1586d972011-12-17 01:35:57 +000054 m_step_out_plan_sp (),
55 m_immediate_step_from_function(NULL)
Jim Ingham43d39062011-10-15 00:57:28 +000056
Chris Lattner24943d22010-06-08 16:52:24 +000057{
58 m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
59
Greg Clayton1ebdcc72011-01-21 06:11:58 +000060 StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
Jim Ingham43d39062011-10-15 00:57:28 +000061 StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (frame_idx));
62
Sean Callanancebfad12012-03-13 16:34:56 +000063 if (!return_frame_sp || !immediate_return_from_sp)
64 return; // we can't do anything here. ValidatePlan() will return false.
65
Jim Ingham441e3b92012-03-01 00:50:50 +000066 m_step_out_to_id = return_frame_sp->GetStackID();
67 m_immediate_step_from_id = immediate_return_from_sp->GetStackID();
68
69 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
Jim Ingham43d39062011-10-15 00:57:28 +000070
71 // If the frame directly below the one we are returning to is inlined, we have to be
72 // a little more careful. It is non-trivial to determine the real "return code address" for
73 // an inlined frame, so we have to work our way to that frame and then step out.
74 if (immediate_return_from_sp && immediate_return_from_sp->IsInlined())
Chris Lattner24943d22010-06-08 16:52:24 +000075 {
Jim Ingham43d39062011-10-15 00:57:28 +000076 if (frame_idx > 0)
77 {
78 // First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second
79 // plan that walks us out of this frame.
Jim Ingham441e3b92012-03-01 00:50:50 +000080 m_step_out_plan_sp.reset (new ThreadPlanStepOut(m_thread,
81 NULL,
82 false,
83 stop_others,
84 eVoteNoOpinion,
85 eVoteNoOpinion,
86 frame_idx - 1));
Jim Ingham43d39062011-10-15 00:57:28 +000087 }
88 else
89 {
90 // If we're already at the inlined frame we're stepping through, then just do that now.
91 QueueInlinedStepPlan(false);
92 }
93
94 }
95 else if (return_frame_sp)
96 {
97 // Find the return address and set a breakpoint there:
98 // FIXME - can we do this more securely if we know first_insn?
99
Greg Claytonf4124de2012-02-21 00:09:25 +0000100 m_return_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(&m_thread.GetProcess()->GetTarget());
Sean Callananf6d5fea2012-07-31 22:19:25 +0000101
102 if (m_return_addr == LLDB_INVALID_ADDRESS)
103 return;
104
Greg Claytonf4124de2012-02-21 00:09:25 +0000105 Breakpoint *return_bp = m_thread.CalculateTarget()->CreateBreakpoint (m_return_addr, true).get();
Chris Lattner24943d22010-06-08 16:52:24 +0000106 if (return_bp != NULL)
107 {
108 return_bp->SetThreadID(m_thread.GetID());
109 m_return_bp_id = return_bp->GetID();
Jim Ingham090f8312013-01-26 02:19:28 +0000110 return_bp->SetBreakpointKind ("step-out");
Chris Lattner24943d22010-06-08 16:52:24 +0000111 }
Jim Ingham1586d972011-12-17 01:35:57 +0000112
113 if (immediate_return_from_sp)
114 {
115 const SymbolContext &sc = immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction);
116 if (sc.function)
117 {
118 m_immediate_step_from_function = sc.function;
119 }
120 }
Chris Lattner24943d22010-06-08 16:52:24 +0000121 }
122
Jim Ingham43d39062011-10-15 00:57:28 +0000123}
124
125void
126ThreadPlanStepOut::DidPush()
127{
128 if (m_step_out_plan_sp)
129 m_thread.QueueThreadPlan(m_step_out_plan_sp, false);
130 else if (m_step_through_inline_plan_sp)
131 m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
Chris Lattner24943d22010-06-08 16:52:24 +0000132}
133
134ThreadPlanStepOut::~ThreadPlanStepOut ()
135{
136 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
Greg Claytonf4124de2012-02-21 00:09:25 +0000137 m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id);
Chris Lattner24943d22010-06-08 16:52:24 +0000138}
139
140void
141ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
142{
143 if (level == lldb::eDescriptionLevelBrief)
144 s->Printf ("step out");
145 else
146 {
Jim Ingham43d39062011-10-15 00:57:28 +0000147 if (m_step_out_plan_sp)
Jim Ingham441e3b92012-03-01 00:50:50 +0000148 s->Printf ("Stepping out to inlined frame so we can walk through it.");
Jim Ingham43d39062011-10-15 00:57:28 +0000149 else if (m_step_through_inline_plan_sp)
150 s->Printf ("Stepping out by stepping through inlined function.");
151 else
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000152 s->Printf ("Stepping out from address 0x%" PRIx64 " to return address 0x%" PRIx64 " using breakpoint site %d",
Jim Ingham43d39062011-10-15 00:57:28 +0000153 (uint64_t)m_step_from_insn,
154 (uint64_t)m_return_addr,
Jim Ingham43d39062011-10-15 00:57:28 +0000155 m_return_bp_id);
Chris Lattner24943d22010-06-08 16:52:24 +0000156 }
157}
158
159bool
160ThreadPlanStepOut::ValidatePlan (Stream *error)
161{
Jim Ingham43d39062011-10-15 00:57:28 +0000162 if (m_step_out_plan_sp)
163 return m_step_out_plan_sp->ValidatePlan (error);
164 else if (m_step_through_inline_plan_sp)
165 return m_step_through_inline_plan_sp->ValidatePlan (error);
166 else if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
167 {
Sean Callananf6d5fea2012-07-31 22:19:25 +0000168 if (error)
169 error->PutCString("Could not create return address breakpoint.");
Chris Lattner24943d22010-06-08 16:52:24 +0000170 return false;
Jim Ingham43d39062011-10-15 00:57:28 +0000171 }
Chris Lattner24943d22010-06-08 16:52:24 +0000172 else
173 return true;
174}
175
176bool
177ThreadPlanStepOut::PlanExplainsStop ()
178{
Jim Ingham43d39062011-10-15 00:57:28 +0000179 // If one of our child plans just finished, then we do explain the stop.
180 if (m_step_out_plan_sp)
181 {
182 if (m_step_out_plan_sp->MischiefManaged())
183 {
184 // If this one is done, then we are all done.
Jim Ingham1586d972011-12-17 01:35:57 +0000185 CalculateReturnValue();
Jim Ingham43d39062011-10-15 00:57:28 +0000186 SetPlanComplete();
187 return true;
188 }
189 else
190 return false;
191 }
192 else if (m_step_through_inline_plan_sp)
193 {
194 if (m_step_through_inline_plan_sp->MischiefManaged())
195 return true;
196 else
197 return false;
198 }
199
Chris Lattner24943d22010-06-08 16:52:24 +0000200 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
201 // out will be handled by a child plan.
Jim Ingham43d39062011-10-15 00:57:28 +0000202
Jim Ingham6297a3a2010-10-20 00:39:53 +0000203 StopInfoSP stop_info_sp = GetPrivateStopReason();
204 if (stop_info_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000205 {
Jim Ingham6297a3a2010-10-20 00:39:53 +0000206 StopReason reason = stop_info_sp->GetStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +0000207 switch (reason)
208 {
Greg Clayton643ee732010-08-04 01:40:35 +0000209 case eStopReasonBreakpoint:
210 {
211 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
Greg Claytonf4124de2012-02-21 00:09:25 +0000212 BreakpointSiteSP site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()));
Greg Clayton643ee732010-08-04 01:40:35 +0000213 if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id))
Chris Lattner24943d22010-06-08 16:52:24 +0000214 {
Jim Ingham441e3b92012-03-01 00:50:50 +0000215 bool done;
216
217 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
218
219 if (m_step_out_to_id == frame_zero_id)
220 done = true;
221 else if (m_step_out_to_id < frame_zero_id)
222 {
223 // Either we stepped past the breakpoint, or the stack ID calculation
224 // was incorrect and we should probably stop.
225 done = true;
226 }
227 else
228 {
229 if (m_immediate_step_from_id < frame_zero_id)
230 done = true;
231 else
232 done = false;
233 }
234
235 if (done)
Jim Ingham1586d972011-12-17 01:35:57 +0000236 {
237 CalculateReturnValue();
Greg Clayton1ebdcc72011-01-21 06:11:58 +0000238 SetPlanComplete();
Jim Ingham1586d972011-12-17 01:35:57 +0000239 }
Greg Clayton1ebdcc72011-01-21 06:11:58 +0000240
Greg Clayton643ee732010-08-04 01:40:35 +0000241 // If there was only one owner, then we're done. But if we also hit some
242 // user breakpoint on our way out, we should mark ourselves as done, but
243 // also not claim to explain the stop, since it is more important to report
244 // the user breakpoint than the step out completion.
Chris Lattner24943d22010-06-08 16:52:24 +0000245
Greg Clayton643ee732010-08-04 01:40:35 +0000246 if (site_sp->GetNumberOfOwners() == 1)
247 return true;
248
Chris Lattner24943d22010-06-08 16:52:24 +0000249 }
Greg Clayton643ee732010-08-04 01:40:35 +0000250 return false;
251 }
252 case eStopReasonWatchpoint:
253 case eStopReasonSignal:
254 case eStopReasonException:
Greg Clayton0bce9a22012-12-05 00:16:59 +0000255 case eStopReasonExec:
Andrew Kaylor278f16e2012-12-20 23:08:03 +0000256 case eStopReasonThreadExiting:
Greg Clayton643ee732010-08-04 01:40:35 +0000257 return false;
258
259 default:
260 return true;
Chris Lattner24943d22010-06-08 16:52:24 +0000261 }
262 }
263 return true;
264}
265
266bool
267ThreadPlanStepOut::ShouldStop (Event *event_ptr)
268{
Jim Ingham43d39062011-10-15 00:57:28 +0000269 if (IsPlanComplete())
Jim Ingham43d39062011-10-15 00:57:28 +0000270 return true;
Jim Ingham441e3b92012-03-01 00:50:50 +0000271
272 bool done;
273
274 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
275 if (frame_zero_id < m_step_out_to_id)
276 done = false;
277 else
278 done = true;
279
280 if (done)
Jim Ingham43d39062011-10-15 00:57:28 +0000281 {
Jim Ingham1586d972011-12-17 01:35:57 +0000282 CalculateReturnValue();
Jim Ingham43d39062011-10-15 00:57:28 +0000283 SetPlanComplete();
284 return true;
285 }
286 else
287 {
288 if (m_step_out_plan_sp)
289 {
290 if (m_step_out_plan_sp->MischiefManaged())
291 {
292 // Now step through the inlined stack we are in:
293 if (QueueInlinedStepPlan(true))
294 {
295 return false;
296 }
297 else
298 {
Jim Ingham1586d972011-12-17 01:35:57 +0000299 CalculateReturnValue();
Jim Ingham43d39062011-10-15 00:57:28 +0000300 SetPlanComplete ();
301 return true;
302 }
303 }
304 else
305 return m_step_out_plan_sp->ShouldStop(event_ptr);
306 }
307 else if (m_step_through_inline_plan_sp)
308 {
309 if (m_step_through_inline_plan_sp->MischiefManaged())
310 {
Jim Ingham1586d972011-12-17 01:35:57 +0000311 // We don't calculate the return value here because we don't know how to.
312 // But in case we had a return value sitting around from our process in
313 // getting here, let's clear it out.
314 m_return_valobj_sp.reset();
Jim Ingham43d39062011-10-15 00:57:28 +0000315 SetPlanComplete();
316 return true;
317 }
318 else
319 return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
320 }
321 else
322 return false;
323 }
Chris Lattner24943d22010-06-08 16:52:24 +0000324}
325
326bool
327ThreadPlanStepOut::StopOthers ()
328{
329 return m_stop_others;
330}
331
332StateType
Jim Ingham745ac7a2010-11-11 19:26:09 +0000333ThreadPlanStepOut::GetPlanRunState ()
Chris Lattner24943d22010-06-08 16:52:24 +0000334{
335 return eStateRunning;
336}
337
338bool
339ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan)
340{
341 ThreadPlan::WillResume (resume_state, current_plan);
Jim Ingham43d39062011-10-15 00:57:28 +0000342 if (m_step_out_plan_sp || m_step_through_inline_plan_sp)
343 return true;
344
Chris Lattner24943d22010-06-08 16:52:24 +0000345 if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
346 return false;
347
348 if (current_plan)
349 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000350 Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
Chris Lattner24943d22010-06-08 16:52:24 +0000351 if (return_bp != NULL)
352 return_bp->SetEnabled (true);
353 }
354 return true;
355}
356
357bool
358ThreadPlanStepOut::WillStop ()
359{
Jim Ingham43d39062011-10-15 00:57:28 +0000360 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
361 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000362 Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
Jim Ingham43d39062011-10-15 00:57:28 +0000363 if (return_bp != NULL)
364 return_bp->SetEnabled (false);
365 }
366
Chris Lattner24943d22010-06-08 16:52:24 +0000367 return true;
368}
369
370bool
371ThreadPlanStepOut::MischiefManaged ()
372{
Jim Ingham43d39062011-10-15 00:57:28 +0000373 if (IsPlanComplete())
Chris Lattner24943d22010-06-08 16:52:24 +0000374 {
375 // Did I reach my breakpoint? If so I'm done.
376 //
377 // I also check the stack depth, since if we've blown past the breakpoint for some
378 // reason and we're now stopping for some other reason altogether, then we're done
379 // with this step out operation.
380
Greg Claytone005f2c2010-11-06 01:53:30 +0000381 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000382 if (log)
383 log->Printf("Completed step out plan.");
Jim Ingham43d39062011-10-15 00:57:28 +0000384 if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
385 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000386 m_thread.CalculateTarget()->RemoveBreakpointByID (m_return_bp_id);
Jim Ingham43d39062011-10-15 00:57:28 +0000387 m_return_bp_id = LLDB_INVALID_BREAK_ID;
388 }
389
Chris Lattner24943d22010-06-08 16:52:24 +0000390 ThreadPlan::MischiefManaged ();
391 return true;
392 }
393 else
394 {
395 return false;
396 }
397}
398
Jim Ingham43d39062011-10-15 00:57:28 +0000399bool
400ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
401{
402 // Now figure out the range of this inlined block, and set up a "step through range"
403 // plan for that. If we've been provided with a context, then use the block in that
404 // context.
405 StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (0));
406 if (!immediate_return_from_sp)
407 return false;
408
409 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
410 if (log)
411 {
412 StreamString s;
413 immediate_return_from_sp->Dump(&s, true, false);
414 log->Printf("Queuing inlined frame to step past: %s.", s.GetData());
415 }
416
417 Block *from_block = immediate_return_from_sp->GetFrameBlock();
418 if (from_block)
419 {
420 Block *inlined_block = from_block->GetContainingInlinedBlock();
421 if (inlined_block)
422 {
423 size_t num_ranges = inlined_block->GetNumRanges();
424 AddressRange inline_range;
425 if (inlined_block->GetRangeAtIndex(0, inline_range))
426 {
427 SymbolContext inlined_sc;
428 inlined_block->CalculateSymbolContext(&inlined_sc);
Jim Inghamc3ba2af2012-07-26 18:23:21 +0000429 inlined_sc.target_sp = GetTarget().shared_from_this();
Jim Ingham43d39062011-10-15 00:57:28 +0000430 RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
431 ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,
432 inline_range,
433 inlined_sc,
434 run_mode);
435 step_through_inline_plan_ptr->SetOkayToDiscard(true);
436 StreamString errors;
437 if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
438 {
439 //FIXME: Log this failure.
440 delete step_through_inline_plan_ptr;
441 return false;
442 }
443
444 for (size_t i = 1; i < num_ranges; i++)
445 {
446 if (inlined_block->GetRangeAtIndex (i, inline_range))
447 step_through_inline_plan_ptr->AddRange (inline_range);
448 }
449 m_step_through_inline_plan_sp.reset (step_through_inline_plan_ptr);
450 if (queue_now)
451 m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false);
452 return true;
453 }
454 }
455 }
456
457 return false;
458}
Jim Ingham1586d972011-12-17 01:35:57 +0000459
460void
461ThreadPlanStepOut::CalculateReturnValue ()
462{
463 if (m_return_valobj_sp)
464 return;
465
466 if (m_immediate_step_from_function != NULL)
467 {
468 Type *return_type = m_immediate_step_from_function->GetType();
469 lldb::clang_type_t return_clang_type = m_immediate_step_from_function->GetReturnClangType();
470 if (return_type && return_clang_type)
471 {
472 ClangASTType ast_type (return_type->GetClangAST(), return_clang_type);
473
Greg Claytonf4124de2012-02-21 00:09:25 +0000474 lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI();
Jim Ingham1586d972011-12-17 01:35:57 +0000475 if (abi_sp)
476 {
477 m_return_valobj_sp = abi_sp->GetReturnValueObject(m_thread, ast_type);
478 }
479 }
480 }
481}
Jim Ingham88e3de22012-05-03 21:19:36 +0000482
483bool
484ThreadPlanStepOut::IsPlanStale()
485{
486 // If we are still lower on the stack than the frame we are returning to, then
487 // there's something for us to do. Otherwise, we're stale.
488
489 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
490 if (frame_zero_id < m_step_out_to_id)
491 return false;
492 else
493 return true;
494}
495