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