1 //===-- ThreadPlanShouldStopHere.cpp --------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Target/ThreadPlanShouldStopHere.h"
10 #include "lldb/Symbol/Symbol.h"
11 #include "lldb/Target/RegisterContext.h"
12 #include "lldb/Target/Thread.h"
13 #include "lldb/Utility/LLDBLog.h"
14 #include "lldb/Utility/Log.h"
17 using namespace lldb_private
;
19 // ThreadPlanShouldStopHere constructor
20 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan
*owner
)
21 : m_callbacks(), m_baton(nullptr), m_owner(owner
),
22 m_flags(ThreadPlanShouldStopHere::eNone
) {
23 m_callbacks
.should_stop_here_callback
=
24 ThreadPlanShouldStopHere::DefaultShouldStopHereCallback
;
25 m_callbacks
.step_from_here_callback
=
26 ThreadPlanShouldStopHere::DefaultStepFromHereCallback
;
29 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(
30 ThreadPlan
*owner
, const ThreadPlanShouldStopHereCallbacks
*callbacks
,
32 : m_callbacks(), m_baton(), m_owner(owner
),
33 m_flags(ThreadPlanShouldStopHere::eNone
) {
34 SetShouldStopHereCallbacks(callbacks
, baton
);
37 ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default;
39 bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback(
40 FrameComparison operation
, Status
&status
) {
41 bool should_stop_here
= true;
42 if (m_callbacks
.should_stop_here_callback
) {
43 should_stop_here
= m_callbacks
.should_stop_here_callback(
44 m_owner
, m_flags
, operation
, status
, m_baton
);
45 Log
*log
= GetLog(LLDBLog::Step
);
47 lldb::addr_t current_addr
=
48 m_owner
->GetThread().GetRegisterContext()->GetPC(0);
50 LLDB_LOGF(log
, "ShouldStopHere callback returned %u from 0x%" PRIx64
".",
51 should_stop_here
, current_addr
);
55 return should_stop_here
;
58 bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
59 ThreadPlan
*current_plan
, Flags
&flags
, FrameComparison operation
,
60 Status
&status
, void *baton
) {
61 bool should_stop_here
= true;
62 StackFrame
*frame
= current_plan
->GetThread().GetStackFrameAtIndex(0).get();
66 Log
*log
= GetLog(LLDBLog::Step
);
68 if ((operation
== eFrameCompareOlder
&& flags
.Test(eStepOutAvoidNoDebug
)) ||
69 (operation
== eFrameCompareYounger
&& flags
.Test(eStepInAvoidNoDebug
)) ||
70 (operation
== eFrameCompareSameParent
&&
71 flags
.Test(eStepInAvoidNoDebug
))) {
72 if (!frame
->HasDebugInformation()) {
73 LLDB_LOGF(log
, "Stepping out of frame with no debug info");
75 should_stop_here
= false;
79 // Always avoid code with line number 0.
80 // FIXME: At present the ShouldStop and the StepFromHere calculate this
81 // independently. If this ever
82 // becomes expensive (this one isn't) we can try to have this set a state
83 // that the StepFromHere can use.
86 sc
= frame
->GetSymbolContext(eSymbolContextLineEntry
);
87 if (sc
.line_entry
.line
== 0)
88 should_stop_here
= false;
91 return should_stop_here
;
94 ThreadPlanSP
ThreadPlanShouldStopHere::DefaultStepFromHereCallback(
95 ThreadPlan
*current_plan
, Flags
&flags
, FrameComparison operation
,
96 Status
&status
, void *baton
) {
97 const bool stop_others
= false;
98 const size_t frame_index
= 0;
99 ThreadPlanSP return_plan_sp
;
100 // If we are stepping through code at line number 0, then we need to step
101 // over this range. Otherwise we will step out.
102 Log
*log
= GetLog(LLDBLog::Step
);
104 StackFrame
*frame
= current_plan
->GetThread().GetStackFrameAtIndex(0).get();
106 return return_plan_sp
;
108 sc
= frame
->GetSymbolContext(eSymbolContextLineEntry
| eSymbolContextSymbol
);
110 if (sc
.line_entry
.line
== 0) {
111 AddressRange range
= sc
.line_entry
.range
;
113 // If the whole function is marked line 0 just step out, that's easier &
114 // faster than continuing to step through it.
115 bool just_step_out
= false;
116 if (sc
.symbol
&& sc
.symbol
->ValueIsAddress()) {
117 Address symbol_end
= sc
.symbol
->GetAddress();
118 symbol_end
.Slide(sc
.symbol
->GetByteSize() - 1);
119 if (range
.ContainsFileAddress(sc
.symbol
->GetAddress()) &&
120 range
.ContainsFileAddress(symbol_end
)) {
121 LLDB_LOGF(log
, "Stopped in a function with only line 0 lines, just "
123 just_step_out
= true;
126 if (!just_step_out
) {
127 LLDB_LOGF(log
, "ThreadPlanShouldStopHere::DefaultStepFromHereCallback "
128 "Queueing StepInRange plan to step through line 0 code.");
130 return_plan_sp
= current_plan
->GetThread().QueueThreadPlanForStepInRange(
131 false, range
, sc
, nullptr, eOnlyDuringStepping
, status
,
132 eLazyBoolCalculate
, eLazyBoolNo
);
138 current_plan
->GetThread().QueueThreadPlanForStepOutNoShouldStop(
139 false, nullptr, true, stop_others
, eVoteNo
, eVoteNoOpinion
,
140 frame_index
, status
, true);
141 return return_plan_sp
;
144 ThreadPlanSP
ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(
145 lldb_private::Flags
&flags
, lldb::FrameComparison operation
,
147 ThreadPlanSP return_plan_sp
;
148 if (m_callbacks
.step_from_here_callback
) {
149 return_plan_sp
= m_callbacks
.step_from_here_callback(
150 m_owner
, flags
, operation
, status
, m_baton
);
152 return return_plan_sp
;
155 lldb::ThreadPlanSP
ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut(
156 lldb::FrameComparison operation
, Status
&status
) {
157 if (!InvokeShouldStopHereCallback(operation
, status
))
158 return QueueStepOutFromHerePlan(m_flags
, operation
, status
);
160 return ThreadPlanSP();