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 //----------------------------------------------------------------------
ThreadPlan(ThreadPlanKind kind,const char * name,Thread & thread,Vote stop_vote,Vote run_vote)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 //----------------------------------------------------------------------
~ThreadPlan()51 ThreadPlan::~ThreadPlan()
52 {
53 }
54
55 bool
PlanExplainsStop(Event * event_ptr)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
IsPlanComplete()71 ThreadPlan::IsPlanComplete ()
72 {
73 Mutex::Locker locker(m_plan_complete_mutex);
74 return m_plan_complete;
75 }
76
77 void
SetPlanComplete(bool success)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
MischiefManaged()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
ShouldReportStop(Event * event_ptr)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
ShouldReportRun(Event * event_ptr)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
StopOthers()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
SetStopOthers(bool new_value)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
WillResume(StateType resume_state,bool current_plan)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
GetNextID()175 ThreadPlan::GetNextID()
176 {
177 static uint32_t g_nextPlanID = 0;
178 return ++g_nextPlanID;
179 }
180
181 void
DidPush()182 ThreadPlan::DidPush()
183 {
184 }
185
186 void
WillPop()187 ThreadPlan::WillPop()
188 {
189 }
190
191 bool
OkayToDiscard()192 ThreadPlan::OkayToDiscard()
193 {
194 if (!IsMasterPlan())
195 return true;
196 else
197 return m_okay_to_discard;
198 }
199
200 lldb::StateType
RunState()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 //----------------------------------------------------------------------
210 // ThreadPlanNull
211 //----------------------------------------------------------------------
212
ThreadPlanNull(Thread & thread)213 ThreadPlanNull::ThreadPlanNull (Thread &thread) :
214 ThreadPlan (ThreadPlan::eKindNull,
215 "Null Thread Plan",
216 thread,
217 eVoteNoOpinion,
218 eVoteNoOpinion)
219 {
220 }
221
~ThreadPlanNull()222 ThreadPlanNull::~ThreadPlanNull ()
223 {
224 }
225
226 void
GetDescription(Stream * s,lldb::DescriptionLevel level)227 ThreadPlanNull::GetDescription (Stream *s,
228 lldb::DescriptionLevel level)
229 {
230 s->PutCString("Null thread plan - thread has been destroyed.");
231 }
232
233 bool
ValidatePlan(Stream * error)234 ThreadPlanNull::ValidatePlan (Stream *error)
235 {
236 #ifdef LLDB_CONFIGURATION_DEBUG
237 fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
238 __PRETTY_FUNCTION__,
239 m_thread.GetID(),
240 m_thread.GetProtocolID());
241 #else
242 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
243 if (log)
244 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
245 __PRETTY_FUNCTION__,
246 m_thread.GetID(),
247 m_thread.GetProtocolID());
248 #endif
249 return true;
250 }
251
252 bool
ShouldStop(Event * event_ptr)253 ThreadPlanNull::ShouldStop (Event *event_ptr)
254 {
255 #ifdef LLDB_CONFIGURATION_DEBUG
256 fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
257 __PRETTY_FUNCTION__,
258 m_thread.GetID(),
259 m_thread.GetProtocolID());
260 #else
261 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
262 if (log)
263 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
264 __PRETTY_FUNCTION__,
265 m_thread.GetID(),
266 m_thread.GetProtocolID());
267 #endif
268 return true;
269 }
270
271 bool
WillStop()272 ThreadPlanNull::WillStop ()
273 {
274 #ifdef LLDB_CONFIGURATION_DEBUG
275 fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
276 __PRETTY_FUNCTION__,
277 m_thread.GetID(),
278 m_thread.GetProtocolID());
279 #else
280 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
281 if (log)
282 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
283 __PRETTY_FUNCTION__,
284 m_thread.GetID(),
285 m_thread.GetProtocolID());
286 #endif
287 return true;
288 }
289
290 bool
DoPlanExplainsStop(Event * event_ptr)291 ThreadPlanNull::DoPlanExplainsStop (Event *event_ptr)
292 {
293 #ifdef LLDB_CONFIGURATION_DEBUG
294 fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
295 __PRETTY_FUNCTION__,
296 m_thread.GetID(),
297 m_thread.GetProtocolID());
298 #else
299 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
300 if (log)
301 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
302 __PRETTY_FUNCTION__,
303 m_thread.GetID(),
304 m_thread.GetProtocolID());
305 #endif
306 return true;
307 }
308
309 // The null plan is never done.
310 bool
MischiefManaged()311 ThreadPlanNull::MischiefManaged ()
312 {
313 // The null plan is never done.
314 #ifdef LLDB_CONFIGURATION_DEBUG
315 fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
316 __PRETTY_FUNCTION__,
317 m_thread.GetID(),
318 m_thread.GetProtocolID());
319 #else
320 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
321 if (log)
322 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
323 __PRETTY_FUNCTION__,
324 m_thread.GetID(),
325 m_thread.GetProtocolID());
326 #endif
327 return false;
328 }
329
330 lldb::StateType
GetPlanRunState()331 ThreadPlanNull::GetPlanRunState ()
332 {
333 // Not sure what to return here. This is a dead thread.
334 #ifdef LLDB_CONFIGURATION_DEBUG
335 fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
336 __PRETTY_FUNCTION__,
337 m_thread.GetID(),
338 m_thread.GetProtocolID());
339 #else
340 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
341 if (log)
342 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
343 __PRETTY_FUNCTION__,
344 m_thread.GetID(),
345 m_thread.GetProtocolID());
346 #endif
347 return eStateRunning;
348 }
349