1 //===-- ThreadPlanStepOut.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/ThreadPlanStepOut.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Breakpoint/Breakpoint.h" 17 #include "lldb/lldb-private-log.h" 18 #include "lldb/Core/Log.h" 19 #include "lldb/Target/Process.h" 20 #include "lldb/Target/RegisterContext.h" 21 #include "lldb/Target/StopInfo.h" 22 #include "lldb/Target/Target.h" 23 24 using namespace lldb; 25 using namespace lldb_private; 26 27 //---------------------------------------------------------------------- 28 // ThreadPlanStepOut: Step out of the current frame 29 //---------------------------------------------------------------------- 30 31 ThreadPlanStepOut::ThreadPlanStepOut 32 ( 33 Thread &thread, 34 SymbolContext *context, 35 bool first_insn, 36 bool stop_others, 37 Vote stop_vote, 38 Vote run_vote, 39 uint32_t frame_idx 40 ) : 41 ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote), 42 m_step_from_context (context), 43 m_step_from_insn (LLDB_INVALID_ADDRESS), 44 m_return_bp_id (LLDB_INVALID_BREAK_ID), 45 m_return_addr (LLDB_INVALID_ADDRESS), 46 m_first_insn (first_insn), 47 m_stop_others (stop_others) 48 { 49 m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); 50 51 // Find the return address and set a breakpoint there: 52 // FIXME - can we do this more securely if we know first_insn? 53 54 StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1)); 55 if (return_frame_sp) 56 { 57 // TODO: check for inlined frames and do the right thing... 58 m_return_addr = return_frame_sp->GetRegisterContext()->GetPC(); 59 Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get(); 60 if (return_bp != NULL) 61 { 62 return_bp->SetThreadID(m_thread.GetID()); 63 m_return_bp_id = return_bp->GetID(); 64 } 65 } 66 67 m_stack_depth = m_thread.GetStackFrameCount() - frame_idx; 68 } 69 70 ThreadPlanStepOut::~ThreadPlanStepOut () 71 { 72 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 73 m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id); 74 } 75 76 void 77 ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level) 78 { 79 if (level == lldb::eDescriptionLevelBrief) 80 s->Printf ("step out"); 81 else 82 { 83 s->Printf ("Stepping out from address 0x%llx to return address 0x%llx using breakpoint site %d", 84 (uint64_t)m_step_from_insn, 85 (uint64_t)m_return_addr, 86 m_return_bp_id); 87 } 88 } 89 90 bool 91 ThreadPlanStepOut::ValidatePlan (Stream *error) 92 { 93 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 94 return false; 95 else 96 return true; 97 } 98 99 bool 100 ThreadPlanStepOut::PlanExplainsStop () 101 { 102 // We don't explain signals or breakpoints (breakpoints that handle stepping in or 103 // out will be handled by a child plan. 104 StopInfoSP stop_info_sp = GetPrivateStopReason(); 105 if (stop_info_sp) 106 { 107 StopReason reason = stop_info_sp->GetStopReason(); 108 switch (reason) 109 { 110 case eStopReasonBreakpoint: 111 { 112 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened... 113 BreakpointSiteSP site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info_sp->GetValue())); 114 if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id)) 115 { 116 const uint32_t num_frames = m_thread.GetStackFrameCount(); 117 if (m_stack_depth > num_frames) 118 SetPlanComplete(); 119 120 // If there was only one owner, then we're done. But if we also hit some 121 // user breakpoint on our way out, we should mark ourselves as done, but 122 // also not claim to explain the stop, since it is more important to report 123 // the user breakpoint than the step out completion. 124 125 if (site_sp->GetNumberOfOwners() == 1) 126 return true; 127 128 } 129 return false; 130 } 131 case eStopReasonWatchpoint: 132 case eStopReasonSignal: 133 case eStopReasonException: 134 return false; 135 136 default: 137 return true; 138 } 139 } 140 return true; 141 } 142 143 bool 144 ThreadPlanStepOut::ShouldStop (Event *event_ptr) 145 { 146 if (IsPlanComplete() || m_stack_depth > m_thread.GetStackFrameCount()) 147 { 148 SetPlanComplete(); 149 return true; 150 } 151 else 152 return false; 153 } 154 155 bool 156 ThreadPlanStepOut::StopOthers () 157 { 158 return m_stop_others; 159 } 160 161 StateType 162 ThreadPlanStepOut::GetPlanRunState () 163 { 164 return eStateRunning; 165 } 166 167 bool 168 ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan) 169 { 170 ThreadPlan::WillResume (resume_state, current_plan); 171 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 172 return false; 173 174 if (current_plan) 175 { 176 Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get(); 177 if (return_bp != NULL) 178 return_bp->SetEnabled (true); 179 } 180 return true; 181 } 182 183 bool 184 ThreadPlanStepOut::WillStop () 185 { 186 Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get(); 187 if (return_bp != NULL) 188 return_bp->SetEnabled (false); 189 return true; 190 } 191 192 bool 193 ThreadPlanStepOut::MischiefManaged () 194 { 195 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 196 { 197 // If I couldn't set this breakpoint, then I'm just going to jettison myself. 198 return true; 199 } 200 else if (IsPlanComplete()) 201 { 202 // Did I reach my breakpoint? If so I'm done. 203 // 204 // I also check the stack depth, since if we've blown past the breakpoint for some 205 // reason and we're now stopping for some other reason altogether, then we're done 206 // with this step out operation. 207 208 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 209 if (log) 210 log->Printf("Completed step out plan."); 211 m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_return_bp_id); 212 m_return_bp_id = LLDB_INVALID_BREAK_ID; 213 ThreadPlan::MischiefManaged (); 214 return true; 215 } 216 else 217 { 218 return false; 219 } 220 } 221 222