1 //===-- ThreadPlan.cpp ----------------------------------------------------===// 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 // ThreadPlan constructor 22 ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, 23 Vote stop_vote, Vote run_vote) 24 : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), 25 m_stop_vote(stop_vote), m_run_vote(run_vote), 26 m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), 27 m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(), 28 m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), 29 m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), 30 m_plan_succeeded(true) { 31 SetID(GetNextID()); 32 } 33 34 // Destructor 35 ThreadPlan::~ThreadPlan() = default; 36 37 Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); } 38 39 const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); } 40 41 Thread &ThreadPlan::GetThread() { 42 if (m_thread) 43 return *m_thread; 44 45 ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid); 46 m_thread = thread_sp.get(); 47 return *m_thread; 48 } 49 50 bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { 51 if (m_cached_plan_explains_stop == eLazyBoolCalculate) { 52 bool actual_value = DoPlanExplainsStop(event_ptr); 53 m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo; 54 return actual_value; 55 } else { 56 return m_cached_plan_explains_stop == eLazyBoolYes; 57 } 58 } 59 60 bool ThreadPlan::IsPlanComplete() { 61 std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 62 return m_plan_complete; 63 } 64 65 void ThreadPlan::SetPlanComplete(bool success) { 66 std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 67 m_plan_complete = true; 68 m_plan_succeeded = success; 69 } 70 71 bool ThreadPlan::MischiefManaged() { 72 std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); 73 // Mark the plan is complete, but don't override the success flag. 74 m_plan_complete = true; 75 return true; 76 } 77 78 Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { 79 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 80 81 if (m_stop_vote == eVoteNoOpinion) { 82 ThreadPlan *prev_plan = GetPreviousPlan(); 83 if (prev_plan) { 84 Vote prev_vote = prev_plan->ShouldReportStop(event_ptr); 85 LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote); 86 return prev_vote; 87 } 88 } 89 LLDB_LOG(log, "Returning vote: {0}", 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 explicit 110 // 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 = GetThread().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 LLDB_LOGF( 126 log, 127 "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 128 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " 129 "plan = '%s', state = %s, stop others = %d", 130 __FUNCTION__, GetThread().GetIndexID(), 131 static_cast<void *>(&GetThread()), m_tid, static_cast<uint64_t>(pc), 132 static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(), 133 StateAsCString(resume_state), StopOthers()); 134 } 135 } 136 bool success = DoWillResume(resume_state, current_plan); 137 m_thread = nullptr; // We don't cache the thread pointer over resumes. This 138 // Thread might go away, and another Thread represent 139 // the same underlying object on a later stop. 140 return success; 141 } 142 143 lldb::user_id_t ThreadPlan::GetNextID() { 144 static uint32_t g_nextPlanID = 0; 145 return ++g_nextPlanID; 146 } 147 148 void ThreadPlan::DidPush() {} 149 150 void ThreadPlan::WillPop() {} 151 152 bool ThreadPlan::OkayToDiscard() { 153 return IsMasterPlan() ? m_okay_to_discard : true; 154 } 155 156 lldb::StateType ThreadPlan::RunState() { 157 if (m_tracer_sp && m_tracer_sp->TracingEnabled() && 158 m_tracer_sp->SingleStepEnabled()) 159 return eStateStepping; 160 else 161 return GetPlanRunState(); 162 } 163 164 bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { 165 switch (reason) { 166 case eStopReasonWatchpoint: 167 case eStopReasonSignal: 168 case eStopReasonException: 169 case eStopReasonExec: 170 case eStopReasonThreadExiting: 171 case eStopReasonInstrumentation: 172 return true; 173 default: 174 return false; 175 } 176 } 177 178 // ThreadPlanNull 179 180 ThreadPlanNull::ThreadPlanNull(Thread &thread) 181 : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread, 182 eVoteNoOpinion, eVoteNoOpinion) {} 183 184 ThreadPlanNull::~ThreadPlanNull() = default; 185 186 void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) { 187 s->PutCString("Null thread plan - thread has been destroyed."); 188 } 189 190 bool ThreadPlanNull::ValidatePlan(Stream *error) { 191 #ifdef LLDB_CONFIGURATION_DEBUG 192 fprintf(stderr, 193 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 194 ", ptid = 0x%" PRIx64 ")", 195 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 196 #else 197 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 198 if (log) 199 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 200 ", ptid = 0x%" PRIx64 ")", 201 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 202 #endif 203 return true; 204 } 205 206 bool ThreadPlanNull::ShouldStop(Event *event_ptr) { 207 #ifdef LLDB_CONFIGURATION_DEBUG 208 fprintf(stderr, 209 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 210 ", ptid = 0x%" PRIx64 ")", 211 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 212 #else 213 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 214 if (log) 215 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 216 ", ptid = 0x%" PRIx64 ")", 217 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 218 #endif 219 return true; 220 } 221 222 bool ThreadPlanNull::WillStop() { 223 #ifdef LLDB_CONFIGURATION_DEBUG 224 fprintf(stderr, 225 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 226 ", ptid = 0x%" PRIx64 ")", 227 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 228 #else 229 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 230 if (log) 231 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 232 ", ptid = 0x%" PRIx64 ")", 233 LLVM_PRETTY_FUNCTION, m_tid, GetThread().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, GetThread().GetID(), GetThread().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_tid, GetThread().GetProtocolID()); 250 #endif 251 return true; 252 } 253 254 // The null plan is never done. 255 bool ThreadPlanNull::MischiefManaged() { 256 // The null plan is never done. 257 #ifdef LLDB_CONFIGURATION_DEBUG 258 fprintf(stderr, 259 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 260 ", ptid = 0x%" PRIx64 ")", 261 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 262 #else 263 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 264 if (log) 265 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 266 ", ptid = 0x%" PRIx64 ")", 267 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 268 #endif 269 return false; 270 } 271 272 lldb::StateType ThreadPlanNull::GetPlanRunState() { 273 // Not sure what to return here. This is a dead thread. 274 #ifdef LLDB_CONFIGURATION_DEBUG 275 fprintf(stderr, 276 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 277 ", ptid = 0x%" PRIx64 ")", 278 LLVM_PRETTY_FUNCTION, m_tid, GetThread().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 283 ", ptid = 0x%" PRIx64 ")", 284 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 285 #endif 286 return eStateRunning; 287 } 288