1cfca06d7SDimitry Andric //===-- ThreadPlanStepOverBreakpoint.cpp ----------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9f034231aSEd Maste #include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
10f034231aSEd Maste
11f034231aSEd Maste #include "lldb/Target/Process.h"
12f034231aSEd Maste #include "lldb/Target/RegisterContext.h"
13145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
1474a628f7SDimitry Andric #include "lldb/Utility/Log.h"
1574a628f7SDimitry Andric #include "lldb/Utility/Stream.h"
16f034231aSEd Maste
17f034231aSEd Maste using namespace lldb;
18f034231aSEd Maste using namespace lldb_private;
19f034231aSEd Maste
2014f1b3e8SDimitry Andric // ThreadPlanStepOverBreakpoint: Single steps over a breakpoint bp_site_sp at
2114f1b3e8SDimitry Andric // the pc.
22f034231aSEd Maste
ThreadPlanStepOverBreakpoint(Thread & thread)2314f1b3e8SDimitry Andric ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint(Thread &thread)
2414f1b3e8SDimitry Andric : ThreadPlan(
2514f1b3e8SDimitry Andric ThreadPlan::eKindStepOverBreakpoint, "Step over breakpoint trap",
2614f1b3e8SDimitry Andric thread, eVoteNo,
27f034231aSEd Maste eVoteNoOpinion), // We need to report the run since this happens
28f73363f1SDimitry Andric // first in the thread plan stack when stepping over
29f73363f1SDimitry Andric // a breakpoint
30f034231aSEd Maste m_breakpoint_addr(LLDB_INVALID_ADDRESS),
3114f1b3e8SDimitry Andric m_auto_continue(false), m_reenabled_breakpoint_site(false)
32f034231aSEd Maste
33f034231aSEd Maste {
34cfca06d7SDimitry Andric m_breakpoint_addr = thread.GetRegisterContext()->GetPC();
3514f1b3e8SDimitry Andric m_breakpoint_site_id =
36cfca06d7SDimitry Andric thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress(
3714f1b3e8SDimitry Andric m_breakpoint_addr);
38f034231aSEd Maste }
39f034231aSEd Maste
40344a3780SDimitry Andric ThreadPlanStepOverBreakpoint::~ThreadPlanStepOverBreakpoint() = default;
4114f1b3e8SDimitry Andric
GetDescription(Stream * s,lldb::DescriptionLevel level)4214f1b3e8SDimitry Andric void ThreadPlanStepOverBreakpoint::GetDescription(
4314f1b3e8SDimitry Andric Stream *s, lldb::DescriptionLevel level) {
4414f1b3e8SDimitry Andric s->Printf("Single stepping past breakpoint site %" PRIu64 " at 0x%" PRIx64,
4514f1b3e8SDimitry Andric m_breakpoint_site_id, (uint64_t)m_breakpoint_addr);
46f034231aSEd Maste }
47f034231aSEd Maste
ValidatePlan(Stream * error)4814f1b3e8SDimitry Andric bool ThreadPlanStepOverBreakpoint::ValidatePlan(Stream *error) { return true; }
49f034231aSEd Maste
DoPlanExplainsStop(Event * event_ptr)5014f1b3e8SDimitry Andric bool ThreadPlanStepOverBreakpoint::DoPlanExplainsStop(Event *event_ptr) {
51f034231aSEd Maste StopInfoSP stop_info_sp = GetPrivateStopInfo();
5214f1b3e8SDimitry Andric if (stop_info_sp) {
53f034231aSEd Maste StopReason reason = stop_info_sp->GetStopReason();
54205afe67SEd Maste
55145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
56b60736ecSDimitry Andric LLDB_LOG(log, "Step over breakpoint stopped for reason: {0}.",
57b60736ecSDimitry Andric Thread::StopReasonAsString(reason));
58f73363f1SDimitry Andric
5914f1b3e8SDimitry Andric switch (reason) {
60205afe67SEd Maste case eStopReasonTrace:
61205afe67SEd Maste case eStopReasonNone:
62f034231aSEd Maste return true;
63205afe67SEd Maste case eStopReasonBreakpoint:
64f73363f1SDimitry Andric {
6514f1b3e8SDimitry Andric // It's a little surprising that we stop here for a breakpoint hit.
66f73363f1SDimitry Andric // However, when you single step ONTO a breakpoint we still want to call
67f73363f1SDimitry Andric // that a breakpoint hit, and trigger the actions, etc. Otherwise you
6814f1b3e8SDimitry Andric // would see the PC at the breakpoint without having triggered the
69f73363f1SDimitry Andric // actions, then you'd continue, the PC wouldn't change, and you'd see
70f73363f1SDimitry Andric // the breakpoint hit, which would be odd. So the lower levels fake
71f73363f1SDimitry Andric // "step onto breakpoint address" and return that as a breakpoint hit.
72f73363f1SDimitry Andric // So our trace step COULD appear as a breakpoint hit if the next
73f73363f1SDimitry Andric // instruction also contained a breakpoint. We don't want to handle
74f73363f1SDimitry Andric // that, since we really don't know what to do with breakpoint hits.
75f73363f1SDimitry Andric // But make sure we don't set ourselves to auto-continue or we'll wrench
76f73363f1SDimitry Andric // control away from the plans that can deal with this.
77f73363f1SDimitry Andric // Be careful, however, as we may have "seen a breakpoint under the PC
78f73363f1SDimitry Andric // because we stopped without changing the PC, in which case we do want
79f73363f1SDimitry Andric // to re-claim this stop so we'll try again.
80cfca06d7SDimitry Andric lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC();
81f73363f1SDimitry Andric
82f73363f1SDimitry Andric if (pc_addr == m_breakpoint_addr) {
83ead24645SDimitry Andric LLDB_LOGF(log,
84ead24645SDimitry Andric "Got breakpoint stop reason but pc: 0x%" PRIx64
85ead24645SDimitry Andric "hasn't changed.",
86ead24645SDimitry Andric pc_addr);
87f73363f1SDimitry Andric return true;
88f73363f1SDimitry Andric }
89f73363f1SDimitry Andric
90205afe67SEd Maste SetAutoContinue(false);
91f034231aSEd Maste return false;
92f73363f1SDimitry Andric }
93205afe67SEd Maste default:
94205afe67SEd Maste return false;
95205afe67SEd Maste }
96f034231aSEd Maste }
97f034231aSEd Maste return false;
98f034231aSEd Maste }
99f034231aSEd Maste
ShouldStop(Event * event_ptr)10014f1b3e8SDimitry Andric bool ThreadPlanStepOverBreakpoint::ShouldStop(Event *event_ptr) {
101205afe67SEd Maste return !ShouldAutoContinue(event_ptr);
102f034231aSEd Maste }
103f034231aSEd Maste
StopOthers()10414f1b3e8SDimitry Andric bool ThreadPlanStepOverBreakpoint::StopOthers() { return true; }
105f034231aSEd Maste
GetPlanRunState()10614f1b3e8SDimitry Andric StateType ThreadPlanStepOverBreakpoint::GetPlanRunState() {
107f034231aSEd Maste return eStateStepping;
108f034231aSEd Maste }
109f034231aSEd Maste
DoWillResume(StateType resume_state,bool current_plan)11014f1b3e8SDimitry Andric bool ThreadPlanStepOverBreakpoint::DoWillResume(StateType resume_state,
11114f1b3e8SDimitry Andric bool current_plan) {
11214f1b3e8SDimitry Andric if (current_plan) {
11314f1b3e8SDimitry Andric BreakpointSiteSP bp_site_sp(
114cfca06d7SDimitry Andric m_process.GetBreakpointSiteList().FindByAddress(m_breakpoint_addr));
115f73363f1SDimitry Andric if (bp_site_sp && bp_site_sp->IsEnabled()) {
116cfca06d7SDimitry Andric m_process.DisableBreakpointSite(bp_site_sp.get());
117f73363f1SDimitry Andric m_reenabled_breakpoint_site = false;
118f73363f1SDimitry Andric }
119f034231aSEd Maste }
120f034231aSEd Maste return true;
121f034231aSEd Maste }
122f034231aSEd Maste
WillStop()12314f1b3e8SDimitry Andric bool ThreadPlanStepOverBreakpoint::WillStop() {
124f034231aSEd Maste ReenableBreakpointSite();
125f034231aSEd Maste return true;
126f034231aSEd Maste }
127f034231aSEd Maste
DidPop()128c0981da4SDimitry Andric void ThreadPlanStepOverBreakpoint::DidPop() { ReenableBreakpointSite(); }
129f73363f1SDimitry Andric
MischiefManaged()13014f1b3e8SDimitry Andric bool ThreadPlanStepOverBreakpoint::MischiefManaged() {
131cfca06d7SDimitry Andric lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC();
132f034231aSEd Maste
13314f1b3e8SDimitry Andric if (pc_addr == m_breakpoint_addr) {
13414f1b3e8SDimitry Andric // If we are still at the PC of our breakpoint, then for some reason we
135f73363f1SDimitry Andric // didn't get a chance to run.
136f034231aSEd Maste return false;
13714f1b3e8SDimitry Andric } else {
138145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
139ead24645SDimitry Andric LLDB_LOGF(log, "Completed step over breakpoint plan.");
14014f1b3e8SDimitry Andric // Otherwise, re-enable the breakpoint we were stepping over, and we're
14114f1b3e8SDimitry Andric // done.
142f034231aSEd Maste ReenableBreakpointSite();
143f034231aSEd Maste ThreadPlan::MischiefManaged();
144f034231aSEd Maste return true;
145f034231aSEd Maste }
146f034231aSEd Maste }
147f034231aSEd Maste
ReenableBreakpointSite()14814f1b3e8SDimitry Andric void ThreadPlanStepOverBreakpoint::ReenableBreakpointSite() {
14914f1b3e8SDimitry Andric if (!m_reenabled_breakpoint_site) {
150f034231aSEd Maste m_reenabled_breakpoint_site = true;
15114f1b3e8SDimitry Andric BreakpointSiteSP bp_site_sp(
152cfca06d7SDimitry Andric m_process.GetBreakpointSiteList().FindByAddress(m_breakpoint_addr));
15314f1b3e8SDimitry Andric if (bp_site_sp) {
154cfca06d7SDimitry Andric m_process.EnableBreakpointSite(bp_site_sp.get());
155f034231aSEd Maste }
156f034231aSEd Maste }
157f034231aSEd Maste }
ThreadDestroyed()15814f1b3e8SDimitry Andric void ThreadPlanStepOverBreakpoint::ThreadDestroyed() {
159f034231aSEd Maste ReenableBreakpointSite();
160f034231aSEd Maste }
161f034231aSEd Maste
SetAutoContinue(bool do_it)16214f1b3e8SDimitry Andric void ThreadPlanStepOverBreakpoint::SetAutoContinue(bool do_it) {
163f034231aSEd Maste m_auto_continue = do_it;
164f034231aSEd Maste }
165f034231aSEd Maste
ShouldAutoContinue(Event * event_ptr)16614f1b3e8SDimitry Andric bool ThreadPlanStepOverBreakpoint::ShouldAutoContinue(Event *event_ptr) {
167f034231aSEd Maste return m_auto_continue;
168f034231aSEd Maste }
169205afe67SEd Maste
IsPlanStale()17014f1b3e8SDimitry Andric bool ThreadPlanStepOverBreakpoint::IsPlanStale() {
171cfca06d7SDimitry Andric return GetThread().GetRegisterContext()->GetPC() != m_breakpoint_addr;
172205afe67SEd Maste }
173