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 || (operation == eFrameCompareSameParent && flags.Test(eStepInAvoidNoDebug))) 87 { 88 if (!frame->HasDebugInformation()) 89 { 90 if (log) 91 log->Printf ("Stepping out of frame with no debug info"); 92 93 should_stop_here = false; 94 } 95 } 96 97 // Always avoid code with line number 0. 98 // FIXME: At present the ShouldStop and the StepFromHere calculate this independently. If this ever 99 // becomes expensive (this one isn't) we can try to have this set a state that the StepFromHere can use. 100 if (frame) 101 { 102 SymbolContext sc; 103 sc = frame->GetSymbolContext (eSymbolContextLineEntry); 104 if (sc.line_entry.line == 0) 105 should_stop_here = false; 106 } 107 108 return should_stop_here; 109 } 110 111 ThreadPlanSP 112 ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan, 113 Flags &flags, 114 FrameComparison operation, 115 void *baton) 116 { 117 const bool stop_others = false; 118 const size_t frame_index = 0; 119 ThreadPlanSP return_plan_sp; 120 // If we are stepping through code at line number 0, then we need to step over this range. Otherwise 121 // we will step out. 122 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); 123 if (!frame) 124 return return_plan_sp; 125 SymbolContext sc; 126 sc = frame->GetSymbolContext (eSymbolContextLineEntry); 127 if (sc.line_entry.line == 0) 128 { 129 AddressRange range = sc.line_entry.range; 130 return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOverRange(false, 131 range, 132 sc, 133 eOnlyDuringStepping, 134 eLazyBoolNo); 135 } 136 137 if (!return_plan_sp) 138 return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop (false, 139 NULL, 140 true, 141 stop_others, 142 eVoteNo, 143 eVoteNoOpinion, 144 frame_index); 145 return return_plan_sp; 146 } 147 148 ThreadPlanSP 149 ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(lldb_private::Flags &flags, lldb::FrameComparison operation) 150 { 151 ThreadPlanSP return_plan_sp; 152 if (m_callbacks.step_from_here_callback) 153 { 154 return_plan_sp = m_callbacks.step_from_here_callback (m_owner, flags, operation, m_baton); 155 } 156 return return_plan_sp; 157 158 } 159 160 lldb::ThreadPlanSP 161 ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation) 162 { 163 if (!InvokeShouldStopHereCallback(operation)) 164 return QueueStepOutFromHerePlan(m_flags, operation); 165 else 166 return ThreadPlanSP(); 167 } 168 169