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/Core/Log.h" 15 #include "lldb/Symbol/Symbol.h" 16 #include "lldb/Target/RegisterContext.h" 17 #include "lldb/Target/Thread.h" 18 #include "lldb/Target/ThreadPlanShouldStopHere.h" 19 20 using namespace lldb; 21 using namespace lldb_private; 22 23 //---------------------------------------------------------------------- 24 // ThreadPlanShouldStopHere constructor 25 //---------------------------------------------------------------------- 26 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) : 27 m_callbacks(), 28 m_baton(nullptr), 29 m_owner(owner), 30 m_flags(ThreadPlanShouldStopHere::eNone) 31 { 32 m_callbacks.should_stop_here_callback = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback; 33 m_callbacks.step_from_here_callback = ThreadPlanShouldStopHere::DefaultStepFromHereCallback; 34 } 35 36 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks, void *baton) : 37 m_callbacks (), 38 m_baton (), 39 m_owner (owner), 40 m_flags (ThreadPlanShouldStopHere::eNone) 41 { 42 SetShouldStopHereCallbacks(callbacks, baton); 43 } 44 45 ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default; 46 47 bool 48 ThreadPlanShouldStopHere::InvokeShouldStopHereCallback (FrameComparison operation) 49 { 50 bool should_stop_here = true; 51 if (m_callbacks.should_stop_here_callback) 52 { 53 should_stop_here = m_callbacks.should_stop_here_callback (m_owner, m_flags, operation, m_baton); 54 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 55 if (log) 56 { 57 lldb::addr_t current_addr = m_owner->GetThread().GetRegisterContext()->GetPC(0); 58 59 log->Printf ("ShouldStopHere callback returned %u from 0x%" PRIx64 ".", should_stop_here, current_addr); 60 } 61 } 62 63 return should_stop_here; 64 } 65 66 bool 67 ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (ThreadPlan *current_plan, 68 Flags &flags, 69 FrameComparison operation, 70 void *baton) 71 { 72 bool should_stop_here = true; 73 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); 74 if (!frame) 75 return true; 76 77 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 78 79 if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) 80 || (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) 81 || (operation == eFrameCompareSameParent && flags.Test(eStepInAvoidNoDebug))) 82 { 83 if (!frame->HasDebugInformation()) 84 { 85 if (log) 86 log->Printf ("Stepping out of frame with no debug info"); 87 88 should_stop_here = false; 89 } 90 } 91 92 // Always avoid code with line number 0. 93 // FIXME: At present the ShouldStop and the StepFromHere calculate this independently. If this ever 94 // becomes expensive (this one isn't) we can try to have this set a state that the StepFromHere can use. 95 if (frame) 96 { 97 SymbolContext sc; 98 sc = frame->GetSymbolContext (eSymbolContextLineEntry); 99 if (sc.line_entry.line == 0) 100 should_stop_here = false; 101 } 102 103 return should_stop_here; 104 } 105 106 ThreadPlanSP 107 ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan, 108 Flags &flags, 109 FrameComparison operation, 110 void *baton) 111 { 112 const bool stop_others = false; 113 const size_t frame_index = 0; 114 ThreadPlanSP return_plan_sp; 115 // If we are stepping through code at line number 0, then we need to step over this range. Otherwise 116 // we will step out. 117 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 118 119 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); 120 if (!frame) 121 return return_plan_sp; 122 SymbolContext sc; 123 sc = frame->GetSymbolContext (eSymbolContextLineEntry|eSymbolContextSymbol); 124 125 if (sc.line_entry.line == 0) 126 { 127 AddressRange range = sc.line_entry.range; 128 129 // If the whole function is marked line 0 just step out, that's easier & faster than continuing 130 // to step through it. 131 bool just_step_out = false; 132 if (sc.symbol && sc.symbol->ValueIsAddress()) 133 { 134 Address symbol_end = sc.symbol->GetAddress(); 135 symbol_end.Slide(sc.symbol->GetByteSize() - 1); 136 if (range.ContainsFileAddress(sc.symbol->GetAddress()) && range.ContainsFileAddress(symbol_end)) 137 { 138 if (log) 139 log->Printf("Stopped in a function with only line 0 lines, just stepping out."); 140 just_step_out = true; 141 } 142 } 143 if (!just_step_out) 144 { 145 if (log) 146 log->Printf ("ThreadPlanShouldStopHere::DefaultStepFromHereCallback Queueing StepInRange plan to step through line 0 code."); 147 148 return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange(false, 149 range, 150 sc, 151 NULL, 152 eOnlyDuringStepping, 153 eLazyBoolCalculate, 154 eLazyBoolNo); 155 } 156 } 157 158 if (!return_plan_sp) 159 return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop(false, 160 nullptr, 161 true, 162 stop_others, 163 eVoteNo, 164 eVoteNoOpinion, 165 frame_index, 166 true); 167 return return_plan_sp; 168 } 169 170 ThreadPlanSP 171 ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(lldb_private::Flags &flags, lldb::FrameComparison operation) 172 { 173 ThreadPlanSP return_plan_sp; 174 if (m_callbacks.step_from_here_callback) 175 { 176 return_plan_sp = m_callbacks.step_from_here_callback (m_owner, flags, operation, m_baton); 177 } 178 return return_plan_sp; 179 } 180 181 lldb::ThreadPlanSP 182 ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation) 183 { 184 if (!InvokeShouldStopHereCallback(operation)) 185 return QueueStepOutFromHerePlan(m_flags, operation); 186 else 187 return ThreadPlanSP(); 188 } 189