1 //===-- ThreadPlanShouldStopHere.cpp ----------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "lldb/Target/RegisterContext.h" 15 #include "lldb/Target/Thread.h" 16 #include "lldb/Target/ThreadPlanShouldStopHere.h" 17 #include "lldb/Core/Log.h" 18 19 using namespace lldb; 20 using namespace lldb_private; 21 22 //---------------------------------------------------------------------- 23 // ThreadPlanShouldStopHere constructor 24 //---------------------------------------------------------------------- 25 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) : 26 m_callbacks(), 27 m_baton(nullptr), 28 m_owner(owner), 29 m_flags(ThreadPlanShouldStopHere::eNone) 30 { 31 m_callbacks.should_stop_here_callback = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback; 32 m_callbacks.step_from_here_callback = ThreadPlanShouldStopHere::DefaultStepFromHereCallback; 33 } 34 35 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks, void *baton) : 36 m_callbacks (), 37 m_baton (), 38 m_owner (owner), 39 m_flags (ThreadPlanShouldStopHere::eNone) 40 { 41 SetShouldStopHereCallbacks(callbacks, baton); 42 } 43 44 ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default; 45 46 bool 47 ThreadPlanShouldStopHere::InvokeShouldStopHereCallback (FrameComparison operation) 48 { 49 bool should_stop_here = true; 50 if (m_callbacks.should_stop_here_callback) 51 { 52 should_stop_here = m_callbacks.should_stop_here_callback (m_owner, m_flags, operation, m_baton); 53 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 54 if (log) 55 { 56 lldb::addr_t current_addr = m_owner->GetThread().GetRegisterContext()->GetPC(0); 57 58 log->Printf ("ShouldStopHere callback returned %u from 0x%" PRIx64 ".", should_stop_here, current_addr); 59 } 60 } 61 62 return should_stop_here; 63 } 64 65 bool 66 ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (ThreadPlan *current_plan, 67 Flags &flags, 68 FrameComparison operation, 69 void *baton) 70 { 71 bool should_stop_here = true; 72 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); 73 if (!frame) 74 return true; 75 76 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 77 78 if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) 79 || (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) 80 || (operation == eFrameCompareSameParent && flags.Test(eStepInAvoidNoDebug))) 81 { 82 if (!frame->HasDebugInformation()) 83 { 84 if (log) 85 log->Printf ("Stepping out of frame with no debug info"); 86 87 should_stop_here = false; 88 } 89 } 90 91 // Always avoid code with line number 0. 92 // FIXME: At present the ShouldStop and the StepFromHere calculate this independently. If this ever 93 // becomes expensive (this one isn't) we can try to have this set a state that the StepFromHere can use. 94 if (frame) 95 { 96 SymbolContext sc; 97 sc = frame->GetSymbolContext (eSymbolContextLineEntry); 98 if (sc.line_entry.line == 0) 99 should_stop_here = false; 100 } 101 102 return should_stop_here; 103 } 104 105 ThreadPlanSP 106 ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan, 107 Flags &flags, 108 FrameComparison operation, 109 void *baton) 110 { 111 const bool stop_others = false; 112 const size_t frame_index = 0; 113 ThreadPlanSP return_plan_sp; 114 // If we are stepping through code at line number 0, then we need to step over this range. Otherwise 115 // we will step out. 116 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); 117 if (!frame) 118 return return_plan_sp; 119 SymbolContext sc; 120 sc = frame->GetSymbolContext (eSymbolContextLineEntry); 121 if (sc.line_entry.line == 0) 122 { 123 AddressRange range = sc.line_entry.range; 124 return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOverRange(false, 125 range, 126 sc, 127 eOnlyDuringStepping, 128 eLazyBoolNo); 129 } 130 131 if (!return_plan_sp) 132 return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop(false, 133 nullptr, 134 true, 135 stop_others, 136 eVoteNo, 137 eVoteNoOpinion, 138 frame_index); 139 return return_plan_sp; 140 } 141 142 ThreadPlanSP 143 ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(lldb_private::Flags &flags, lldb::FrameComparison operation) 144 { 145 ThreadPlanSP return_plan_sp; 146 if (m_callbacks.step_from_here_callback) 147 { 148 return_plan_sp = m_callbacks.step_from_here_callback (m_owner, flags, operation, m_baton); 149 } 150 return return_plan_sp; 151 } 152 153 lldb::ThreadPlanSP 154 ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation) 155 { 156 if (!InvokeShouldStopHereCallback(operation)) 157 return QueueStepOutFromHerePlan(m_flags, operation); 158 else 159 return ThreadPlanSP(); 160 } 161