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