| 1 | //===-- ThreadPlanBase.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/ThreadPlanBase.h" |
| 10 | |
| 11 | // |
| 12 | #include "lldb/Breakpoint/Breakpoint.h" |
| 13 | #include "lldb/Breakpoint/BreakpointLocation.h" |
| 14 | #include "lldb/Breakpoint/BreakpointSite.h" |
| 15 | #include "lldb/Breakpoint/StoppointCallbackContext.h" |
| 16 | #include "lldb/Target/Process.h" |
| 17 | #include "lldb/Target/RegisterContext.h" |
| 18 | #include "lldb/Target/StopInfo.h" |
| 19 | #include "lldb/Utility/LLDBLog.h" |
| 20 | #include "lldb/Utility/Log.h" |
| 21 | #include "lldb/Utility/Stream.h" |
| 22 | |
| 23 | using namespace lldb; |
| 24 | using namespace lldb_private; |
| 25 | |
| 26 | // ThreadPlanBase: This one always stops, and never has anything particular to |
| 27 | // do. |
| 28 | // FIXME: The "signal handling" policies should probably go here. |
| 29 | |
| 30 | ThreadPlanBase::ThreadPlanBase(Thread &thread) |
| 31 | : ThreadPlan(ThreadPlan::eKindBase, "base plan" , thread, eVoteYes, |
| 32 | eVoteNoOpinion) { |
| 33 | // Set the tracer to a default tracer. |
| 34 | // FIXME: need to add a thread settings variable to pix various tracers... |
| 35 | #define THREAD_PLAN_USE_ASSEMBLY_TRACER 1 |
| 36 | |
| 37 | #ifdef THREAD_PLAN_USE_ASSEMBLY_TRACER |
| 38 | ThreadPlanTracerSP new_tracer_sp(new ThreadPlanAssemblyTracer(thread)); |
| 39 | #else |
| 40 | ThreadPlanTracerSP new_tracer_sp(new ThreadPlanTracer(m_thread)); |
| 41 | #endif |
| 42 | new_tracer_sp->EnableTracing(value: thread.GetTraceEnabledState()); |
| 43 | SetThreadPlanTracer(new_tracer_sp); |
| 44 | SetIsControllingPlan(true); |
| 45 | } |
| 46 | |
| 47 | ThreadPlanBase::~ThreadPlanBase() = default; |
| 48 | |
| 49 | void ThreadPlanBase::GetDescription(Stream *s, lldb::DescriptionLevel level) { |
| 50 | s->Printf(format: "Base thread plan." ); |
| 51 | } |
| 52 | |
| 53 | bool ThreadPlanBase::ValidatePlan(Stream *error) { return true; } |
| 54 | |
| 55 | bool ThreadPlanBase::DoPlanExplainsStop(Event *event_ptr) { |
| 56 | // The base plan should defer to its tracer, since by default it always |
| 57 | // handles the stop. |
| 58 | return !TracerExplainsStop(); |
| 59 | } |
| 60 | |
| 61 | Vote ThreadPlanBase::ShouldReportStop(Event *event_ptr) { |
| 62 | StopInfoSP stop_info_sp = GetThread().GetStopInfo(); |
| 63 | if (stop_info_sp) { |
| 64 | bool should_notify = stop_info_sp->ShouldNotify(event_ptr); |
| 65 | if (should_notify) |
| 66 | return eVoteYes; |
| 67 | else |
| 68 | return eVoteNoOpinion; |
| 69 | } else |
| 70 | return eVoteNoOpinion; |
| 71 | } |
| 72 | |
| 73 | bool ThreadPlanBase::ShouldStop(Event *event_ptr) { |
| 74 | m_report_stop_vote = eVoteYes; |
| 75 | m_report_run_vote = eVoteYes; |
| 76 | |
| 77 | Log *log = GetLog(mask: LLDBLog::Step); |
| 78 | |
| 79 | StopInfoSP stop_info_sp = GetPrivateStopInfo(); |
| 80 | if (stop_info_sp) { |
| 81 | StopReason reason = stop_info_sp->GetStopReason(); |
| 82 | switch (reason) { |
| 83 | case eStopReasonInvalid: |
| 84 | case eStopReasonNone: |
| 85 | // This |
| 86 | m_report_run_vote = eVoteNoOpinion; |
| 87 | m_report_stop_vote = eVoteNo; |
| 88 | return false; |
| 89 | |
| 90 | case eStopReasonBreakpoint: |
| 91 | case eStopReasonWatchpoint: |
| 92 | if (stop_info_sp->ShouldStopSynchronous(event_ptr)) { |
| 93 | // If we are going to stop for a breakpoint, then unship the other |
| 94 | // plans at this point. Don't force the discard, however, so |
| 95 | // Controlling plans can stay in place if they want to. |
| 96 | LLDB_LOGF( |
| 97 | log, |
| 98 | "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 |
| 99 | " (breakpoint hit.)" , |
| 100 | m_tid); |
| 101 | GetThread().DiscardThreadPlans(force: false); |
| 102 | return true; |
| 103 | } |
| 104 | // If we aren't going to stop at this breakpoint, and it is internal, |
| 105 | // don't report this stop or the subsequent running event. Otherwise we |
| 106 | // will post the stopped & running, but the stopped event will get marked |
| 107 | // with "restarted" so the UI will know to wait and expect the consequent |
| 108 | // "running". |
| 109 | if (stop_info_sp->ShouldNotify(event_ptr)) { |
| 110 | m_report_stop_vote = eVoteYes; |
| 111 | m_report_run_vote = eVoteYes; |
| 112 | } else { |
| 113 | m_report_stop_vote = eVoteNo; |
| 114 | m_report_run_vote = eVoteNo; |
| 115 | } |
| 116 | return false; |
| 117 | |
| 118 | // TODO: the break below was missing, was this intentional??? If so |
| 119 | // please mention it |
| 120 | break; |
| 121 | |
| 122 | case eStopReasonException: |
| 123 | // If we crashed, discard thread plans and stop. Don't force the |
| 124 | // discard, however, since on rerun the target may clean up this |
| 125 | // exception and continue normally from there. |
| 126 | LLDB_LOGF( |
| 127 | log, |
| 128 | "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 |
| 129 | " (exception: %s)" , |
| 130 | m_tid, stop_info_sp->GetDescription()); |
| 131 | GetThread().DiscardThreadPlans(force: false); |
| 132 | return true; |
| 133 | |
| 134 | case eStopReasonExec: |
| 135 | // If we crashed, discard thread plans and stop. Don't force the |
| 136 | // discard, however, since on rerun the target may clean up this |
| 137 | // exception and continue normally from there. |
| 138 | LLDB_LOGF( |
| 139 | log, |
| 140 | "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 |
| 141 | " (exec.)" , |
| 142 | m_tid); |
| 143 | GetThread().DiscardThreadPlans(force: false); |
| 144 | return true; |
| 145 | |
| 146 | case eStopReasonThreadExiting: |
| 147 | case eStopReasonSignal: |
| 148 | if (stop_info_sp->ShouldStop(event_ptr)) { |
| 149 | LLDB_LOGF( |
| 150 | log, |
| 151 | "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 |
| 152 | " (signal: %s)" , |
| 153 | m_tid, stop_info_sp->GetDescription()); |
| 154 | GetThread().DiscardThreadPlans(force: false); |
| 155 | return true; |
| 156 | } else { |
| 157 | // We're not going to stop, but while we are here, let's figure out |
| 158 | // whether to report this. |
| 159 | if (stop_info_sp->ShouldNotify(event_ptr)) |
| 160 | m_report_stop_vote = eVoteYes; |
| 161 | else |
| 162 | m_report_stop_vote = eVoteNo; |
| 163 | } |
| 164 | return false; |
| 165 | |
| 166 | default: |
| 167 | return true; |
| 168 | } |
| 169 | |
| 170 | } else { |
| 171 | m_report_run_vote = eVoteNoOpinion; |
| 172 | m_report_stop_vote = eVoteNo; |
| 173 | } |
| 174 | |
| 175 | // If there's no explicit reason to stop, then we will continue. |
| 176 | return false; |
| 177 | } |
| 178 | |
| 179 | bool ThreadPlanBase::StopOthers() { return false; } |
| 180 | |
| 181 | StateType ThreadPlanBase::GetPlanRunState() { return eStateRunning; } |
| 182 | |
| 183 | bool ThreadPlanBase::WillStop() { return true; } |
| 184 | |
| 185 | bool ThreadPlanBase::DoWillResume(lldb::StateType resume_state, |
| 186 | bool current_plan) { |
| 187 | // Reset these to the default values so we don't set them wrong, then not get |
| 188 | // asked for a while, then return the wrong answer. |
| 189 | m_report_run_vote = eVoteNoOpinion; |
| 190 | m_report_stop_vote = eVoteNo; |
| 191 | return true; |
| 192 | } |
| 193 | |
| 194 | // The base plan is never done. |
| 195 | bool ThreadPlanBase::MischiefManaged() { |
| 196 | // The base plan is never done. |
| 197 | return false; |
| 198 | } |
| 199 | |
| 200 | RunDirection ThreadPlanBase::GetDirection() const { |
| 201 | return m_process.GetBaseDirection(); |
| 202 | } |
| 203 | |