xref: /src/contrib/llvm-project/lldb/source/Target/ThreadPlanShouldStopHere.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1cfca06d7SDimitry Andric //===-- ThreadPlanShouldStopHere.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 
974a628f7SDimitry Andric #include "lldb/Target/ThreadPlanShouldStopHere.h"
10f3fbd1c0SDimitry Andric #include "lldb/Symbol/Symbol.h"
11f034231aSEd Maste #include "lldb/Target/RegisterContext.h"
1274a628f7SDimitry Andric #include "lldb/Target/Thread.h"
13145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
1474a628f7SDimitry Andric #include "lldb/Utility/Log.h"
15f034231aSEd Maste 
16f034231aSEd Maste using namespace lldb;
17f034231aSEd Maste using namespace lldb_private;
18f034231aSEd Maste 
19f034231aSEd Maste // ThreadPlanShouldStopHere constructor
ThreadPlanShouldStopHere(ThreadPlan * owner)2014f1b3e8SDimitry Andric ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner)
2114f1b3e8SDimitry Andric     : m_callbacks(), m_baton(nullptr), m_owner(owner),
2214f1b3e8SDimitry Andric       m_flags(ThreadPlanShouldStopHere::eNone) {
2314f1b3e8SDimitry Andric   m_callbacks.should_stop_here_callback =
2414f1b3e8SDimitry Andric       ThreadPlanShouldStopHere::DefaultShouldStopHereCallback;
2514f1b3e8SDimitry Andric   m_callbacks.step_from_here_callback =
2614f1b3e8SDimitry Andric       ThreadPlanShouldStopHere::DefaultStepFromHereCallback;
270cac4ca3SEd Maste }
280cac4ca3SEd Maste 
ThreadPlanShouldStopHere(ThreadPlan * owner,const ThreadPlanShouldStopHereCallbacks * callbacks,void * baton)2914f1b3e8SDimitry Andric ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(
3014f1b3e8SDimitry Andric     ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks,
3114f1b3e8SDimitry Andric     void *baton)
3214f1b3e8SDimitry Andric     : m_callbacks(), m_baton(), m_owner(owner),
3314f1b3e8SDimitry Andric       m_flags(ThreadPlanShouldStopHere::eNone) {
340cac4ca3SEd Maste   SetShouldStopHereCallbacks(callbacks, baton);
35f034231aSEd Maste }
36f034231aSEd Maste 
37e81d9d49SDimitry Andric ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default;
38f034231aSEd Maste 
InvokeShouldStopHereCallback(FrameComparison operation,Status & status)3914f1b3e8SDimitry Andric bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback(
4094994d37SDimitry Andric     FrameComparison operation, Status &status) {
410cac4ca3SEd Maste   bool should_stop_here = true;
4214f1b3e8SDimitry Andric   if (m_callbacks.should_stop_here_callback) {
4314f1b3e8SDimitry Andric     should_stop_here = m_callbacks.should_stop_here_callback(
4494994d37SDimitry Andric         m_owner, m_flags, operation, status, m_baton);
45145449b1SDimitry Andric     Log *log = GetLog(LLDBLog::Step);
4614f1b3e8SDimitry Andric     if (log) {
4714f1b3e8SDimitry Andric       lldb::addr_t current_addr =
4814f1b3e8SDimitry Andric           m_owner->GetThread().GetRegisterContext()->GetPC(0);
49f034231aSEd Maste 
50ead24645SDimitry Andric       LLDB_LOGF(log, "ShouldStopHere callback returned %u from 0x%" PRIx64 ".",
5114f1b3e8SDimitry Andric                 should_stop_here, current_addr);
520cac4ca3SEd Maste     }
530cac4ca3SEd Maste   }
540cac4ca3SEd Maste 
550cac4ca3SEd Maste   return should_stop_here;
560cac4ca3SEd Maste }
570cac4ca3SEd Maste 
DefaultShouldStopHereCallback(ThreadPlan * current_plan,Flags & flags,FrameComparison operation,Status & status,void * baton)5814f1b3e8SDimitry Andric bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
5914f1b3e8SDimitry Andric     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
6094994d37SDimitry Andric     Status &status, void *baton) {
610cac4ca3SEd Maste   bool should_stop_here = true;
620cac4ca3SEd Maste   StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
630cac4ca3SEd Maste   if (!frame)
640cac4ca3SEd Maste     return true;
650cac4ca3SEd Maste 
66145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
670cac4ca3SEd Maste 
6814f1b3e8SDimitry Andric   if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) ||
6914f1b3e8SDimitry Andric       (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) ||
7014f1b3e8SDimitry Andric       (operation == eFrameCompareSameParent &&
7114f1b3e8SDimitry Andric        flags.Test(eStepInAvoidNoDebug))) {
7214f1b3e8SDimitry Andric     if (!frame->HasDebugInformation()) {
73ead24645SDimitry Andric       LLDB_LOGF(log, "Stepping out of frame with no debug info");
740cac4ca3SEd Maste 
750cac4ca3SEd Maste       should_stop_here = false;
76f034231aSEd Maste     }
77f034231aSEd Maste   }
780cac4ca3SEd Maste 
790cac4ca3SEd Maste   // Always avoid code with line number 0.
8014f1b3e8SDimitry Andric   // FIXME: At present the ShouldStop and the StepFromHere calculate this
8114f1b3e8SDimitry Andric   // independently.  If this ever
82f73363f1SDimitry Andric   // becomes expensive (this one isn't) we can try to have this set a state
83f73363f1SDimitry Andric   // that the StepFromHere can use.
8414f1b3e8SDimitry Andric   if (frame) {
850cac4ca3SEd Maste     SymbolContext sc;
860cac4ca3SEd Maste     sc = frame->GetSymbolContext(eSymbolContextLineEntry);
870cac4ca3SEd Maste     if (sc.line_entry.line == 0)
880cac4ca3SEd Maste       should_stop_here = false;
890cac4ca3SEd Maste   }
900cac4ca3SEd Maste 
910cac4ca3SEd Maste   return should_stop_here;
920cac4ca3SEd Maste }
930cac4ca3SEd Maste 
DefaultStepFromHereCallback(ThreadPlan * current_plan,Flags & flags,FrameComparison operation,Status & status,void * baton)9414f1b3e8SDimitry Andric ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback(
9514f1b3e8SDimitry Andric     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
9694994d37SDimitry Andric     Status &status, void *baton) {
970cac4ca3SEd Maste   const bool stop_others = false;
980cac4ca3SEd Maste   const size_t frame_index = 0;
990cac4ca3SEd Maste   ThreadPlanSP return_plan_sp;
100f73363f1SDimitry Andric   // If we are stepping through code at line number 0, then we need to step
101f73363f1SDimitry Andric   // over this range.  Otherwise we will step out.
102145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
103f3fbd1c0SDimitry Andric 
1040cac4ca3SEd Maste   StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
1050cac4ca3SEd Maste   if (!frame)
1060cac4ca3SEd Maste     return return_plan_sp;
1070cac4ca3SEd Maste   SymbolContext sc;
108f3fbd1c0SDimitry Andric   sc = frame->GetSymbolContext(eSymbolContextLineEntry | eSymbolContextSymbol);
109f3fbd1c0SDimitry Andric 
11014f1b3e8SDimitry Andric   if (sc.line_entry.line == 0) {
1110cac4ca3SEd Maste     AddressRange range = sc.line_entry.range;
112f3fbd1c0SDimitry Andric 
11314f1b3e8SDimitry Andric     // If the whole function is marked line 0 just step out, that's easier &
114f73363f1SDimitry Andric     // faster than continuing to step through it.
115f3fbd1c0SDimitry Andric     bool just_step_out = false;
11614f1b3e8SDimitry Andric     if (sc.symbol && sc.symbol->ValueIsAddress()) {
117f3fbd1c0SDimitry Andric       Address symbol_end = sc.symbol->GetAddress();
118f3fbd1c0SDimitry Andric       symbol_end.Slide(sc.symbol->GetByteSize() - 1);
11914f1b3e8SDimitry Andric       if (range.ContainsFileAddress(sc.symbol->GetAddress()) &&
12014f1b3e8SDimitry Andric           range.ContainsFileAddress(symbol_end)) {
121ead24645SDimitry Andric         LLDB_LOGF(log, "Stopped in a function with only line 0 lines, just "
12214f1b3e8SDimitry Andric                        "stepping out.");
123f3fbd1c0SDimitry Andric         just_step_out = true;
124f3fbd1c0SDimitry Andric       }
125f3fbd1c0SDimitry Andric     }
12614f1b3e8SDimitry Andric     if (!just_step_out) {
127ead24645SDimitry Andric       LLDB_LOGF(log, "ThreadPlanShouldStopHere::DefaultStepFromHereCallback "
12814f1b3e8SDimitry Andric                      "Queueing StepInRange plan to step through line 0 code.");
129f3fbd1c0SDimitry Andric 
13014f1b3e8SDimitry Andric       return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange(
1315f29bb8aSDimitry Andric           false, range, sc, nullptr, eOnlyDuringStepping, status,
13294994d37SDimitry Andric           eLazyBoolCalculate, eLazyBoolNo);
1330cac4ca3SEd Maste     }
134f3fbd1c0SDimitry Andric   }
1350cac4ca3SEd Maste 
1360cac4ca3SEd Maste   if (!return_plan_sp)
13714f1b3e8SDimitry Andric     return_plan_sp =
13814f1b3e8SDimitry Andric         current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop(
13914f1b3e8SDimitry Andric             false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion,
14094994d37SDimitry Andric             frame_index, status, true);
141f034231aSEd Maste   return return_plan_sp;
142f034231aSEd Maste }
1430cac4ca3SEd Maste 
QueueStepOutFromHerePlan(lldb_private::Flags & flags,lldb::FrameComparison operation,Status & status)14414f1b3e8SDimitry Andric ThreadPlanSP ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(
14594994d37SDimitry Andric     lldb_private::Flags &flags, lldb::FrameComparison operation,
14694994d37SDimitry Andric     Status &status) {
1470cac4ca3SEd Maste   ThreadPlanSP return_plan_sp;
14814f1b3e8SDimitry Andric   if (m_callbacks.step_from_here_callback) {
14994994d37SDimitry Andric     return_plan_sp = m_callbacks.step_from_here_callback(
15094994d37SDimitry Andric         m_owner, flags, operation, status, m_baton);
1510cac4ca3SEd Maste   }
1520cac4ca3SEd Maste   return return_plan_sp;
1530cac4ca3SEd Maste }
1540cac4ca3SEd Maste 
CheckShouldStopHereAndQueueStepOut(lldb::FrameComparison operation,Status & status)15514f1b3e8SDimitry Andric lldb::ThreadPlanSP ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut(
15694994d37SDimitry Andric     lldb::FrameComparison operation, Status &status) {
15794994d37SDimitry Andric   if (!InvokeShouldStopHereCallback(operation, status))
15894994d37SDimitry Andric     return QueueStepOutFromHerePlan(m_flags, operation, status);
159f034231aSEd Maste   else
160f034231aSEd Maste     return ThreadPlanSP();
161f034231aSEd Maste }
162