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 LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote); 80 return prev_vote; 81 } 82 } 83 LLDB_LOG(log, "Returning vote: {0}", m_stop_vote); 84 return m_stop_vote; 85 } 86 87 Vote ThreadPlan::ShouldReportRun(Event *event_ptr) { 88 if (m_run_vote == eVoteNoOpinion) { 89 ThreadPlan *prev_plan = GetPreviousPlan(); 90 if (prev_plan) 91 return prev_plan->ShouldReportRun(event_ptr); 92 } 93 return m_run_vote; 94 } 95 96 bool ThreadPlan::StopOthers() { 97 ThreadPlan *prev_plan; 98 prev_plan = GetPreviousPlan(); 99 return (prev_plan == nullptr) ? false : prev_plan->StopOthers(); 100 } 101 102 void ThreadPlan::SetStopOthers(bool new_value) { 103 // SetStopOthers doesn't work up the hierarchy. You have to set the 104 // explicit ThreadPlan you want to affect. 105 } 106 107 bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { 108 m_cached_plan_explains_stop = eLazyBoolCalculate; 109 110 if (current_plan) { 111 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 112 113 if (log) { 114 RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); 115 assert(reg_ctx); 116 addr_t pc = reg_ctx->GetPC(); 117 addr_t sp = reg_ctx->GetSP(); 118 addr_t fp = reg_ctx->GetFP(); 119 log->Printf( 120 "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 121 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " 122 "plan = '%s', state = %s, stop others = %d", 123 __FUNCTION__, m_thread.GetIndexID(), static_cast<void *>(&m_thread), 124 m_thread.GetID(), static_cast<uint64_t>(pc), 125 static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(), 126 StateAsCString(resume_state), StopOthers()); 127 } 128 } 129 return DoWillResume(resume_state, current_plan); 130 } 131 132 lldb::user_id_t ThreadPlan::GetNextID() { 133 static uint32_t g_nextPlanID = 0; 134 return ++g_nextPlanID; 135 } 136 137 void ThreadPlan::DidPush() {} 138 139 void ThreadPlan::WillPop() {} 140 141 bool ThreadPlan::OkayToDiscard() { 142 return IsMasterPlan() ? m_okay_to_discard : true; 143 } 144 145 lldb::StateType ThreadPlan::RunState() { 146 if (m_tracer_sp && m_tracer_sp->TracingEnabled() && 147 m_tracer_sp->SingleStepEnabled()) 148 return eStateStepping; 149 else 150 return GetPlanRunState(); 151 } 152 153 bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { 154 switch (reason) { 155 case eStopReasonWatchpoint: 156 case eStopReasonSignal: 157 case eStopReasonException: 158 case eStopReasonExec: 159 case eStopReasonThreadExiting: 160 case eStopReasonInstrumentation: 161 return true; 162 default: 163 return false; 164 } 165 } 166 167 //---------------------------------------------------------------------- 168 // ThreadPlanNull 169 //---------------------------------------------------------------------- 170 171 ThreadPlanNull::ThreadPlanNull(Thread &thread) 172 : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread, 173 eVoteNoOpinion, eVoteNoOpinion) {} 174 175 ThreadPlanNull::~ThreadPlanNull() = default; 176 177 void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) { 178 s->PutCString("Null thread plan - thread has been destroyed."); 179 } 180 181 bool ThreadPlanNull::ValidatePlan(Stream *error) { 182 #ifdef LLDB_CONFIGURATION_DEBUG 183 fprintf(stderr, 184 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 185 ", ptid = 0x%" PRIx64 ")", 186 LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 187 #else 188 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 189 if (log) 190 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 191 ", ptid = 0x%" PRIx64 ")", 192 LLVM_PRETTY_FUNCTION, m_thread.GetID(), 193 m_thread.GetProtocolID()); 194 #endif 195 return true; 196 } 197 198 bool ThreadPlanNull::ShouldStop(Event *event_ptr) { 199 #ifdef LLDB_CONFIGURATION_DEBUG 200 fprintf(stderr, 201 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 202 ", ptid = 0x%" PRIx64 ")", 203 LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 204 #else 205 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 206 if (log) 207 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 208 ", ptid = 0x%" PRIx64 ")", 209 LLVM_PRETTY_FUNCTION, m_thread.GetID(), 210 m_thread.GetProtocolID()); 211 #endif 212 return true; 213 } 214 215 bool ThreadPlanNull::WillStop() { 216 #ifdef LLDB_CONFIGURATION_DEBUG 217 fprintf(stderr, 218 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 219 ", ptid = 0x%" PRIx64 ")", 220 LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 221 #else 222 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 223 if (log) 224 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 225 ", ptid = 0x%" PRIx64 ")", 226 LLVM_PRETTY_FUNCTION, m_thread.GetID(), 227 m_thread.GetProtocolID()); 228 #endif 229 return true; 230 } 231 232 bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { 233 #ifdef LLDB_CONFIGURATION_DEBUG 234 fprintf(stderr, 235 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 236 ", ptid = 0x%" PRIx64 ")", 237 LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 238 #else 239 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 240 if (log) 241 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 242 ", ptid = 0x%" PRIx64 ")", 243 LLVM_PRETTY_FUNCTION, m_thread.GetID(), 244 m_thread.GetProtocolID()); 245 #endif 246 return true; 247 } 248 249 // The null plan is never done. 250 bool ThreadPlanNull::MischiefManaged() { 251 // The null plan is never done. 252 #ifdef LLDB_CONFIGURATION_DEBUG 253 fprintf(stderr, 254 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 255 ", ptid = 0x%" PRIx64 ")", 256 LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 257 #else 258 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 259 if (log) 260 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 261 ", ptid = 0x%" PRIx64 ")", 262 LLVM_PRETTY_FUNCTION, m_thread.GetID(), 263 m_thread.GetProtocolID()); 264 #endif 265 return false; 266 } 267 268 lldb::StateType ThreadPlanNull::GetPlanRunState() { 269 // Not sure what to return here. This is a dead thread. 270 #ifdef LLDB_CONFIGURATION_DEBUG 271 fprintf(stderr, 272 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 273 ", ptid = 0x%" PRIx64 ")", 274 LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 275 #else 276 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 277 if (log) 278 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 279 ", ptid = 0x%" PRIx64 ")", 280 LLVM_PRETTY_FUNCTION, m_thread.GetID(), 281 m_thread.GetProtocolID()); 282 #endif 283 return eStateRunning; 284 } 285