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