294 lines · cpp
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-exception6//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/LLDBLog.h"16#include "lldb/Utility/Log.h"17#include "lldb/Utility/State.h"18 19using namespace lldb;20using namespace lldb_private;21 22// ThreadPlan constructor23ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread,24 Vote report_stop_vote, Vote report_run_vote)25 : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),26 m_report_stop_vote(report_stop_vote), m_report_run_vote(report_run_vote),27 m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false),28 m_thread(&thread), 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),31 m_is_controlling_plan(false), m_plan_succeeded(true) {32 SetID(GetNextID());33}34 35// Destructor36ThreadPlan::~ThreadPlan() = default;37 38Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); }39 40const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); }41 42Thread &ThreadPlan::GetThread() {43 if (m_thread)44 return *m_thread;45 46 ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);47 m_thread = thread_sp.get();48 return *m_thread;49}50 51bool ThreadPlan::PlanExplainsStop(Event *event_ptr) {52 if (m_cached_plan_explains_stop == eLazyBoolCalculate) {53 bool actual_value = DoPlanExplainsStop(event_ptr);54 CachePlanExplainsStop(actual_value);55 return actual_value;56 } else {57 return m_cached_plan_explains_stop == eLazyBoolYes;58 }59}60 61bool ThreadPlan::IsPlanComplete() {62 std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);63 return m_plan_complete;64}65 66void ThreadPlan::SetPlanComplete(bool success) {67 std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);68 m_plan_complete = true;69 m_plan_succeeded = success;70}71 72bool ThreadPlan::MischiefManaged() {73 std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex);74 // Mark the plan is complete, but don't override the success flag.75 m_plan_complete = true;76 return true;77}78 79Vote ThreadPlan::ShouldReportStop(Event *event_ptr) {80 Log *log = GetLog(LLDBLog::Step);81 82 if (m_report_stop_vote == eVoteNoOpinion) {83 ThreadPlan *prev_plan = GetPreviousPlan();84 if (prev_plan) {85 Vote prev_vote = prev_plan->ShouldReportStop(event_ptr);86 LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote);87 return prev_vote;88 }89 }90 LLDB_LOG(log, "Returning vote: {0}", m_report_stop_vote);91 return m_report_stop_vote;92}93 94Vote ThreadPlan::ShouldReportRun(Event *event_ptr) {95 if (m_report_run_vote == eVoteNoOpinion) {96 ThreadPlan *prev_plan = GetPreviousPlan();97 if (prev_plan)98 return prev_plan->ShouldReportRun(event_ptr);99 }100 return m_report_run_vote;101}102 103void ThreadPlan::ClearThreadCache() { m_thread = nullptr; }104 105bool ThreadPlan::StopOthers() {106 ThreadPlan *prev_plan;107 prev_plan = GetPreviousPlan();108 return (prev_plan == nullptr) ? false : prev_plan->StopOthers();109}110 111void ThreadPlan::SetStopOthers(bool new_value) {112 // SetStopOthers doesn't work up the hierarchy. You have to set the explicit113 // ThreadPlan you want to affect.114}115 116bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) {117 m_cached_plan_explains_stop = eLazyBoolCalculate;118 119 if (current_plan) {120 Log *log = GetLog(LLDBLog::Step);121 122 if (log) {123 RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();124 assert(reg_ctx);125 addr_t pc = reg_ctx->GetPC();126 addr_t sp = reg_ctx->GetSP();127 addr_t fp = reg_ctx->GetFP();128 LLDB_LOGF(129 log,130 "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64131 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "132 "plan = '%s', state = %s, stop others = %d",133 __FUNCTION__, GetThread().GetIndexID(),134 static_cast<void *>(&GetThread()), m_tid, static_cast<uint64_t>(pc),135 static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(),136 StateAsCString(resume_state), StopOthers());137 }138 }139 bool success = DoWillResume(resume_state, current_plan);140 ClearThreadCache(); // We don't cache the thread pointer over resumes. This141 // Thread might go away, and another Thread represent142 // the same underlying object on a later stop.143 return success;144}145 146lldb::user_id_t ThreadPlan::GetNextID() {147 static uint32_t g_nextPlanID = 0;148 return ++g_nextPlanID;149}150 151void ThreadPlan::DidPush() {}152 153void ThreadPlan::DidPop() {}154 155bool ThreadPlan::OkayToDiscard() {156 return IsControllingPlan() ? m_okay_to_discard : true;157}158 159lldb::StateType ThreadPlan::RunState() {160 if (m_tracer_sp && m_tracer_sp->TracingEnabled())161 return eStateStepping;162 else163 return GetPlanRunState();164}165 166bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) {167 switch (reason) {168 case eStopReasonWatchpoint:169 case eStopReasonSignal:170 case eStopReasonException:171 case eStopReasonExec:172 case eStopReasonThreadExiting:173 case eStopReasonInstrumentation:174 case eStopReasonFork:175 case eStopReasonVFork:176 case eStopReasonVForkDone:177 case eStopReasonInterrupt:178 return true;179 default:180 return false;181 }182}183 184// ThreadPlanNull185 186ThreadPlanNull::ThreadPlanNull(Thread &thread)187 : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread,188 eVoteNoOpinion, eVoteNoOpinion) {}189 190ThreadPlanNull::~ThreadPlanNull() = default;191 192void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) {193 s->PutCString("Null thread plan - thread has been destroyed.");194}195 196bool ThreadPlanNull::ValidatePlan(Stream *error) {197#ifdef LLDB_CONFIGURATION_DEBUG198 fprintf(stderr,199 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64200 ", ptid = 0x%" PRIx64 ")",201 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());202#else203 Log *log = GetLog(LLDBLog::Thread);204 if (log)205 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64206 ", ptid = 0x%" PRIx64 ")",207 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());208#endif209 return true;210}211 212bool ThreadPlanNull::ShouldStop(Event *event_ptr) {213#ifdef LLDB_CONFIGURATION_DEBUG214 fprintf(stderr,215 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64216 ", ptid = 0x%" PRIx64 ")",217 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());218#else219 Log *log = GetLog(LLDBLog::Thread);220 if (log)221 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64222 ", ptid = 0x%" PRIx64 ")",223 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());224#endif225 return true;226}227 228bool ThreadPlanNull::WillStop() {229#ifdef LLDB_CONFIGURATION_DEBUG230 fprintf(stderr,231 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64232 ", ptid = 0x%" PRIx64 ")",233 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());234#else235 Log *log = GetLog(LLDBLog::Thread);236 if (log)237 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64238 ", ptid = 0x%" PRIx64 ")",239 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());240#endif241 return true;242}243 244bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) {245#ifdef LLDB_CONFIGURATION_DEBUG246 fprintf(stderr,247 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64248 ", ptid = 0x%" PRIx64 ")",249 LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID());250#else251 Log *log = GetLog(LLDBLog::Thread);252 if (log)253 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64254 ", ptid = 0x%" PRIx64 ")",255 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());256#endif257 return true;258}259 260// The null plan is never done.261bool ThreadPlanNull::MischiefManaged() {262// The null plan is never done.263#ifdef LLDB_CONFIGURATION_DEBUG264 fprintf(stderr,265 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64266 ", ptid = 0x%" PRIx64 ")",267 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());268#else269 Log *log = GetLog(LLDBLog::Thread);270 if (log)271 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64272 ", ptid = 0x%" PRIx64 ")",273 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());274#endif275 return false;276}277 278lldb::StateType ThreadPlanNull::GetPlanRunState() {279// Not sure what to return here. This is a dead thread.280#ifdef LLDB_CONFIGURATION_DEBUG281 fprintf(stderr,282 "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64283 ", ptid = 0x%" PRIx64 ")",284 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());285#else286 Log *log = GetLog(LLDBLog::Thread);287 if (log)288 log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64289 ", ptid = 0x%" PRIx64 ")",290 LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());291#endif292 return eStateRunning;293}294