1 //===-- ThreadPlan.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/lldb-python.h"
11 
12 #include "lldb/Target/ThreadPlan.h"
13 
14 // C Includes
15 // C++ Includes
16 // Other libraries and framework includes
17 // Project includes
18 #include "lldb/Core/Debugger.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Core/State.h"
21 #include "lldb/Target/RegisterContext.h"
22 #include "lldb/Target/Thread.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/Target.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //----------------------------------------------------------------------
30 // ThreadPlan constructor
31 //----------------------------------------------------------------------
32 ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vote stop_vote, Vote run_vote) :
33     m_thread (thread),
34     m_stop_vote (stop_vote),
35     m_run_vote (run_vote),
36     m_kind (kind),
37     m_name (name),
38     m_plan_complete_mutex (Mutex::eMutexTypeRecursive),
39     m_cached_plan_explains_stop (eLazyBoolCalculate),
40     m_plan_complete (false),
41     m_plan_private (false),
42     m_okay_to_discard (true),
43     m_is_master_plan (false),
44     m_plan_succeeded(true)
45 {
46     SetID (GetNextID());
47 }
48 
49 //----------------------------------------------------------------------
50 // Destructor
51 //----------------------------------------------------------------------
52 ThreadPlan::~ThreadPlan()
53 {
54 }
55 
56 bool
57 ThreadPlan::PlanExplainsStop (Event *event_ptr)
58 {
59     if (m_cached_plan_explains_stop == eLazyBoolCalculate)
60     {
61         bool actual_value = DoPlanExplainsStop(event_ptr);
62         m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo;
63         return actual_value;
64     }
65     else
66     {
67         return m_cached_plan_explains_stop == eLazyBoolYes;
68     }
69 }
70 
71 bool
72 ThreadPlan::IsPlanComplete ()
73 {
74     Mutex::Locker locker(m_plan_complete_mutex);
75     return m_plan_complete;
76 }
77 
78 void
79 ThreadPlan::SetPlanComplete (bool success)
80 {
81     Mutex::Locker locker(m_plan_complete_mutex);
82     m_plan_complete = true;
83     m_plan_succeeded = success;
84 }
85 
86 bool
87 ThreadPlan::MischiefManaged ()
88 {
89     Mutex::Locker locker(m_plan_complete_mutex);
90     // Mark the plan is complete, but don't override the success flag.
91     m_plan_complete = true;
92     return true;
93 }
94 
95 Vote
96 ThreadPlan::ShouldReportStop (Event *event_ptr)
97 {
98     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
99 
100     if (m_stop_vote == eVoteNoOpinion)
101     {
102         ThreadPlan *prev_plan = GetPreviousPlan ();
103         if (prev_plan)
104         {
105             Vote prev_vote = prev_plan->ShouldReportStop (event_ptr);
106             if (log)
107                 log->Printf ("ThreadPlan::ShouldReportStop() returning previous thread plan vote: %s",
108                              GetVoteAsCString (prev_vote));
109             return prev_vote;
110         }
111     }
112     if (log)
113         log->Printf ("ThreadPlan::ShouldReportStop() returning vote: %s", GetVoteAsCString (m_stop_vote));
114     return m_stop_vote;
115 }
116 
117 Vote
118 ThreadPlan::ShouldReportRun (Event *event_ptr)
119 {
120     if (m_run_vote == eVoteNoOpinion)
121     {
122         ThreadPlan *prev_plan = GetPreviousPlan ();
123         if (prev_plan)
124             return prev_plan->ShouldReportRun (event_ptr);
125     }
126     return m_run_vote;
127 }
128 
129 bool
130 ThreadPlan::StopOthers ()
131 {
132     ThreadPlan *prev_plan;
133     prev_plan = GetPreviousPlan ();
134     if (prev_plan == NULL)
135         return false;
136     else
137         return prev_plan->StopOthers();
138 }
139 
140 void
141 ThreadPlan::SetStopOthers (bool new_value)
142 {
143 	// SetStopOthers doesn't work up the hierarchy.  You have to set the
144     // explicit ThreadPlan you want to affect.
145 }
146 
147 bool
148 ThreadPlan::WillResume (StateType resume_state, bool current_plan)
149 {
150     m_cached_plan_explains_stop = eLazyBoolCalculate;
151 
152     if (current_plan)
153     {
154         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
155 
156         if (log)
157         {
158             RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
159             assert (reg_ctx);
160             addr_t pc = reg_ctx->GetPC();
161             addr_t sp = reg_ctx->GetSP();
162             addr_t fp = reg_ctx->GetFP();
163             log->Printf("%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "
164                         "plan = '%s', state = %s, stop others = %d",
165                         __FUNCTION__, m_thread.GetIndexID(),
166                         static_cast<void*>(&m_thread), m_thread.GetID(),
167                         static_cast<uint64_t>(pc), static_cast<uint64_t>(sp),
168                         static_cast<uint64_t>(fp), m_name.c_str(),
169                         StateAsCString(resume_state), StopOthers());
170         }
171     }
172     return DoWillResume (resume_state, current_plan);
173 }
174 
175 lldb::user_id_t
176 ThreadPlan::GetNextID()
177 {
178     static uint32_t g_nextPlanID = 0;
179     return ++g_nextPlanID;
180 }
181 
182 void
183 ThreadPlan::DidPush()
184 {
185 }
186 
187 void
188 ThreadPlan::WillPop()
189 {
190 }
191 
192 bool
193 ThreadPlan::OkayToDiscard()
194 {
195     if (!IsMasterPlan())
196         return true;
197     else
198         return m_okay_to_discard;
199 }
200 
201 lldb::StateType
202 ThreadPlan::RunState ()
203 {
204     if (m_tracer_sp && m_tracer_sp->TracingEnabled() && m_tracer_sp->SingleStepEnabled())
205         return eStateStepping;
206     else
207         return GetPlanRunState();
208 }
209 
210 //----------------------------------------------------------------------
211 // ThreadPlanNull
212 //----------------------------------------------------------------------
213 
214 ThreadPlanNull::ThreadPlanNull (Thread &thread) :
215     ThreadPlan (ThreadPlan::eKindNull,
216                 "Null Thread Plan",
217                 thread,
218                 eVoteNoOpinion,
219                 eVoteNoOpinion)
220 {
221 }
222 
223 ThreadPlanNull::~ThreadPlanNull ()
224 {
225 }
226 
227 void
228 ThreadPlanNull::GetDescription (Stream *s,
229                                 lldb::DescriptionLevel level)
230 {
231     s->PutCString("Null thread plan - thread has been destroyed.");
232 }
233 
234 bool
235 ThreadPlanNull::ValidatePlan (Stream *error)
236 {
237 #ifdef LLDB_CONFIGURATION_DEBUG
238     fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
239             __PRETTY_FUNCTION__,
240             m_thread.GetID(),
241             m_thread.GetProtocolID());
242 #else
243     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
244     if (log)
245         log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
246                     __PRETTY_FUNCTION__,
247                     m_thread.GetID(),
248                     m_thread.GetProtocolID());
249 #endif
250     return true;
251 }
252 
253 bool
254 ThreadPlanNull::ShouldStop (Event *event_ptr)
255 {
256 #ifdef LLDB_CONFIGURATION_DEBUG
257     fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
258             __PRETTY_FUNCTION__,
259             m_thread.GetID(),
260             m_thread.GetProtocolID());
261 #else
262     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
263     if (log)
264         log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
265                     __PRETTY_FUNCTION__,
266                     m_thread.GetID(),
267                     m_thread.GetProtocolID());
268 #endif
269     return true;
270 }
271 
272 bool
273 ThreadPlanNull::WillStop ()
274 {
275 #ifdef LLDB_CONFIGURATION_DEBUG
276     fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
277             __PRETTY_FUNCTION__,
278             m_thread.GetID(),
279             m_thread.GetProtocolID());
280 #else
281     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
282     if (log)
283         log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
284                     __PRETTY_FUNCTION__,
285                     m_thread.GetID(),
286                     m_thread.GetProtocolID());
287 #endif
288     return true;
289 }
290 
291 bool
292 ThreadPlanNull::DoPlanExplainsStop (Event *event_ptr)
293 {
294 #ifdef LLDB_CONFIGURATION_DEBUG
295     fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
296             __PRETTY_FUNCTION__,
297             m_thread.GetID(),
298             m_thread.GetProtocolID());
299 #else
300     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
301     if (log)
302         log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
303                    __PRETTY_FUNCTION__,
304                    m_thread.GetID(),
305                    m_thread.GetProtocolID());
306 #endif
307     return true;
308 }
309 
310 // The null plan is never done.
311 bool
312 ThreadPlanNull::MischiefManaged ()
313 {
314     // The null plan is never done.
315 #ifdef LLDB_CONFIGURATION_DEBUG
316     fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
317             __PRETTY_FUNCTION__,
318             m_thread.GetID(),
319             m_thread.GetProtocolID());
320 #else
321     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
322     if (log)
323         log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
324                    __PRETTY_FUNCTION__,
325                    m_thread.GetID(),
326                    m_thread.GetProtocolID());
327 #endif
328     return false;
329 }
330 
331 lldb::StateType
332 ThreadPlanNull::GetPlanRunState ()
333 {
334     // Not sure what to return here.  This is a dead thread.
335 #ifdef LLDB_CONFIGURATION_DEBUG
336     fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
337             __PRETTY_FUNCTION__,
338             m_thread.GetID(),
339             m_thread.GetProtocolID());
340 #else
341     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
342     if (log)
343         log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
344                    __PRETTY_FUNCTION__,
345                    m_thread.GetID(),
346                    m_thread.GetProtocolID());
347 #endif
348     return eStateRunning;
349 }
350