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