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