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