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