1 //===-- ThreadPlanCallFunction.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/ThreadPlanCallFunction.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 #include "llvm/Support/MachO.h"
16 // Project includes
17 #include "lldb/lldb-private-log.h"
18 #include "lldb/Breakpoint/Breakpoint.h"
19 #include "lldb/Breakpoint/BreakpointLocation.h"
20 #include "lldb/Core/Address.h"
21 #include "lldb/Core/Log.h"
22 #include "lldb/Core/Stream.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/RegisterContext.h"
25 #include "lldb/Target/StopInfo.h"
26 #include "lldb/Target/Target.h"
27 #include "lldb/Target/Thread.h"
28 #include "lldb/Target/ThreadPlanRunToAddress.h"
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 //----------------------------------------------------------------------
34 // ThreadPlanCallFunction: Plan to call a single function
35 //----------------------------------------------------------------------
36 
37 ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
38                                                 Address &function,
39                                                 lldb::addr_t arg,
40                                                 bool stop_other_threads,
41                                                 bool discard_on_error,
42                                                 lldb::addr_t *this_arg) :
43     ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
44     m_valid (false),
45     m_stop_other_threads (stop_other_threads),
46     m_arg_addr (arg),
47     m_args (NULL),
48     m_process (thread.GetProcess()),
49     m_thread (thread)
50 {
51     SetOkayToDiscard (discard_on_error);
52 
53     Process& process = thread.GetProcess();
54     Target& target = process.GetTarget();
55     const ABI *abi = process.GetABI();
56 
57     if (!abi)
58         return;
59 
60     SetBreakpoints();
61 
62     lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
63 
64     SymbolContextList contexts;
65     SymbolContext context;
66     ModuleSP executableModuleSP (target.GetExecutableModule());
67 
68     if (!executableModuleSP ||
69         !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
70         return;
71 
72     contexts.GetContextAtIndex(0, context);
73 
74     m_start_addr = context.symbol->GetValue();
75     lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
76 
77     if (!thread.SaveFrameZeroState(m_register_backup))
78         return;
79 
80     m_function_addr = function;
81     lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
82 
83     if (!abi->PrepareTrivialCall(thread,
84                                  spBelowRedZone,
85                                  FunctionLoadAddr,
86                                  StartLoadAddr,
87                                  m_arg_addr,
88                                  this_arg))
89         return;
90 
91     m_valid = true;
92 }
93 
94 ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
95                                                 Address &function,
96                                                 ValueList &args,
97                                                 bool stop_other_threads,
98                                                 bool discard_on_error) :
99     ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
100     m_valid (false),
101     m_stop_other_threads (stop_other_threads),
102     m_arg_addr (0),
103     m_args (&args),
104     m_process (thread.GetProcess()),
105     m_thread (thread)
106 {
107 
108     SetOkayToDiscard (discard_on_error);
109 
110     Process& process = thread.GetProcess();
111     Target& target = process.GetTarget();
112     const ABI *abi = process.GetABI();
113 
114     if(!abi)
115         return;
116 
117     SetBreakpoints();
118 
119     lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
120 
121     SymbolContextList contexts;
122     SymbolContext context;
123     ModuleSP executableModuleSP (target.GetExecutableModule());
124 
125     if (!executableModuleSP ||
126         !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
127         return;
128 
129     contexts.GetContextAtIndex(0, context);
130 
131     m_start_addr = context.symbol->GetValue();
132     lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
133 
134     if(!thread.SaveFrameZeroState(m_register_backup))
135         return;
136 
137     m_function_addr = function;
138     lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
139 
140     if (!abi->PrepareNormalCall(thread,
141                                 spBelowRedZone,
142                                 FunctionLoadAddr,
143                                 StartLoadAddr,
144                                 *m_args))
145         return;
146 
147     m_valid = true;
148 }
149 
150 ThreadPlanCallFunction::~ThreadPlanCallFunction ()
151 {
152 }
153 
154 void
155 ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
156 {
157     if (level == lldb::eDescriptionLevelBrief)
158     {
159         s->Printf("Function call thread plan");
160     }
161     else
162     {
163         if (m_args)
164             s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
165         else
166             s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
167     }
168 }
169 
170 bool
171 ThreadPlanCallFunction::ValidatePlan (Stream *error)
172 {
173     if (!m_valid)
174         return false;
175 
176     return true;
177 }
178 
179 bool
180 ThreadPlanCallFunction::PlanExplainsStop ()
181 {
182     // If our subplan knows why we stopped, even if it's done (which would forward the question to us)
183     // we answer yes.
184     if(m_subplan_sp.get() != NULL && m_subplan_sp->PlanExplainsStop())
185         return true;
186 
187     // If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
188     if (!OkayToDiscard())
189         return false;
190 
191     // Otherwise, check the case where we stopped for an internal breakpoint, in that case, continue on.
192     // If it is not an internal breakpoint, consult OkayToDiscard.
193     lldb::StopInfoSP stop_info_sp = GetPrivateStopReason();
194 
195     if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
196     {
197         uint64_t break_site_id = stop_info_sp->GetValue();
198         lldb::BreakpointSiteSP bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID(break_site_id);
199         if (bp_site_sp)
200         {
201             uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
202             bool is_internal = true;
203             for (uint32_t i = 0; i < num_owners; i++)
204             {
205                 Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
206                 break_id_t bid = bp.GetID();
207 
208                 // Check if the breakpoint is one of ours.
209 
210                 if (m_cxx_exception_bp_sp.get() &&
211                     bid == m_cxx_exception_bp_sp->GetID())
212                     return true;
213 
214                 if (m_cxx_exception_alloc_bp_sp.get() &&
215                     bid == m_cxx_exception_alloc_bp_sp->GetID())
216                     return true;
217 
218                 if (m_objc_exception_bp_sp.get() &&
219                     bid == m_objc_exception_bp_sp->GetID())
220                     return true;
221 
222                 if (!bp.IsInternal())
223                 {
224                     is_internal = false;
225                     break;
226                 }
227             }
228             if (is_internal)
229                 return false;
230         }
231 
232         return OkayToDiscard();
233     }
234     else
235     {
236         // If the subplan is running, any crashes are attributable to us.
237         return (m_subplan_sp.get() != NULL);
238     }
239 }
240 
241 bool
242 ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
243 {
244     if (PlanExplainsStop())
245     {
246         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
247 
248         if (log)
249         {
250             RegisterContext *reg_ctx = m_thread.GetRegisterContext();
251 
252             log->PutCString("Function completed.  Register state was:");
253 
254             for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
255                  register_index < num_registers;
256                  ++register_index)
257             {
258                 const char *register_name = reg_ctx->GetRegisterName(register_index);
259                 uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
260 
261                 log->Printf("  %s = 0x%llx", register_name, register_value);
262             }
263         }
264 
265         m_thread.RestoreSaveFrameZero(m_register_backup);
266         m_thread.ClearStackFrames();
267         SetPlanComplete();
268 
269         ClearBreakpoints();
270         return true;
271     }
272     else
273     {
274         return false;
275     }
276 }
277 
278 bool
279 ThreadPlanCallFunction::StopOthers ()
280 {
281     return m_stop_other_threads;
282 }
283 
284 void
285 ThreadPlanCallFunction::SetStopOthers (bool new_value)
286 {
287     if (m_subplan_sp)
288     {
289         ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
290         address_plan->SetStopOthers(new_value);
291     }
292     m_stop_other_threads = new_value;
293 }
294 
295 StateType
296 ThreadPlanCallFunction::RunState ()
297 {
298     return eStateRunning;
299 }
300 
301 void
302 ThreadPlanCallFunction::DidPush ()
303 {
304 //#define SINGLE_STEP_EXPRESSIONS
305 
306 #ifndef SINGLE_STEP_EXPRESSIONS
307     m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
308 
309     m_thread.QueueThreadPlan(m_subplan_sp, false);
310 #endif
311 }
312 
313 bool
314 ThreadPlanCallFunction::WillStop ()
315 {
316     return true;
317 }
318 
319 bool
320 ThreadPlanCallFunction::MischiefManaged ()
321 {
322     if (IsPlanComplete())
323     {
324         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
325 
326         if (log)
327             log->Printf("Completed call function plan.");
328 
329         ThreadPlan::MischiefManaged ();
330         return true;
331     }
332     else
333     {
334         return false;
335     }
336 }
337 
338 void
339 ThreadPlanCallFunction::SetBreakpoints ()
340 {
341     Target& target = m_process.GetTarget();
342 
343     ArchSpec arch_spec = target.GetArchitecture();
344 
345     // A temporary fix to set breakpoints at points where exceptions are being
346     // thrown.  This functionality will migrate into the Target.
347     switch (arch_spec.GetCPUType())
348     {
349     default:
350         break;
351     case llvm::MachO::CPUTypeI386:
352         m_cxx_exception_bp_sp = target.CreateBreakpoint (NULL,
353                                                        "__cxa_throw",
354                                                        eFunctionNameTypeBase,
355                                                        true);
356         m_cxx_exception_alloc_bp_sp = target.CreateBreakpoint (NULL,
357                                                              "__cxa_allocate",
358                                                              eFunctionNameTypeBase,
359                                                              true);
360         m_objc_exception_bp_sp = target.CreateBreakpoint (NULL,
361                                                         "objc_exception_throw",
362                                                         eFunctionNameTypeBase,
363                                                         true);
364         break;
365     case llvm::MachO::CPUTypeX86_64:
366         m_cxx_exception_bp_sp = target.CreateBreakpoint (NULL,
367                                                        "__cxa_throw",
368                                                        eFunctionNameTypeBase,
369                                                        true);
370         m_cxx_exception_alloc_bp_sp = target.CreateBreakpoint (NULL,
371                                                              "__cxa_allocate",
372                                                              eFunctionNameTypeBase,
373                                                              true);
374         break;
375     }
376 }
377 
378 void
379 ThreadPlanCallFunction::ClearBreakpoints ()
380 {
381     Target& target = m_process.GetTarget();
382 
383     if (m_cxx_exception_bp_sp.get())
384     {
385         target.RemoveBreakpointByID(m_cxx_exception_bp_sp->GetID());
386         m_cxx_exception_bp_sp.reset();
387     }
388 
389     if (m_cxx_exception_alloc_bp_sp.get())
390     {
391         target.RemoveBreakpointByID(m_cxx_exception_alloc_bp_sp->GetID());
392         m_cxx_exception_bp_sp.reset();
393     }
394 
395     if (m_objc_exception_bp_sp.get())
396     {
397         target.RemoveBreakpointByID(m_objc_exception_bp_sp->GetID());
398         m_cxx_exception_bp_sp.reset();
399     }
400 }
401