1//===-- ThreadPlanStepThrough.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/ThreadPlanStepThrough.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/lldb-private-log.h"
17#include "lldb/Core/Log.h"
18#include "lldb/Core/Stream.h"
19#include "lldb/Target/DynamicLoader.h"
20#include "lldb/Target/ObjCLanguageRuntime.h"
21#include "lldb/Target/Process.h"
22#include "lldb/Target/RegisterContext.h"
23#include "lldb/Target/Target.h"
24#include "lldb/Breakpoint/Breakpoint.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29//----------------------------------------------------------------------
30// ThreadPlanStepThrough: If the current instruction is a trampoline, step through it
31// If it is the beginning of the prologue of a function, step through that as well.
32// FIXME: At present only handles DYLD trampolines.
33//----------------------------------------------------------------------
34
35ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, StackID &m_stack_id, bool stop_others) :
36    ThreadPlan (ThreadPlan::eKindStepThrough, "Step through trampolines and prologues", thread, eVoteNoOpinion, eVoteNoOpinion),
37    m_start_address (0),
38    m_backstop_bkpt_id (LLDB_INVALID_BREAK_ID),
39    m_backstop_addr(LLDB_INVALID_ADDRESS),
40    m_return_stack_id (m_stack_id),
41    m_stop_others (stop_others)
42{
43
44    LookForPlanToStepThroughFromCurrentPC();
45
46    // If we don't get a valid step through plan, don't bother to set up a backstop.
47    if (m_sub_plan_sp)
48    {
49        m_start_address = GetThread().GetRegisterContext()->GetPC(0);
50
51        // We are going to return back to the concrete frame 1, we might pass by some inlined code that we're in
52        // the middle of by doing this, but it's easier than trying to figure out where the inlined code might return to.
53
54        StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID (m_stack_id);
55
56        if (return_frame_sp)
57        {
58            m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(m_thread.CalculateTarget().get());
59            Breakpoint *return_bp = m_thread.GetProcess()->GetTarget().CreateBreakpoint (m_backstop_addr, true).get();
60            if (return_bp != NULL)
61            {
62                return_bp->SetThreadID(m_thread.GetID());
63                m_backstop_bkpt_id = return_bp->GetID();
64                return_bp->SetBreakpointKind("step-through-backstop");
65            }
66            Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
67            if (log)
68            {
69                log->Printf ("Setting backstop breakpoint %d at address: 0x%" PRIx64, m_backstop_bkpt_id, m_backstop_addr);
70            }
71        }
72    }
73}
74
75ThreadPlanStepThrough::~ThreadPlanStepThrough ()
76{
77    ClearBackstopBreakpoint ();
78}
79
80void
81ThreadPlanStepThrough::DidPush ()
82{
83    if (m_sub_plan_sp)
84        PushPlan(m_sub_plan_sp);
85}
86
87void
88ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC()
89{
90    m_sub_plan_sp = m_thread.GetProcess()->GetDynamicLoader()->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
91    // If that didn't come up with anything, try the ObjC runtime plugin:
92    if (!m_sub_plan_sp.get())
93    {
94        ObjCLanguageRuntime *objc_runtime = m_thread.GetProcess()->GetObjCLanguageRuntime();
95        if (objc_runtime)
96            m_sub_plan_sp = objc_runtime->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
97    }
98
99    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
100    if (log)
101    {
102        lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0);
103        if (m_sub_plan_sp)
104        {
105            StreamString s;
106            m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
107            log->Printf ("Found step through plan from 0x%" PRIx64 ": %s", current_address, s.GetData());
108        }
109        else
110        {
111            log->Printf ("Couldn't find step through plan from address 0x%" PRIx64 ".", current_address);
112        }
113    }
114}
115
116void
117ThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level)
118{
119    if (level == lldb::eDescriptionLevelBrief)
120        s->Printf ("Step through");
121    else
122    {
123        s->PutCString ("Stepping through trampoline code from: ");
124        s->Address(m_start_address, sizeof (addr_t));
125        if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
126        {
127            s->Printf (" with backstop breakpoint id: %d at address: ", m_backstop_bkpt_id);
128            s->Address (m_backstop_addr, sizeof (addr_t));
129        }
130        else
131            s->PutCString (" unable to set a backstop breakpoint.");
132    }
133}
134
135bool
136ThreadPlanStepThrough::ValidatePlan (Stream *error)
137{
138    return m_sub_plan_sp.get() != NULL;
139}
140
141bool
142ThreadPlanStepThrough::DoPlanExplainsStop (Event *event_ptr)
143{
144    // If we have a sub-plan, it will have been asked first if we explain the stop, and
145    // we won't get asked.  The only time we would be the one directly asked this question
146    // is if we hit our backstop breakpoint.
147
148    if (HitOurBackstopBreakpoint())
149        return true;
150    else
151        return false;
152}
153
154bool
155ThreadPlanStepThrough::ShouldStop (Event *event_ptr)
156{
157    // If we've already marked ourselves done, then we're done...
158    if (IsPlanComplete())
159        return true;
160
161    // First, did we hit the backstop breakpoint?
162    if (HitOurBackstopBreakpoint())
163    {
164        SetPlanComplete(false);
165        return true;
166    }
167
168    // If we don't have a sub-plan, then we're also done (can't see how we would ever get here
169    // without a plan, but just in case.
170
171    if (!m_sub_plan_sp)
172    {
173        SetPlanComplete();
174        return true;
175    }
176
177    // If the current sub plan is not done, we don't want to stop.  Actually, we probably won't
178    // ever get here in this state, since we generally won't get asked any questions if out
179    // current sub-plan is not done...
180    if (!m_sub_plan_sp->IsPlanComplete())
181        return false;
182
183    // If our current sub plan failed, then let's just run to our backstop.  If we can't do that then just stop.
184    if (!m_sub_plan_sp->PlanSucceeded())
185    {
186        if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
187        {
188            m_sub_plan_sp.reset();
189            return false;
190        }
191        else
192        {
193            SetPlanComplete(false);
194            return true;
195        }
196    }
197
198    // Next see if there is a specific step through plan at our current pc (these might
199    // chain, for instance stepping through a dylib trampoline to the objc dispatch function...)
200    LookForPlanToStepThroughFromCurrentPC();
201    if (m_sub_plan_sp)
202    {
203        PushPlan (m_sub_plan_sp);
204        return false;
205    }
206    else
207    {
208        SetPlanComplete();
209        return true;
210    }
211}
212
213bool
214ThreadPlanStepThrough::StopOthers ()
215{
216    return m_stop_others;
217}
218
219StateType
220ThreadPlanStepThrough::GetPlanRunState ()
221{
222    return eStateRunning;
223}
224
225bool
226ThreadPlanStepThrough::DoWillResume (StateType resume_state, bool current_plan)
227{
228    return true;
229}
230
231bool
232ThreadPlanStepThrough::WillStop ()
233{
234    return true;
235}
236
237void
238ThreadPlanStepThrough::ClearBackstopBreakpoint ()
239{
240    if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
241    {
242        m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id);
243        m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
244    }
245}
246
247bool
248ThreadPlanStepThrough::MischiefManaged ()
249{
250    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
251
252    if (!IsPlanComplete())
253    {
254        return false;
255    }
256    else
257    {
258        if (log)
259            log->Printf("Completed step through step plan.");
260
261        ClearBackstopBreakpoint ();
262        ThreadPlan::MischiefManaged ();
263        return true;
264    }
265}
266
267bool
268ThreadPlanStepThrough::HitOurBackstopBreakpoint()
269{
270    StopInfoSP stop_info_sp(m_thread.GetStopInfo());
271    if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
272    {
273        break_id_t stop_value = (break_id_t) stop_info_sp->GetValue();
274        BreakpointSiteSP cur_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value);
275        if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id))
276        {
277            StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
278
279            if (cur_frame_zero_id == m_return_stack_id)
280            {
281                Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
282                if (log)
283                    log->PutCString ("ThreadPlanStepThrough hit backstop breakpoint.");
284                return true;
285            }
286        }
287    }
288    return false;
289}
290
291