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     ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
39     m_valid(false),
40     m_process(thread.GetProcess()),
41     m_arg_addr (arg),
42     m_args (NULL),
43     m_thread(thread),
44     m_stop_other_threads(stop_other_threads)
45 {
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(&process);
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(&process);
76 
77     if (!abi->PrepareTrivialCall(thread,
78                                  spBelowRedZone,
79                                  FunctionLoadAddr,
80                                  StartLoadAddr,
81                                  m_arg_addr))
82         return;
83 
84     m_valid = true;
85 }
86 
87 ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
88                                                 Address &function,
89                                                 ValueList &args,
90                                                 bool stop_other_threads,
91                                                 bool discard_on_error) :
92     ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
93     m_valid(false),
94     m_process(thread.GetProcess()),
95     m_arg_addr (0),
96     m_args (&args),
97     m_thread(thread),
98     m_stop_other_threads(stop_other_threads)
99 {
100 
101     SetOkayToDiscard (discard_on_error);
102 
103     Process& process = thread.GetProcess();
104     Target& target = process.GetTarget();
105     const ABI *abi = process.GetABI();
106 
107     if(!abi)
108         return;
109 
110     lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
111 
112     SymbolContextList contexts;
113     SymbolContext context;
114     ModuleSP executableModuleSP (target.GetExecutableModule());
115 
116     if (!executableModuleSP ||
117         !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
118         return;
119 
120     contexts.GetContextAtIndex(0, context);
121 
122     m_start_addr = context.symbol->GetValue();
123     lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&process);
124 
125     if(!thread.SaveFrameZeroState(m_register_backup))
126         return;
127 
128     m_function_addr = function;
129     lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&process);
130 
131     if (!abi->PrepareNormalCall(thread,
132                                 spBelowRedZone,
133                                 FunctionLoadAddr,
134                                 StartLoadAddr,
135                                 *m_args))
136         return;
137 
138     m_valid = true;
139 }
140 
141 ThreadPlanCallFunction::~ThreadPlanCallFunction ()
142 {
143 }
144 
145 void
146 ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
147 {
148     if (level == lldb::eDescriptionLevelBrief)
149     {
150         s->Printf("Function call thread plan");
151     }
152     else
153     {
154         if (m_args)
155             s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process), m_arg_addr);
156         else
157             s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process), m_arg_addr);
158     }
159 }
160 
161 bool
162 ThreadPlanCallFunction::ValidatePlan (Stream *error)
163 {
164     if (!m_valid)
165         return false;
166 
167     return true;
168 }
169 
170 bool
171 ThreadPlanCallFunction::PlanExplainsStop ()
172 {
173     if (!m_subplan_sp)
174         return false;
175     else
176         return m_subplan_sp->PlanExplainsStop();
177 }
178 
179 bool
180 ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
181 {
182     if (PlanExplainsStop())
183     {
184         m_thread.RestoreSaveFrameZero(m_register_backup);
185         m_thread.ClearStackFrames();
186         SetPlanComplete();
187         return true;
188     }
189     else
190     {
191         return false;
192     }
193 }
194 
195 bool
196 ThreadPlanCallFunction::StopOthers ()
197 {
198     return m_stop_other_threads;
199 }
200 
201 void
202 ThreadPlanCallFunction::SetStopOthers (bool new_value)
203 {
204     if (m_subplan_sp)
205     {
206         ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
207         address_plan->SetStopOthers(new_value);
208     }
209     m_stop_other_threads = new_value;
210 }
211 
212 StateType
213 ThreadPlanCallFunction::RunState ()
214 {
215     return eStateRunning;
216 }
217 
218 void
219 ThreadPlanCallFunction::DidPush ()
220 {
221     m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
222 
223     m_thread.QueueThreadPlan(m_subplan_sp, false);
224 
225 }
226 
227 bool
228 ThreadPlanCallFunction::WillStop ()
229 {
230     return true;
231 }
232 
233 bool
234 ThreadPlanCallFunction::MischiefManaged ()
235 {
236     if (IsPlanComplete())
237     {
238         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
239 
240         if (log)
241             log->Printf("Completed call function plan.");
242 
243         ThreadPlan::MischiefManaged ();
244         return true;
245     }
246     else
247     {
248         return false;
249     }
250 }
251