1254721Semaste//===-- ThreadPlanStepThrough.cpp -------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste// C Includes
11254721Semaste// C++ Includes
12254721Semaste// Other libraries and framework includes
13254721Semaste// Project includes
14296417Sdim#include "lldb/Target/ThreadPlanStepThrough.h"
15254721Semaste#include "lldb/Core/Log.h"
16254721Semaste#include "lldb/Core/Stream.h"
17254721Semaste#include "lldb/Target/DynamicLoader.h"
18254721Semaste#include "lldb/Target/ObjCLanguageRuntime.h"
19254721Semaste#include "lldb/Target/Process.h"
20254721Semaste#include "lldb/Target/RegisterContext.h"
21254721Semaste#include "lldb/Target/Target.h"
22254721Semaste#include "lldb/Breakpoint/Breakpoint.h"
23254721Semaste
24254721Semasteusing namespace lldb;
25254721Semasteusing namespace lldb_private;
26254721Semaste
27254721Semaste//----------------------------------------------------------------------
28254721Semaste// ThreadPlanStepThrough: If the current instruction is a trampoline, step through it
29254721Semaste// If it is the beginning of the prologue of a function, step through that as well.
30254721Semaste// FIXME: At present only handles DYLD trampolines.
31254721Semaste//----------------------------------------------------------------------
32254721Semaste
33254721SemasteThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, StackID &m_stack_id, bool stop_others) :
34254721Semaste    ThreadPlan (ThreadPlan::eKindStepThrough, "Step through trampolines and prologues", thread, eVoteNoOpinion, eVoteNoOpinion),
35254721Semaste    m_start_address (0),
36254721Semaste    m_backstop_bkpt_id (LLDB_INVALID_BREAK_ID),
37254721Semaste    m_backstop_addr(LLDB_INVALID_ADDRESS),
38254721Semaste    m_return_stack_id (m_stack_id),
39254721Semaste    m_stop_others (stop_others)
40254721Semaste{
41254721Semaste    LookForPlanToStepThroughFromCurrentPC();
42254721Semaste
43254721Semaste    // If we don't get a valid step through plan, don't bother to set up a backstop.
44254721Semaste    if (m_sub_plan_sp)
45254721Semaste    {
46254721Semaste        m_start_address = GetThread().GetRegisterContext()->GetPC(0);
47254721Semaste
48254721Semaste        // We are going to return back to the concrete frame 1, we might pass by some inlined code that we're in
49254721Semaste        // the middle of by doing this, but it's easier than trying to figure out where the inlined code might return to.
50254721Semaste
51254721Semaste        StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID (m_stack_id);
52254721Semaste
53254721Semaste        if (return_frame_sp)
54254721Semaste        {
55254721Semaste            m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(m_thread.CalculateTarget().get());
56258054Semaste            Breakpoint *return_bp = m_thread.GetProcess()->GetTarget().CreateBreakpoint (m_backstop_addr, true, false).get();
57296417Sdim            if (return_bp != nullptr)
58254721Semaste            {
59254721Semaste                return_bp->SetThreadID(m_thread.GetID());
60254721Semaste                m_backstop_bkpt_id = return_bp->GetID();
61254721Semaste                return_bp->SetBreakpointKind("step-through-backstop");
62254721Semaste            }
63254721Semaste            Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
64254721Semaste            if (log)
65254721Semaste            {
66254721Semaste                log->Printf ("Setting backstop breakpoint %d at address: 0x%" PRIx64, m_backstop_bkpt_id, m_backstop_addr);
67254721Semaste            }
68254721Semaste        }
69254721Semaste    }
70254721Semaste}
71254721Semaste
72254721SemasteThreadPlanStepThrough::~ThreadPlanStepThrough ()
73254721Semaste{
74254721Semaste    ClearBackstopBreakpoint ();
75254721Semaste}
76254721Semaste
77254721Semastevoid
78254721SemasteThreadPlanStepThrough::DidPush ()
79254721Semaste{
80254721Semaste    if (m_sub_plan_sp)
81254721Semaste        PushPlan(m_sub_plan_sp);
82254721Semaste}
83254721Semaste
84254721Semastevoid
85254721SemasteThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC()
86254721Semaste{
87280031Sdim    DynamicLoader *loader = m_thread.GetProcess()->GetDynamicLoader();
88280031Sdim    if (loader)
89280031Sdim        m_sub_plan_sp = loader->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
90280031Sdim
91254721Semaste    // If that didn't come up with anything, try the ObjC runtime plugin:
92254721Semaste    if (!m_sub_plan_sp.get())
93254721Semaste    {
94254721Semaste        ObjCLanguageRuntime *objc_runtime = m_thread.GetProcess()->GetObjCLanguageRuntime();
95254721Semaste        if (objc_runtime)
96254721Semaste            m_sub_plan_sp = objc_runtime->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
97254721Semaste    }
98254721Semaste
99254721Semaste    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
100254721Semaste    if (log)
101254721Semaste    {
102254721Semaste        lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0);
103254721Semaste        if (m_sub_plan_sp)
104254721Semaste        {
105254721Semaste            StreamString s;
106254721Semaste            m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
107254721Semaste            log->Printf ("Found step through plan from 0x%" PRIx64 ": %s", current_address, s.GetData());
108254721Semaste        }
109254721Semaste        else
110254721Semaste        {
111254721Semaste            log->Printf ("Couldn't find step through plan from address 0x%" PRIx64 ".", current_address);
112254721Semaste        }
113254721Semaste    }
114254721Semaste}
115254721Semaste
116254721Semastevoid
117254721SemasteThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level)
118254721Semaste{
119254721Semaste    if (level == lldb::eDescriptionLevelBrief)
120254721Semaste        s->Printf ("Step through");
121254721Semaste    else
122254721Semaste    {
123254721Semaste        s->PutCString ("Stepping through trampoline code from: ");
124254721Semaste        s->Address(m_start_address, sizeof (addr_t));
125254721Semaste        if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
126254721Semaste        {
127254721Semaste            s->Printf (" with backstop breakpoint id: %d at address: ", m_backstop_bkpt_id);
128254721Semaste            s->Address (m_backstop_addr, sizeof (addr_t));
129254721Semaste        }
130254721Semaste        else
131254721Semaste            s->PutCString (" unable to set a backstop breakpoint.");
132254721Semaste    }
133254721Semaste}
134254721Semaste
135254721Semastebool
136254721SemasteThreadPlanStepThrough::ValidatePlan (Stream *error)
137254721Semaste{
138296417Sdim    return m_sub_plan_sp.get() != nullptr;
139254721Semaste}
140254721Semaste
141254721Semastebool
142254721SemasteThreadPlanStepThrough::DoPlanExplainsStop (Event *event_ptr)
143254721Semaste{
144254721Semaste    // If we have a sub-plan, it will have been asked first if we explain the stop, and
145254721Semaste    // we won't get asked.  The only time we would be the one directly asked this question
146254721Semaste    // is if we hit our backstop breakpoint.
147254721Semaste
148296417Sdim    return HitOurBackstopBreakpoint();
149254721Semaste}
150254721Semaste
151254721Semastebool
152254721SemasteThreadPlanStepThrough::ShouldStop (Event *event_ptr)
153254721Semaste{
154254721Semaste    // If we've already marked ourselves done, then we're done...
155254721Semaste    if (IsPlanComplete())
156254721Semaste        return true;
157254721Semaste
158254721Semaste    // First, did we hit the backstop breakpoint?
159254721Semaste    if (HitOurBackstopBreakpoint())
160254721Semaste    {
161262528Semaste        SetPlanComplete(true);
162254721Semaste        return true;
163254721Semaste    }
164254721Semaste
165254721Semaste    // If we don't have a sub-plan, then we're also done (can't see how we would ever get here
166254721Semaste    // without a plan, but just in case.
167254721Semaste
168254721Semaste    if (!m_sub_plan_sp)
169254721Semaste    {
170254721Semaste        SetPlanComplete();
171254721Semaste        return true;
172254721Semaste    }
173254721Semaste
174254721Semaste    // If the current sub plan is not done, we don't want to stop.  Actually, we probably won't
175254721Semaste    // ever get here in this state, since we generally won't get asked any questions if out
176254721Semaste    // current sub-plan is not done...
177254721Semaste    if (!m_sub_plan_sp->IsPlanComplete())
178254721Semaste        return false;
179254721Semaste
180254721Semaste    // If our current sub plan failed, then let's just run to our backstop.  If we can't do that then just stop.
181254721Semaste    if (!m_sub_plan_sp->PlanSucceeded())
182254721Semaste    {
183254721Semaste        if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
184254721Semaste        {
185254721Semaste            m_sub_plan_sp.reset();
186254721Semaste            return false;
187254721Semaste        }
188254721Semaste        else
189254721Semaste        {
190254721Semaste            SetPlanComplete(false);
191254721Semaste            return true;
192254721Semaste        }
193254721Semaste    }
194254721Semaste
195254721Semaste    // Next see if there is a specific step through plan at our current pc (these might
196254721Semaste    // chain, for instance stepping through a dylib trampoline to the objc dispatch function...)
197254721Semaste    LookForPlanToStepThroughFromCurrentPC();
198254721Semaste    if (m_sub_plan_sp)
199254721Semaste    {
200254721Semaste        PushPlan (m_sub_plan_sp);
201254721Semaste        return false;
202254721Semaste    }
203254721Semaste    else
204254721Semaste    {
205254721Semaste        SetPlanComplete();
206254721Semaste        return true;
207254721Semaste    }
208254721Semaste}
209254721Semaste
210254721Semastebool
211254721SemasteThreadPlanStepThrough::StopOthers ()
212254721Semaste{
213254721Semaste    return m_stop_others;
214254721Semaste}
215254721Semaste
216254721SemasteStateType
217254721SemasteThreadPlanStepThrough::GetPlanRunState ()
218254721Semaste{
219254721Semaste    return eStateRunning;
220254721Semaste}
221254721Semaste
222254721Semastebool
223254721SemasteThreadPlanStepThrough::DoWillResume (StateType resume_state, bool current_plan)
224254721Semaste{
225254721Semaste    return true;
226254721Semaste}
227254721Semaste
228254721Semastebool
229254721SemasteThreadPlanStepThrough::WillStop ()
230254721Semaste{
231254721Semaste    return true;
232254721Semaste}
233254721Semaste
234254721Semastevoid
235254721SemasteThreadPlanStepThrough::ClearBackstopBreakpoint ()
236254721Semaste{
237254721Semaste    if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
238254721Semaste    {
239254721Semaste        m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id);
240254721Semaste        m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
241254721Semaste    }
242254721Semaste}
243254721Semaste
244254721Semastebool
245254721SemasteThreadPlanStepThrough::MischiefManaged ()
246254721Semaste{
247254721Semaste    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
248254721Semaste
249254721Semaste    if (!IsPlanComplete())
250254721Semaste    {
251254721Semaste        return false;
252254721Semaste    }
253254721Semaste    else
254254721Semaste    {
255254721Semaste        if (log)
256254721Semaste            log->Printf("Completed step through step plan.");
257254721Semaste
258254721Semaste        ClearBackstopBreakpoint ();
259254721Semaste        ThreadPlan::MischiefManaged ();
260254721Semaste        return true;
261254721Semaste    }
262254721Semaste}
263254721Semaste
264254721Semastebool
265254721SemasteThreadPlanStepThrough::HitOurBackstopBreakpoint()
266254721Semaste{
267254721Semaste    StopInfoSP stop_info_sp(m_thread.GetStopInfo());
268254721Semaste    if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
269254721Semaste    {
270254721Semaste        break_id_t stop_value = (break_id_t) stop_info_sp->GetValue();
271254721Semaste        BreakpointSiteSP cur_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value);
272254721Semaste        if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id))
273254721Semaste        {
274254721Semaste            StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
275254721Semaste
276254721Semaste            if (cur_frame_zero_id == m_return_stack_id)
277254721Semaste            {
278254721Semaste                Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
279254721Semaste                if (log)
280254721Semaste                    log->PutCString ("ThreadPlanStepThrough hit backstop breakpoint.");
281254721Semaste                return true;
282254721Semaste            }
283254721Semaste        }
284254721Semaste    }
285254721Semaste    return false;
286254721Semaste}
287