ThreadPlanStepOut.cpp revision f4124deeb9532044a38c0774ced872f2709347da
1//===-- 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"
19#include "lldb/Core/Value.h"
20#include "lldb/Core/ValueObjectConstResult.h"
21#include "lldb/Target/Process.h"
22#include "lldb/Target/RegisterContext.h"
23#include "lldb/Target/StopInfo.h"
24#include "lldb/Target/Target.h"
25#include "lldb/Target/ThreadPlanStepOverRange.h"
26
27using namespace lldb;
28using namespace lldb_private;
29
30//----------------------------------------------------------------------
31// ThreadPlanStepOut: Step out of the current frame
32//----------------------------------------------------------------------
33
34ThreadPlanStepOut::ThreadPlanStepOut
35(
36    Thread &thread,
37    SymbolContext *context,
38    bool first_insn,
39    bool stop_others,
40    Vote stop_vote,
41    Vote run_vote,
42    uint32_t frame_idx
43) :
44    ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
45    m_step_from_context (context),
46    m_step_from_insn (LLDB_INVALID_ADDRESS),
47    m_return_bp_id (LLDB_INVALID_BREAK_ID),
48    m_return_addr (LLDB_INVALID_ADDRESS),
49    m_first_insn (first_insn),
50    m_stop_others (stop_others),
51    m_step_through_inline_plan_sp(),
52    m_step_out_plan_sp (),
53    m_immediate_step_from_function(NULL)
54
55{
56    m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
57
58    StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
59    StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (frame_idx));
60
61    m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
62
63    // If the frame directly below the one we are returning to is inlined, we have to be
64    // a little more careful.  It is non-trivial to determine the real "return code address" for
65    // an inlined frame, so we have to work our way to that frame and then step out.
66    if (immediate_return_from_sp && immediate_return_from_sp->IsInlined())
67    {
68        if (frame_idx > 0)
69        {
70            // First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second
71            // plan that walks us out of this frame.
72            m_step_out_plan_sp.reset (new ThreadPlanStepOut(m_thread, NULL, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, frame_idx - 1));
73            m_step_out_plan_sp->SetOkayToDiscard(true);
74        }
75        else
76        {
77            // If we're already at the inlined frame we're stepping through, then just do that now.
78            QueueInlinedStepPlan(false);
79        }
80
81    }
82    else if (return_frame_sp)
83    {
84        // Find the return address and set a breakpoint there:
85        // FIXME - can we do this more securely if we know first_insn?
86
87        m_return_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(&m_thread.GetProcess()->GetTarget());
88        Breakpoint *return_bp = m_thread.CalculateTarget()->CreateBreakpoint (m_return_addr, true).get();
89        if (return_bp != NULL)
90        {
91            return_bp->SetThreadID(m_thread.GetID());
92            m_return_bp_id = return_bp->GetID();
93        }
94
95        if (immediate_return_from_sp)
96        {
97            const SymbolContext &sc = immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction);
98            if (sc.function)
99            {
100                m_immediate_step_from_function = sc.function;
101            }
102        }
103    }
104
105}
106
107void
108ThreadPlanStepOut::DidPush()
109{
110    if (m_step_out_plan_sp)
111        m_thread.QueueThreadPlan(m_step_out_plan_sp, false);
112    else if (m_step_through_inline_plan_sp)
113        m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
114}
115
116ThreadPlanStepOut::~ThreadPlanStepOut ()
117{
118    if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
119        m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id);
120}
121
122void
123ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
124{
125    if (level == lldb::eDescriptionLevelBrief)
126        s->Printf ("step out");
127    else
128    {
129        if (m_step_out_plan_sp)
130            s->Printf ("Stepping out to inlined frame at depth: %d so we can walk through it.", m_stack_depth);
131        else if (m_step_through_inline_plan_sp)
132            s->Printf ("Stepping out by stepping through inlined function.");
133        else
134            s->Printf ("Stepping out from address 0x%llx to return address 0x%llx at depth: %d using breakpoint site %d",
135                       (uint64_t)m_step_from_insn,
136                       (uint64_t)m_return_addr,
137                       m_stack_depth,
138                       m_return_bp_id);
139    }
140}
141
142bool
143ThreadPlanStepOut::ValidatePlan (Stream *error)
144{
145    if (m_step_out_plan_sp)
146        return m_step_out_plan_sp->ValidatePlan (error);
147    else if (m_step_through_inline_plan_sp)
148        return m_step_through_inline_plan_sp->ValidatePlan (error);
149    else if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
150    {
151        error->PutCString("Could not create return address breakpoint.");
152        return false;
153    }
154    else
155        return true;
156}
157
158bool
159ThreadPlanStepOut::PlanExplainsStop ()
160{
161    // If one of our child plans just finished, then we do explain the stop.
162    if (m_step_out_plan_sp)
163    {
164        if (m_step_out_plan_sp->MischiefManaged())
165        {
166            // If this one is done, then we are all done.
167            CalculateReturnValue();
168            SetPlanComplete();
169            return true;
170        }
171        else
172            return false;
173    }
174    else if (m_step_through_inline_plan_sp)
175    {
176        if (m_step_through_inline_plan_sp->MischiefManaged())
177            return true;
178        else
179            return false;
180    }
181
182    // We don't explain signals or breakpoints (breakpoints that handle stepping in or
183    // out will be handled by a child plan.
184
185    StopInfoSP stop_info_sp = GetPrivateStopReason();
186    if (stop_info_sp)
187    {
188        StopReason reason = stop_info_sp->GetStopReason();
189        switch (reason)
190        {
191        case eStopReasonBreakpoint:
192        {
193            // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
194            BreakpointSiteSP site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()));
195            if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id))
196            {
197                const uint32_t num_frames = m_thread.GetStackFrameCount();
198                if (m_stack_depth > num_frames)
199                {
200                    CalculateReturnValue();
201                    SetPlanComplete();
202                }
203
204                // If there was only one owner, then we're done.  But if we also hit some
205                // user breakpoint on our way out, we should mark ourselves as done, but
206                // also not claim to explain the stop, since it is more important to report
207                // the user breakpoint than the step out completion.
208
209                if (site_sp->GetNumberOfOwners() == 1)
210                    return true;
211
212            }
213            return false;
214        }
215        case eStopReasonWatchpoint:
216        case eStopReasonSignal:
217        case eStopReasonException:
218            return false;
219
220        default:
221            return true;
222        }
223    }
224    return true;
225}
226
227bool
228ThreadPlanStepOut::ShouldStop (Event *event_ptr)
229{
230        if (IsPlanComplete())
231        {
232            return true;
233        }
234        else if (m_stack_depth > m_thread.GetStackFrameCount())
235        {
236            CalculateReturnValue();
237            SetPlanComplete();
238            return true;
239        }
240        else
241        {
242            if (m_step_out_plan_sp)
243            {
244                if (m_step_out_plan_sp->MischiefManaged())
245                {
246                    // Now step through the inlined stack we are in:
247                    if (QueueInlinedStepPlan(true))
248                    {
249                        return false;
250                    }
251                    else
252                    {
253                        CalculateReturnValue();
254                        SetPlanComplete ();
255                        return true;
256                    }
257                }
258                else
259                    return m_step_out_plan_sp->ShouldStop(event_ptr);
260            }
261            else if (m_step_through_inline_plan_sp)
262            {
263                if (m_step_through_inline_plan_sp->MischiefManaged())
264                {
265                    // We don't calculate the return value here because we don't know how to.
266                    // But in case we had a return value sitting around from our process in
267                    // getting here, let's clear it out.
268                    m_return_valobj_sp.reset();
269                    SetPlanComplete();
270                    return true;
271                }
272                else
273                    return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
274            }
275            else
276                return false;
277        }
278}
279
280bool
281ThreadPlanStepOut::StopOthers ()
282{
283    return m_stop_others;
284}
285
286StateType
287ThreadPlanStepOut::GetPlanRunState ()
288{
289    return eStateRunning;
290}
291
292bool
293ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan)
294{
295    ThreadPlan::WillResume (resume_state, current_plan);
296    if (m_step_out_plan_sp || m_step_through_inline_plan_sp)
297        return true;
298
299    if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
300        return false;
301
302    if (current_plan)
303    {
304        Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
305        if (return_bp != NULL)
306            return_bp->SetEnabled (true);
307    }
308    return true;
309}
310
311bool
312ThreadPlanStepOut::WillStop ()
313{
314    if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
315    {
316        Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
317        if (return_bp != NULL)
318            return_bp->SetEnabled (false);
319    }
320
321    return true;
322}
323
324bool
325ThreadPlanStepOut::MischiefManaged ()
326{
327    if (IsPlanComplete())
328    {
329        // Did I reach my breakpoint?  If so I'm done.
330        //
331        // I also check the stack depth, since if we've blown past the breakpoint for some
332        // reason and we're now stopping for some other reason altogether, then we're done
333        // with this step out operation.
334
335        LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
336        if (log)
337            log->Printf("Completed step out plan.");
338        if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
339        {
340            m_thread.CalculateTarget()->RemoveBreakpointByID (m_return_bp_id);
341            m_return_bp_id = LLDB_INVALID_BREAK_ID;
342        }
343
344        ThreadPlan::MischiefManaged ();
345        return true;
346    }
347    else
348    {
349        return false;
350    }
351}
352
353bool
354ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
355{
356    // Now figure out the range of this inlined block, and set up a "step through range"
357    // plan for that.  If we've been provided with a context, then use the block in that
358    // context.
359    StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (0));
360    if (!immediate_return_from_sp)
361        return false;
362
363    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
364    if (log)
365    {
366        StreamString s;
367        immediate_return_from_sp->Dump(&s, true, false);
368        log->Printf("Queuing inlined frame to step past: %s.", s.GetData());
369    }
370
371    Block *from_block = immediate_return_from_sp->GetFrameBlock();
372    if (from_block)
373    {
374        Block *inlined_block = from_block->GetContainingInlinedBlock();
375        if (inlined_block)
376        {
377            size_t num_ranges = inlined_block->GetNumRanges();
378            AddressRange inline_range;
379            if (inlined_block->GetRangeAtIndex(0, inline_range))
380            {
381                SymbolContext inlined_sc;
382                inlined_block->CalculateSymbolContext(&inlined_sc);
383                RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
384                ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,
385                                                                                                    inline_range,
386                                                                                                    inlined_sc,
387                                                                                                    run_mode);
388                step_through_inline_plan_ptr->SetOkayToDiscard(true);
389                StreamString errors;
390                if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
391                {
392                    //FIXME: Log this failure.
393                    delete step_through_inline_plan_ptr;
394                    return false;
395                }
396
397                for (size_t i = 1; i < num_ranges; i++)
398                {
399                    if (inlined_block->GetRangeAtIndex (i, inline_range))
400                        step_through_inline_plan_ptr->AddRange (inline_range);
401                }
402                m_step_through_inline_plan_sp.reset (step_through_inline_plan_ptr);
403                if (queue_now)
404                    m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false);
405                return true;
406            }
407        }
408    }
409
410    return false;
411}
412
413void
414ThreadPlanStepOut::CalculateReturnValue ()
415{
416    if (m_return_valobj_sp)
417        return;
418
419    if (m_immediate_step_from_function != NULL)
420    {
421        Type *return_type = m_immediate_step_from_function->GetType();
422        lldb::clang_type_t return_clang_type = m_immediate_step_from_function->GetReturnClangType();
423        if (return_type && return_clang_type)
424        {
425            ClangASTType ast_type (return_type->GetClangAST(), return_clang_type);
426
427            lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI();
428            if (abi_sp)
429            {
430                m_return_valobj_sp = abi_sp->GetReturnValueObject(m_thread, ast_type);
431            }
432        }
433    }
434}
435