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