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 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //----------------------------------------------------------------------
30 // ThreadPlanCallFunction: Plan to call a single function
31 //----------------------------------------------------------------------
32 
33 ThreadPlanCallFunction::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 
88 ThreadPlanCallFunction::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 
142 ThreadPlanCallFunction::~ThreadPlanCallFunction ()
143 {
144 }
145 
146 void
147 ThreadPlanCallFunction::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 
162 bool
163 ThreadPlanCallFunction::ValidatePlan (Stream *error)
164 {
165     if (!m_valid)
166         return false;
167 
168     return true;
169 }
170 
171 bool
172 ThreadPlanCallFunction::PlanExplainsStop ()
173 {
174     if (!m_subplan_sp)
175         return false;
176     else
177         return m_subplan_sp->PlanExplainsStop();
178 }
179 
180 bool
181 ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
182 {
183     if (PlanExplainsStop())
184     {
185         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
186 
187         if (log)
188         {
189             RegisterContext *reg_ctx = m_thread.GetRegisterContext();
190 
191             log->PutCString("Function completed.  Register state was:");
192 
193             for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
194                  register_index < num_registers;
195                  ++register_index)
196             {
197                 const char *register_name = reg_ctx->GetRegisterName(register_index);
198                 uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
199 
200                 log->Printf("  %s = 0x%llx", register_name, register_value);
201             }
202         }
203 
204         m_thread.RestoreSaveFrameZero(m_register_backup);
205         m_thread.ClearStackFrames();
206         SetPlanComplete();
207         return true;
208     }
209     else
210     {
211         return false;
212     }
213 }
214 
215 bool
216 ThreadPlanCallFunction::StopOthers ()
217 {
218     return m_stop_other_threads;
219 }
220 
221 void
222 ThreadPlanCallFunction::SetStopOthers (bool new_value)
223 {
224     if (m_subplan_sp)
225     {
226         ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
227         address_plan->SetStopOthers(new_value);
228     }
229     m_stop_other_threads = new_value;
230 }
231 
232 StateType
233 ThreadPlanCallFunction::RunState ()
234 {
235     return eStateRunning;
236 }
237 
238 void
239 ThreadPlanCallFunction::DidPush ()
240 {
241     m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
242 
243     m_thread.QueueThreadPlan(m_subplan_sp, false);
244 
245 }
246 
247 bool
248 ThreadPlanCallFunction::WillStop ()
249 {
250     return true;
251 }
252 
253 bool
254 ThreadPlanCallFunction::MischiefManaged ()
255 {
256     if (IsPlanComplete())
257     {
258         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
259 
260         if (log)
261             log->Printf("Completed call function plan.");
262 
263         ThreadPlan::MischiefManaged ();
264         return true;
265     }
266     else
267     {
268         return false;
269     }
270 }
271