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_kind(kind), m_thread(&thread), 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 return DoWillResume(resume_state, current_plan); 137 } 138 139 lldb::user_id_t ThreadPlan::GetNextID() { 140 static uint32_t g_nextPlanID = 0; 141 return ++g_nextPlanID; 142 } 143 144 void ThreadPlan::DidPush() {} 145 146 void ThreadPlan::WillPop() {} 147 148 bool ThreadPlan::OkayToDiscard() { 149 return IsMasterPlan() ? m_okay_to_discard : true; 150 } 151 152 lldb::StateType ThreadPlan::RunState() { 153 if (m_tracer_sp && m_tracer_sp->TracingEnabled() && 154 m_tracer_sp->SingleStepEnabled()) 155 return eStateStepping; 156 else 157 return GetPlanRunState(); 158 } 159 160 bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { 161 switch (reason) { 162 case eStopReasonWatchpoint: 163 case eStopReasonSignal: 164 case eStopReasonException: 165 case eStopReasonExec: 166 case eStopReasonThreadExiting: 167 case eStopReasonInstrumentation: 168 return true; 169 default: 170 return false; 171 } 172 } 173 174 // ThreadPlanNull 175 176 ThreadPlanNull::ThreadPlanNull(Thread &thread) 177 : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread, 178 eVoteNoOpinion, eVoteNoOpinion) {} 179 180 ThreadPlanNull::~ThreadPlanNull() = default; 181 182 void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) { 183 s->PutCString("Null thread plan - thread has been destroyed."); 184 } 185 186 bool ThreadPlanNull::ValidatePlan(Stream *error) { 187 #ifdef LLDB_CONFIGURATION_DEBUG 188 fprintf(stderr, 189 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 190 ", ptid = 0x%" PRIx64 ")", 191 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 192 #else 193 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 194 if (log) 195 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 196 ", ptid = 0x%" PRIx64 ")", 197 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 198 #endif 199 return true; 200 } 201 202 bool ThreadPlanNull::ShouldStop(Event *event_ptr) { 203 #ifdef LLDB_CONFIGURATION_DEBUG 204 fprintf(stderr, 205 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 206 ", ptid = 0x%" PRIx64 ")", 207 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 208 #else 209 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 210 if (log) 211 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 212 ", ptid = 0x%" PRIx64 ")", 213 LLVM_PRETTY_FUNCTION, m_tid, GetThread().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_tid, GetThread().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_tid, GetThread().GetProtocolID()); 230 #endif 231 return true; 232 } 233 234 bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { 235 #ifdef LLDB_CONFIGURATION_DEBUG 236 fprintf(stderr, 237 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 238 ", ptid = 0x%" PRIx64 ")", 239 LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); 240 #else 241 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 242 if (log) 243 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 244 ", ptid = 0x%" PRIx64 ")", 245 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 246 #endif 247 return true; 248 } 249 250 // The null plan is never done. 251 bool ThreadPlanNull::MischiefManaged() { 252 // The null plan is never done. 253 #ifdef LLDB_CONFIGURATION_DEBUG 254 fprintf(stderr, 255 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 256 ", ptid = 0x%" PRIx64 ")", 257 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); 258 #else 259 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 260 if (log) 261 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 262 ", ptid = 0x%" PRIx64 ")", 263 LLVM_PRETTY_FUNCTION, m_tid, GetThread().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_tid, GetThread().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_tid, GetThread().GetProtocolID()); 281 #endif 282 return eStateRunning; 283 } 284