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