ThreadPlanStepOut.cpp revision a14755aaab93eaa3e60ae10e75cb5c4bd3244fbb
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/Target/Process.h"
20#include "lldb/Target/RegisterContext.h"
21#include "lldb/Target/StopInfo.h"
22#include "lldb/Target/Target.h"
23
24using namespace lldb;
25using namespace lldb_private;
26
27//----------------------------------------------------------------------
28// ThreadPlanStepOut: Step out of the current frame
29//----------------------------------------------------------------------
30
31ThreadPlanStepOut::ThreadPlanStepOut
32(
33    Thread &thread,
34    SymbolContext *context,
35    bool first_insn,
36    bool stop_others,
37    Vote stop_vote,
38    Vote run_vote,
39    uint32_t frame_idx
40) :
41    ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
42    m_step_from_context (context),
43    m_step_from_insn (LLDB_INVALID_ADDRESS),
44    m_return_bp_id (LLDB_INVALID_BREAK_ID),
45    m_return_addr (LLDB_INVALID_ADDRESS),
46    m_first_insn (first_insn),
47    m_stop_others (stop_others)
48{
49    m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
50
51    // Find the return address and set a breakpoint there:
52    // FIXME - can we do this more securely if we know first_insn?
53
54    StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
55    if (return_frame_sp)
56    {
57        // TODO: check for inlined frames and do the right thing...
58        m_return_addr = return_frame_sp->GetRegisterContext()->GetPC();
59        Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get();
60        if (return_bp != NULL)
61        {
62            return_bp->SetThreadID(m_thread.GetID());
63            m_return_bp_id = return_bp->GetID();
64        }
65    }
66
67    m_stack_depth = m_thread.GetStackFrameCount() - frame_idx;
68}
69
70ThreadPlanStepOut::~ThreadPlanStepOut ()
71{
72    if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
73        m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id);
74}
75
76void
77ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
78{
79    if (level == lldb::eDescriptionLevelBrief)
80        s->Printf ("step out");
81    else
82    {
83        s->Printf ("Stepping out from address 0x%llx to return address 0x%llx using breakpoint site %d",
84                   (uint64_t)m_step_from_insn,
85                   (uint64_t)m_return_addr,
86                   m_return_bp_id);
87    }
88}
89
90bool
91ThreadPlanStepOut::ValidatePlan (Stream *error)
92{
93    if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
94        return false;
95    else
96        return true;
97}
98
99bool
100ThreadPlanStepOut::PlanExplainsStop ()
101{
102    // We don't explain signals or breakpoints (breakpoints that handle stepping in or
103    // out will be handled by a child plan.
104    StopInfoSP stop_info_sp = GetPrivateStopReason();
105    if (stop_info_sp)
106    {
107        StopReason reason = stop_info_sp->GetStopReason();
108        switch (reason)
109        {
110        case eStopReasonBreakpoint:
111        {
112            // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
113            BreakpointSiteSP site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()));
114            if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id))
115            {
116                const uint32_t num_frames = m_thread.GetStackFrameCount();
117                if (m_stack_depth > num_frames)
118                    SetPlanComplete();
119
120                // If there was only one owner, then we're done.  But if we also hit some
121                // user breakpoint on our way out, we should mark ourselves as done, but
122                // also not claim to explain the stop, since it is more important to report
123                // the user breakpoint than the step out completion.
124
125                if (site_sp->GetNumberOfOwners() == 1)
126                    return true;
127
128            }
129            return false;
130        }
131        case eStopReasonWatchpoint:
132        case eStopReasonSignal:
133        case eStopReasonException:
134            return false;
135
136        default:
137            return true;
138        }
139    }
140    return true;
141}
142
143bool
144ThreadPlanStepOut::ShouldStop (Event *event_ptr)
145{
146    if (IsPlanComplete() || m_stack_depth > m_thread.GetStackFrameCount())
147    {
148        SetPlanComplete();
149        return true;
150    }
151    else
152        return false;
153}
154
155bool
156ThreadPlanStepOut::StopOthers ()
157{
158    return m_stop_others;
159}
160
161StateType
162ThreadPlanStepOut::GetPlanRunState ()
163{
164    return eStateRunning;
165}
166
167bool
168ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan)
169{
170    ThreadPlan::WillResume (resume_state, current_plan);
171    if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
172        return false;
173
174    if (current_plan)
175    {
176        Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
177        if (return_bp != NULL)
178            return_bp->SetEnabled (true);
179    }
180    return true;
181}
182
183bool
184ThreadPlanStepOut::WillStop ()
185{
186    Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
187    if (return_bp != NULL)
188        return_bp->SetEnabled (false);
189    return true;
190}
191
192bool
193ThreadPlanStepOut::MischiefManaged ()
194{
195    if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
196    {
197        // If I couldn't set this breakpoint, then I'm just going to jettison myself.
198        return true;
199    }
200    else if (IsPlanComplete())
201    {
202        // Did I reach my breakpoint?  If so I'm done.
203        //
204        // I also check the stack depth, since if we've blown past the breakpoint for some
205        // reason and we're now stopping for some other reason altogether, then we're done
206        // with this step out operation.
207
208        LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
209        if (log)
210            log->Printf("Completed step out plan.");
211        m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_return_bp_id);
212        m_return_bp_id = LLDB_INVALID_BREAK_ID;
213        ThreadPlan::MischiefManaged ();
214        return true;
215    }
216    else
217    {
218        return false;
219    }
220}
221
222