blob: 86cdd4875c9b5034bd2f18548fcf71f7bcac2966 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:241//===-- 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
Sean Callanan6db73ca2010-11-03 01:37:5215#include "llvm/Support/MachO.h"
Chris Lattner30fdc8d2010-06-08 16:52:2416// Project includes
17#include "lldb/lldb-private-log.h"
Jim Ingham40d871f2010-10-26 00:27:4518#include "lldb/Breakpoint/Breakpoint.h"
19#include "lldb/Breakpoint/BreakpointLocation.h"
Chris Lattner30fdc8d2010-06-08 16:52:2420#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"
Jim Ingham40d871f2010-10-26 00:27:4525#include "lldb/Target/StopInfo.h"
Chris Lattner30fdc8d2010-06-08 16:52:2426#include "lldb/Target/Target.h"
27#include "lldb/Target/Thread.h"
28#include "lldb/Target/ThreadPlanRunToAddress.h"
29
30using namespace lldb;
31using namespace lldb_private;
32
33//----------------------------------------------------------------------
34// ThreadPlanCallFunction: Plan to call a single function
35//----------------------------------------------------------------------
36
37ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
38 Address &function,
39 lldb::addr_t arg,
40 bool stop_other_threads,
Sean Callananfc55f5d2010-09-21 00:44:1241 bool discard_on_error,
42 lldb::addr_t *this_arg) :
Jim Inghamb01e742a2010-06-19 04:45:3243 ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
Benjamin Kramer1ee0d4f2010-07-16 12:32:3344 m_valid (false),
45 m_stop_other_threads (stop_other_threads),
Chris Lattner30fdc8d2010-06-08 16:52:2446 m_arg_addr (arg),
47 m_args (NULL),
Benjamin Kramer1ee0d4f2010-07-16 12:32:3348 m_process (thread.GetProcess()),
49 m_thread (thread)
Chris Lattner30fdc8d2010-06-08 16:52:2450{
Chris Lattner30fdc8d2010-06-08 16:52:2451 SetOkayToDiscard (discard_on_error);
52
53 Process& process = thread.GetProcess();
54 Target& target = process.GetTarget();
55 const ABI *abi = process.GetABI();
Sean Callanan6db73ca2010-11-03 01:37:5256
Chris Lattner30fdc8d2010-06-08 16:52:2457 if (!abi)
58 return;
Sean Callanan6db73ca2010-11-03 01:37:5259
60 SetBreakpoints();
61
Chris Lattner30fdc8d2010-06-08 16:52:2462 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();
Greg Claytonf5e56de2010-09-14 23:36:4075 lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
Chris Lattner30fdc8d2010-06-08 16:52:2476
77 if (!thread.SaveFrameZeroState(m_register_backup))
78 return;
79
80 m_function_addr = function;
Greg Claytonf5e56de2010-09-14 23:36:4081 lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
Chris Lattner30fdc8d2010-06-08 16:52:2482
83 if (!abi->PrepareTrivialCall(thread,
84 spBelowRedZone,
85 FunctionLoadAddr,
86 StartLoadAddr,
Sean Callananfc55f5d2010-09-21 00:44:1287 m_arg_addr,
88 this_arg))
Chris Lattner30fdc8d2010-06-08 16:52:2489 return;
90
91 m_valid = true;
92}
93
94ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
95 Address &function,
96 ValueList &args,
97 bool stop_other_threads,
98 bool discard_on_error) :
Jim Inghamb01e742a2010-06-19 04:45:3299 ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
Benjamin Kramer1ee0d4f2010-07-16 12:32:33100 m_valid (false),
101 m_stop_other_threads (stop_other_threads),
Chris Lattner30fdc8d2010-06-08 16:52:24102 m_arg_addr (0),
103 m_args (&args),
Benjamin Kramer1ee0d4f2010-07-16 12:32:33104 m_process (thread.GetProcess()),
105 m_thread (thread)
Chris Lattner30fdc8d2010-06-08 16:52:24106{
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
Sean Callanan6db73ca2010-11-03 01:37:52117 SetBreakpoints();
118
Chris Lattner30fdc8d2010-06-08 16:52:24119 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();
Greg Claytonf5e56de2010-09-14 23:36:40132 lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
Chris Lattner30fdc8d2010-06-08 16:52:24133
134 if(!thread.SaveFrameZeroState(m_register_backup))
135 return;
136
137 m_function_addr = function;
Greg Claytonf5e56de2010-09-14 23:36:40138 lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
Chris Lattner30fdc8d2010-06-08 16:52:24139
140 if (!abi->PrepareNormalCall(thread,
141 spBelowRedZone,
142 FunctionLoadAddr,
143 StartLoadAddr,
144 *m_args))
145 return;
146
147 m_valid = true;
148}
149
150ThreadPlanCallFunction::~ThreadPlanCallFunction ()
151{
152}
153
154void
155ThreadPlanCallFunction::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)
Greg Claytonf5e56de2010-09-14 23:36:40164 s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
Chris Lattner30fdc8d2010-06-08 16:52:24165 else
Greg Claytonf5e56de2010-09-14 23:36:40166 s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
Chris Lattner30fdc8d2010-06-08 16:52:24167 }
168}
169
170bool
171ThreadPlanCallFunction::ValidatePlan (Stream *error)
172{
173 if (!m_valid)
174 return false;
175
176 return true;
177}
178
179bool
180ThreadPlanCallFunction::PlanExplainsStop ()
Sean Callanan6db73ca2010-11-03 01:37:52181{
Jim Ingham40d871f2010-10-26 00:27:45182 // 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;
Sean Callanan3e6fedc2010-10-19 22:24:06186
Jim Ingham40d871f2010-10-26 00:27:45187 // 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();
Sean Callanan6db73ca2010-11-03 01:37:52194
Jim Ingham40d871f2010-10-26 00:27:45195 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 {
Sean Callanan6db73ca2010-11-03 01:37:52205 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())
Jim Ingham40d871f2010-10-26 00:27:45223 {
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 }
Chris Lattner30fdc8d2010-06-08 16:52:24239}
240
241bool
242ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
243{
244 if (PlanExplainsStop())
245 {
Sean Callanan5300d372010-07-31 01:32:05246 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
Chris Lattner30fdc8d2010-06-08 16:52:24265 m_thread.RestoreSaveFrameZero(m_register_backup);
266 m_thread.ClearStackFrames();
267 SetPlanComplete();
Sean Callanan6db73ca2010-11-03 01:37:52268
269 ClearBreakpoints();
Chris Lattner30fdc8d2010-06-08 16:52:24270 return true;
271 }
272 else
273 {
274 return false;
275 }
276}
277
278bool
279ThreadPlanCallFunction::StopOthers ()
280{
281 return m_stop_other_threads;
282}
283
284void
285ThreadPlanCallFunction::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
295StateType
296ThreadPlanCallFunction::RunState ()
297{
298 return eStateRunning;
299}
300
301void
302ThreadPlanCallFunction::DidPush ()
303{
Sean Callananbe3a1b12010-10-26 00:31:56304//#define SINGLE_STEP_EXPRESSIONS
305
306#ifndef SINGLE_STEP_EXPRESSIONS
Chris Lattner30fdc8d2010-06-08 16:52:24307 m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
308
309 m_thread.QueueThreadPlan(m_subplan_sp, false);
Sean Callananbe3a1b12010-10-26 00:31:56310#endif
Chris Lattner30fdc8d2010-06-08 16:52:24311}
312
313bool
314ThreadPlanCallFunction::WillStop ()
315{
316 return true;
317}
318
319bool
320ThreadPlanCallFunction::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}
Sean Callanan6db73ca2010-11-03 01:37:52337
338void
339ThreadPlanCallFunction::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
378void
379ThreadPlanCallFunction::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}