ThreadPlanCallFunction.cpp revision 1af4e79959e941568390b867fb14cfedc7d6919f
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// Project includes
16#include "lldb/lldb-private-log.h"
17#include "lldb/Core/Address.h"
18#include "lldb/Core/Log.h"
19#include "lldb/Core/Stream.h"
20#include "lldb/Target/Process.h"
21#include "lldb/Target/RegisterContext.h"
22#include "lldb/Target/Target.h"
23#include "lldb/Target/Thread.h"
24#include "lldb/Target/ThreadPlanRunToAddress.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29//----------------------------------------------------------------------
30// ThreadPlanCallFunction: Plan to call a single function
31//----------------------------------------------------------------------
32
33ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
34                                                Address &function,
35                                                lldb::addr_t arg,
36                                                bool stop_other_threads,
37                                                bool discard_on_error,
38                                                lldb::addr_t *this_arg) :
39    ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
40    m_valid (false),
41    m_stop_other_threads (stop_other_threads),
42    m_arg_addr (arg),
43    m_args (NULL),
44    m_process (thread.GetProcess()),
45    m_thread (thread)
46{
47    SetOkayToDiscard (discard_on_error);
48
49    Process& process = thread.GetProcess();
50    Target& target = process.GetTarget();
51    const ABI *abi = process.GetABI();
52
53    if (!abi)
54        return;
55
56    lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
57
58    SymbolContextList contexts;
59    SymbolContext context;
60    ModuleSP executableModuleSP (target.GetExecutableModule());
61
62    if (!executableModuleSP ||
63        !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
64        return;
65
66    contexts.GetContextAtIndex(0, context);
67
68    m_start_addr = context.symbol->GetValue();
69    lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
70
71    if (!thread.SaveFrameZeroState(m_register_backup))
72        return;
73
74    m_function_addr = function;
75    lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
76
77    if (!abi->PrepareTrivialCall(thread,
78                                 spBelowRedZone,
79                                 FunctionLoadAddr,
80                                 StartLoadAddr,
81                                 m_arg_addr,
82                                 this_arg))
83        return;
84
85    m_valid = true;
86}
87
88ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
89                                                Address &function,
90                                                ValueList &args,
91                                                bool stop_other_threads,
92                                                bool discard_on_error) :
93    ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
94    m_valid (false),
95    m_stop_other_threads (stop_other_threads),
96    m_arg_addr (0),
97    m_args (&args),
98    m_process (thread.GetProcess()),
99    m_thread (thread)
100{
101
102    SetOkayToDiscard (discard_on_error);
103
104    Process& process = thread.GetProcess();
105    Target& target = process.GetTarget();
106    const ABI *abi = process.GetABI();
107
108    if(!abi)
109        return;
110
111    lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
112
113    SymbolContextList contexts;
114    SymbolContext context;
115    ModuleSP executableModuleSP (target.GetExecutableModule());
116
117    if (!executableModuleSP ||
118        !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
119        return;
120
121    contexts.GetContextAtIndex(0, context);
122
123    m_start_addr = context.symbol->GetValue();
124    lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
125
126    if(!thread.SaveFrameZeroState(m_register_backup))
127        return;
128
129    m_function_addr = function;
130    lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
131
132    if (!abi->PrepareNormalCall(thread,
133                                spBelowRedZone,
134                                FunctionLoadAddr,
135                                StartLoadAddr,
136                                *m_args))
137        return;
138
139    m_valid = true;
140}
141
142ThreadPlanCallFunction::~ThreadPlanCallFunction ()
143{
144}
145
146void
147ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
148{
149    if (level == lldb::eDescriptionLevelBrief)
150    {
151        s->Printf("Function call thread plan");
152    }
153    else
154    {
155        if (m_args)
156            s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
157        else
158            s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
159    }
160}
161
162bool
163ThreadPlanCallFunction::ValidatePlan (Stream *error)
164{
165    if (!m_valid)
166        return false;
167
168    return true;
169}
170
171bool
172ThreadPlanCallFunction::PlanExplainsStop ()
173{
174    // If the subplan is running, any crashes are attributable to us.
175
176    return (m_subplan_sp.get() != NULL);
177}
178
179bool
180ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
181{
182    if (PlanExplainsStop())
183    {
184        Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
185
186        if (log)
187        {
188            RegisterContext *reg_ctx = m_thread.GetRegisterContext();
189
190            log->PutCString("Function completed.  Register state was:");
191
192            for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
193                 register_index < num_registers;
194                 ++register_index)
195            {
196                const char *register_name = reg_ctx->GetRegisterName(register_index);
197                uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
198
199                log->Printf("  %s = 0x%llx", register_name, register_value);
200            }
201        }
202
203        m_thread.RestoreSaveFrameZero(m_register_backup);
204        m_thread.ClearStackFrames();
205        SetPlanComplete();
206        return true;
207    }
208    else
209    {
210        return false;
211    }
212}
213
214bool
215ThreadPlanCallFunction::StopOthers ()
216{
217    return m_stop_other_threads;
218}
219
220void
221ThreadPlanCallFunction::SetStopOthers (bool new_value)
222{
223    if (m_subplan_sp)
224    {
225        ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
226        address_plan->SetStopOthers(new_value);
227    }
228    m_stop_other_threads = new_value;
229}
230
231StateType
232ThreadPlanCallFunction::RunState ()
233{
234    return eStateRunning;
235}
236
237void
238ThreadPlanCallFunction::DidPush ()
239{
240    m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
241
242    m_thread.QueueThreadPlan(m_subplan_sp, false);
243
244}
245
246bool
247ThreadPlanCallFunction::WillStop ()
248{
249    return true;
250}
251
252bool
253ThreadPlanCallFunction::MischiefManaged ()
254{
255    if (IsPlanComplete())
256    {
257        Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
258
259        if (log)
260            log->Printf("Completed call function plan.");
261
262        ThreadPlan::MischiefManaged ();
263        return true;
264    }
265    else
266    {
267        return false;
268    }
269}
270