blob: b33d600f0ee201a6914b706d81b55fb74ff89001 [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
Sean Callananc98aca62010-11-03 19:36:28187 // Check if the breakpoint is one of ours.
188
189 if (BreakpointsExplainStop())
190 return true;
191
Jim Ingham40d871f2010-10-26 00:27:45192 // If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
193 if (!OkayToDiscard())
194 return false;
195
196 // Otherwise, check the case where we stopped for an internal breakpoint, in that case, continue on.
197 // If it is not an internal breakpoint, consult OkayToDiscard.
198 lldb::StopInfoSP stop_info_sp = GetPrivateStopReason();
Sean Callanan6db73ca2010-11-03 01:37:52199
Jim Ingham40d871f2010-10-26 00:27:45200 if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
201 {
202 uint64_t break_site_id = stop_info_sp->GetValue();
203 lldb::BreakpointSiteSP bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID(break_site_id);
204 if (bp_site_sp)
205 {
206 uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
207 bool is_internal = true;
208 for (uint32_t i = 0; i < num_owners; i++)
209 {
Sean Callanan6db73ca2010-11-03 01:37:52210 Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
Sean Callanan6db73ca2010-11-03 01:37:52211
212 if (!bp.IsInternal())
Jim Ingham40d871f2010-10-26 00:27:45213 {
214 is_internal = false;
215 break;
216 }
217 }
218 if (is_internal)
219 return false;
220 }
221
222 return OkayToDiscard();
223 }
224 else
225 {
226 // If the subplan is running, any crashes are attributable to us.
227 return (m_subplan_sp.get() != NULL);
228 }
Chris Lattner30fdc8d2010-06-08 16:52:24229}
230
231bool
232ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
233{
234 if (PlanExplainsStop())
235 {
Sean Callanan5300d372010-07-31 01:32:05236 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
237
238 if (log)
239 {
240 RegisterContext *reg_ctx = m_thread.GetRegisterContext();
241
242 log->PutCString("Function completed. Register state was:");
243
244 for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
245 register_index < num_registers;
246 ++register_index)
247 {
248 const char *register_name = reg_ctx->GetRegisterName(register_index);
249 uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
250
251 log->Printf(" %s = 0x%llx", register_name, register_value);
252 }
253 }
254
Chris Lattner30fdc8d2010-06-08 16:52:24255 m_thread.RestoreSaveFrameZero(m_register_backup);
256 m_thread.ClearStackFrames();
257 SetPlanComplete();
Sean Callanan6db73ca2010-11-03 01:37:52258
259 ClearBreakpoints();
Chris Lattner30fdc8d2010-06-08 16:52:24260 return true;
261 }
262 else
263 {
264 return false;
265 }
266}
267
268bool
269ThreadPlanCallFunction::StopOthers ()
270{
271 return m_stop_other_threads;
272}
273
274void
275ThreadPlanCallFunction::SetStopOthers (bool new_value)
276{
277 if (m_subplan_sp)
278 {
279 ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
280 address_plan->SetStopOthers(new_value);
281 }
282 m_stop_other_threads = new_value;
283}
284
285StateType
286ThreadPlanCallFunction::RunState ()
287{
288 return eStateRunning;
289}
290
291void
292ThreadPlanCallFunction::DidPush ()
293{
Sean Callananbe3a1b12010-10-26 00:31:56294//#define SINGLE_STEP_EXPRESSIONS
295
296#ifndef SINGLE_STEP_EXPRESSIONS
Chris Lattner30fdc8d2010-06-08 16:52:24297 m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
298
299 m_thread.QueueThreadPlan(m_subplan_sp, false);
Sean Callananbe3a1b12010-10-26 00:31:56300#endif
Chris Lattner30fdc8d2010-06-08 16:52:24301}
302
303bool
304ThreadPlanCallFunction::WillStop ()
305{
306 return true;
307}
308
309bool
310ThreadPlanCallFunction::MischiefManaged ()
311{
312 if (IsPlanComplete())
313 {
314 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
315
316 if (log)
317 log->Printf("Completed call function plan.");
318
319 ThreadPlan::MischiefManaged ();
320 return true;
321 }
322 else
323 {
324 return false;
325 }
326}
Sean Callanan6db73ca2010-11-03 01:37:52327
328void
329ThreadPlanCallFunction::SetBreakpoints ()
330{
331 Target& target = m_process.GetTarget();
332
333 ArchSpec arch_spec = target.GetArchitecture();
334
Sean Callanan6db73ca2010-11-03 01:37:52335 switch (arch_spec.GetCPUType())
336 {
337 default:
338 break;
339 case llvm::MachO::CPUTypeI386:
340 m_cxx_exception_bp_sp = target.CreateBreakpoint (NULL,
341 "__cxa_throw",
342 eFunctionNameTypeBase,
343 true);
344 m_cxx_exception_alloc_bp_sp = target.CreateBreakpoint (NULL,
345 "__cxa_allocate",
346 eFunctionNameTypeBase,
347 true);
348 m_objc_exception_bp_sp = target.CreateBreakpoint (NULL,
349 "objc_exception_throw",
350 eFunctionNameTypeBase,
351 true);
352 break;
353 case llvm::MachO::CPUTypeX86_64:
354 m_cxx_exception_bp_sp = target.CreateBreakpoint (NULL,
355 "__cxa_throw",
356 eFunctionNameTypeBase,
357 true);
358 m_cxx_exception_alloc_bp_sp = target.CreateBreakpoint (NULL,
359 "__cxa_allocate",
360 eFunctionNameTypeBase,
361 true);
362 break;
363 }
364}
365
366void
367ThreadPlanCallFunction::ClearBreakpoints ()
368{
369 Target& target = m_process.GetTarget();
370
371 if (m_cxx_exception_bp_sp.get())
372 {
373 target.RemoveBreakpointByID(m_cxx_exception_bp_sp->GetID());
374 m_cxx_exception_bp_sp.reset();
375 }
376
377 if (m_cxx_exception_alloc_bp_sp.get())
378 {
379 target.RemoveBreakpointByID(m_cxx_exception_alloc_bp_sp->GetID());
380 m_cxx_exception_bp_sp.reset();
381 }
382
383 if (m_objc_exception_bp_sp.get())
384 {
385 target.RemoveBreakpointByID(m_objc_exception_bp_sp->GetID());
386 m_cxx_exception_bp_sp.reset();
387 }
388}
Sean Callananc98aca62010-11-03 19:36:28389
390bool
391ThreadPlanCallFunction::BreakpointsExplainStop()
392{
393 // A temporary fix to set breakpoints at points where exceptions are being
394 // thrown. This functionality will migrate into the Target.
395
396 lldb::StopInfoSP stop_info_sp = GetPrivateStopReason();
397
398 if (!stop_info_sp ||
399 stop_info_sp->GetStopReason() != eStopReasonBreakpoint)
400 return false;
401
402 uint64_t break_site_id = stop_info_sp->GetValue();
403 lldb::BreakpointSiteSP bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID(break_site_id);
404
405 if (!bp_site_sp)
406 return false;
407
408 uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
409
410 bool check_cxx_exception = false;
411 break_id_t cxx_exception_bid;
412
413 bool check_cxx_exception_alloc = false;
414 break_id_t cxx_exception_alloc_bid;
415
416 bool check_objc_exception = false;
417 break_id_t objc_exception_bid;
418
419 if (m_cxx_exception_bp_sp.get())
420 {
421 check_cxx_exception = true;
422 cxx_exception_bid = m_cxx_exception_bp_sp->GetID();
423 }
424
425 if (m_cxx_exception_bp_sp.get())
426 {
427 check_cxx_exception_alloc = true;
428 cxx_exception_alloc_bid = m_cxx_exception_alloc_bp_sp->GetID();
429 }
430
431 if (m_cxx_exception_bp_sp.get())
432 {
433 check_objc_exception = true;
434 objc_exception_bid = m_objc_exception_bp_sp->GetID();
435 }
436
437
438 for (uint32_t i = 0; i < num_owners; i++)
439 {
440 break_id_t bid = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().GetID();
441
442 if ((check_cxx_exception && (bid == cxx_exception_bid)) ||
443 (check_cxx_exception_alloc && (bid == cxx_exception_alloc_bid)) ||
444 (check_objc_exception && (bid == objc_exception_bid)))
445 return true;
446 }
447
448 return false;
449}