ThreadPlanCallFunction.cpp revision 94fb5432f10882f8917acb7849abdba7c61277ac
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
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,
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
94ThreadPlanCallFunction::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
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)
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
170bool
171ThreadPlanCallFunction::ValidatePlan (Stream *error)
172{
173    if (!m_valid)
174        return false;
175
176    return true;
177}
178
179bool
180ThreadPlanCallFunction::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    // Check if the breakpoint is one of ours.
188
189    if (BreakpointsExplainStop())
190        return true;
191
192    // 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();
199
200    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            {
210                Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
211
212                if (!bp.IsInternal())
213                {
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    }
229}
230
231bool
232ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
233{
234    if (PlanExplainsStop())
235    {
236        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
255        m_thread.RestoreSaveFrameZero(m_register_backup);
256        m_thread.ClearStackFrames();
257        SetPlanComplete();
258
259        ClearBreakpoints();
260        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{
294//#define SINGLE_STEP_EXPRESSIONS
295
296#ifndef SINGLE_STEP_EXPRESSIONS
297    m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
298
299    m_thread.QueueThreadPlan(m_subplan_sp, false);
300#endif
301}
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}
327
328void
329ThreadPlanCallFunction::SetBreakpoints ()
330{
331    Target& target = m_process.GetTarget();
332
333    ArchSpec arch_spec = target.GetArchitecture();
334
335    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}
389
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}
450