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 
26 using namespace lldb;
27 using 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 
35 ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, 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_stack_depth (0),
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         m_stack_depth = m_thread.GetStackFrameCount() - 1;
51 
52         // We are going to return back to the concrete frame 1, we might pass by some inlined code that we're in
53         // the middle of by doing this, but it's easier than trying to figure out where the inlined code might return to.
54 
55         StackFrameSP return_frame_sp (m_thread.GetFrameWithConcreteFrameIndex(1));
56 
57         if (return_frame_sp)
58         {
59             m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(&m_thread.GetProcess().GetTarget());
60             Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_backstop_addr, true).get();
61             if (return_bp != NULL)
62             {
63                 return_bp->SetThreadID(m_thread.GetID());
64                 m_backstop_bkpt_id = return_bp->GetID();
65             }
66             LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
67             if (log)
68             {
69                 log->Printf ("Setting backstop breakpoint %d at address: 0x%llx", m_backstop_bkpt_id, m_backstop_addr);
70             }
71         }
72     }
73 }
74 
75 ThreadPlanStepThrough::~ThreadPlanStepThrough ()
76 {
77     if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
78     {
79         m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id);
80         m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
81     }
82 }
83 
84 void
85 ThreadPlanStepThrough::DidPush ()
86 {
87     if (m_sub_plan_sp)
88         PushPlan(m_sub_plan_sp);
89 }
90 
91 void
92 ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC()
93 {
94     m_sub_plan_sp = m_thread.GetProcess().GetDynamicLoader()->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
95     // If that didn't come up with anything, try the ObjC runtime plugin:
96     if (!m_sub_plan_sp.get())
97     {
98         ObjCLanguageRuntime *objc_runtime = m_thread.GetProcess().GetObjCLanguageRuntime();
99         if (objc_runtime)
100             m_sub_plan_sp = objc_runtime->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
101     }
102 
103     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
104     if (log)
105     {
106         lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0);
107         if (m_sub_plan_sp)
108         {
109             StreamString s;
110             m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
111             log->Printf ("Found step through plan from 0x%llx: %s", current_address, s.GetData());
112         }
113         else
114         {
115             log->Printf ("Couldn't find step through plan from address 0x%llx.", current_address);
116         }
117     }
118 }
119 
120 void
121 ThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level)
122 {
123     if (level == lldb::eDescriptionLevelBrief)
124         s->Printf ("Step through");
125     else
126     {
127         s->PutCString ("Stepping through trampoline code from: ");
128         s->Address(m_start_address, sizeof (addr_t));
129         if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
130         {
131             s->Printf (" with backstop breakpoint id: %d at address: ", m_backstop_bkpt_id);
132             s->Address (m_backstop_addr, sizeof (addr_t));
133         }
134         else
135             s->PutCString (" unable to set a backstop breakpoint.");
136     }
137 }
138 
139 bool
140 ThreadPlanStepThrough::ValidatePlan (Stream *error)
141 {
142     return m_sub_plan_sp.get() != NULL;
143 }
144 
145 bool
146 ThreadPlanStepThrough::PlanExplainsStop ()
147 {
148     // If we have a sub-plan, it will have been asked first if we explain the stop, and
149     // we won't get asked.  The only time we would be the one directly asked this question
150     // is if we hit our backstop breakpoint.
151 
152     if (HitOurBackstopBreakpoint())
153         return true;
154     else
155         return false;
156 }
157 
158 bool
159 ThreadPlanStepThrough::ShouldStop (Event *event_ptr)
160 {
161     // If we've already marked ourselves done, then we're done...
162     if (IsPlanComplete())
163         return true;
164 
165     // If we don't have a sub-plan, then we're also done (can't see how we would ever get here
166     // without a plan, but just in case.
167 
168     if (!m_sub_plan_sp)
169     {
170         SetPlanComplete();
171         return true;
172     }
173 
174     // First, did we hit the backstop breakpoint?
175     if (HitOurBackstopBreakpoint())
176     {
177         SetPlanComplete();
178         return true;
179     }
180 
181 
182     // If the current sub plan is not done, we don't want to stop.  Actually, we probably won't
183     // ever get here in this state, since we generally won't get asked any questions if out
184     // current sub-plan is not done...
185     if (!m_sub_plan_sp->IsPlanComplete())
186             return false;
187 
188     // Next see if there is a specific step through plan at our current pc (these might
189     // chain, for instance stepping through a dylib trampoline to the objc dispatch function...)
190     LookForPlanToStepThroughFromCurrentPC();
191     if (m_sub_plan_sp)
192     {
193         PushPlan (m_sub_plan_sp);
194         return false;
195     }
196     else
197     {
198         SetPlanComplete();
199         return true;
200     }
201 }
202 
203 bool
204 ThreadPlanStepThrough::StopOthers ()
205 {
206     return m_stop_others;
207 }
208 
209 StateType
210 ThreadPlanStepThrough::GetPlanRunState ()
211 {
212     return eStateStepping;
213 }
214 
215 bool
216 ThreadPlanStepThrough::WillResume (StateType resume_state, bool current_plan)
217 {
218     ThreadPlan::WillResume(resume_state, current_plan);
219     return true;
220 }
221 
222 bool
223 ThreadPlanStepThrough::WillStop ()
224 {
225     return true;
226 }
227 
228 bool
229 ThreadPlanStepThrough::MischiefManaged ()
230 {
231     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
232 
233     // ShouldStop will call HappyToStopHere, which will set the plan to complete if
234     // we're done.  So we can just check that here.
235 
236     if (!IsPlanComplete())
237     {
238         return false;
239     }
240     else
241     {
242         if (log)
243             log->Printf("Completed step through step plan.");
244         ThreadPlan::MischiefManaged ();
245         if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
246         {
247             m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id);
248             m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
249         }
250         return true;
251     }
252 }
253 
254 bool
255 ThreadPlanStepThrough::HitOurBackstopBreakpoint()
256 {
257     StopInfoSP stop_info_sp(m_thread.GetStopInfo());
258     if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
259     {
260         break_id_t stop_value = (break_id_t) stop_info_sp->GetValue();
261         BreakpointSiteSP cur_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID(stop_value);
262         if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id))
263         {
264             size_t current_stack_depth = m_thread.GetStackFrameCount();
265             if (current_stack_depth == m_stack_depth)
266             {
267                 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
268                 if (log)
269                     log->PutCString ("ThreadPlanStepThrough hit backstop breakpoint.");
270                 return true;
271             }
272         }
273     }
274     return false;
275 }
276 
277