ThreadPlanStepOut.cpp revision a14755aaab93eaa3e60ae10e75cb5c4bd3244fbb
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 24using namespace lldb; 25using namespace lldb_private; 26 27//---------------------------------------------------------------------- 28// ThreadPlanStepOut: Step out of the current frame 29//---------------------------------------------------------------------- 30 31ThreadPlanStepOut::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 70ThreadPlanStepOut::~ThreadPlanStepOut () 71{ 72 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 73 m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id); 74} 75 76void 77ThreadPlanStepOut::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 90bool 91ThreadPlanStepOut::ValidatePlan (Stream *error) 92{ 93 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 94 return false; 95 else 96 return true; 97} 98 99bool 100ThreadPlanStepOut::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 143bool 144ThreadPlanStepOut::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 155bool 156ThreadPlanStepOut::StopOthers () 157{ 158 return m_stop_others; 159} 160 161StateType 162ThreadPlanStepOut::GetPlanRunState () 163{ 164 return eStateRunning; 165} 166 167bool 168ThreadPlanStepOut::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 183bool 184ThreadPlanStepOut::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 192bool 193ThreadPlanStepOut::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