1//===-- ThreadPlanStepThrough.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/ThreadPlanStepThrough.h" 11 12// C Includes 13// C++ Includes 14// Other libraries and framework includes 15// Project includes 16#include "lldb/lldb-private-log.h" 17#include "lldb/Core/Log.h" 18#include "lldb/Core/Stream.h" 19#include "lldb/Target/DynamicLoader.h" 20#include "lldb/Target/ObjCLanguageRuntime.h" 21#include "lldb/Target/Process.h" 22#include "lldb/Target/RegisterContext.h" 23#include "lldb/Target/Target.h" 24#include "lldb/Breakpoint/Breakpoint.h" 25 26using namespace lldb; 27using namespace lldb_private; 28 29//---------------------------------------------------------------------- 30// ThreadPlanStepThrough: If the current instruction is a trampoline, step through it 31// If it is the beginning of the prologue of a function, step through that as well. 32// FIXME: At present only handles DYLD trampolines. 33//---------------------------------------------------------------------- 34 35ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, StackID &m_stack_id, bool stop_others) : 36 ThreadPlan (ThreadPlan::eKindStepThrough, "Step through trampolines and prologues", thread, eVoteNoOpinion, eVoteNoOpinion), 37 m_start_address (0), 38 m_backstop_bkpt_id (LLDB_INVALID_BREAK_ID), 39 m_backstop_addr(LLDB_INVALID_ADDRESS), 40 m_return_stack_id (m_stack_id), 41 m_stop_others (stop_others) 42{ 43 44 LookForPlanToStepThroughFromCurrentPC(); 45 46 // If we don't get a valid step through plan, don't bother to set up a backstop. 47 if (m_sub_plan_sp) 48 { 49 m_start_address = GetThread().GetRegisterContext()->GetPC(0); 50 51 // We are going to return back to the concrete frame 1, we might pass by some inlined code that we're in 52 // the middle of by doing this, but it's easier than trying to figure out where the inlined code might return to. 53 54 StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID (m_stack_id); 55 56 if (return_frame_sp) 57 { 58 m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(m_thread.CalculateTarget().get()); 59 Breakpoint *return_bp = m_thread.GetProcess()->GetTarget().CreateBreakpoint (m_backstop_addr, true).get(); 60 if (return_bp != NULL) 61 { 62 return_bp->SetThreadID(m_thread.GetID()); 63 m_backstop_bkpt_id = return_bp->GetID(); 64 return_bp->SetBreakpointKind("step-through-backstop"); 65 } 66 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 67 if (log) 68 { 69 log->Printf ("Setting backstop breakpoint %d at address: 0x%" PRIx64, m_backstop_bkpt_id, m_backstop_addr); 70 } 71 } 72 } 73} 74 75ThreadPlanStepThrough::~ThreadPlanStepThrough () 76{ 77 ClearBackstopBreakpoint (); 78} 79 80void 81ThreadPlanStepThrough::DidPush () 82{ 83 if (m_sub_plan_sp) 84 PushPlan(m_sub_plan_sp); 85} 86 87void 88ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() 89{ 90 m_sub_plan_sp = m_thread.GetProcess()->GetDynamicLoader()->GetStepThroughTrampolinePlan (m_thread, m_stop_others); 91 // If that didn't come up with anything, try the ObjC runtime plugin: 92 if (!m_sub_plan_sp.get()) 93 { 94 ObjCLanguageRuntime *objc_runtime = m_thread.GetProcess()->GetObjCLanguageRuntime(); 95 if (objc_runtime) 96 m_sub_plan_sp = objc_runtime->GetStepThroughTrampolinePlan (m_thread, m_stop_others); 97 } 98 99 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 100 if (log) 101 { 102 lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0); 103 if (m_sub_plan_sp) 104 { 105 StreamString s; 106 m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); 107 log->Printf ("Found step through plan from 0x%" PRIx64 ": %s", current_address, s.GetData()); 108 } 109 else 110 { 111 log->Printf ("Couldn't find step through plan from address 0x%" PRIx64 ".", current_address); 112 } 113 } 114} 115 116void 117ThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level) 118{ 119 if (level == lldb::eDescriptionLevelBrief) 120 s->Printf ("Step through"); 121 else 122 { 123 s->PutCString ("Stepping through trampoline code from: "); 124 s->Address(m_start_address, sizeof (addr_t)); 125 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) 126 { 127 s->Printf (" with backstop breakpoint id: %d at address: ", m_backstop_bkpt_id); 128 s->Address (m_backstop_addr, sizeof (addr_t)); 129 } 130 else 131 s->PutCString (" unable to set a backstop breakpoint."); 132 } 133} 134 135bool 136ThreadPlanStepThrough::ValidatePlan (Stream *error) 137{ 138 return m_sub_plan_sp.get() != NULL; 139} 140 141bool 142ThreadPlanStepThrough::DoPlanExplainsStop (Event *event_ptr) 143{ 144 // If we have a sub-plan, it will have been asked first if we explain the stop, and 145 // we won't get asked. The only time we would be the one directly asked this question 146 // is if we hit our backstop breakpoint. 147 148 if (HitOurBackstopBreakpoint()) 149 return true; 150 else 151 return false; 152} 153 154bool 155ThreadPlanStepThrough::ShouldStop (Event *event_ptr) 156{ 157 // If we've already marked ourselves done, then we're done... 158 if (IsPlanComplete()) 159 return true; 160 161 // First, did we hit the backstop breakpoint? 162 if (HitOurBackstopBreakpoint()) 163 { 164 SetPlanComplete(false); 165 return true; 166 } 167 168 // If we don't have a sub-plan, then we're also done (can't see how we would ever get here 169 // without a plan, but just in case. 170 171 if (!m_sub_plan_sp) 172 { 173 SetPlanComplete(); 174 return true; 175 } 176 177 // If the current sub plan is not done, we don't want to stop. Actually, we probably won't 178 // ever get here in this state, since we generally won't get asked any questions if out 179 // current sub-plan is not done... 180 if (!m_sub_plan_sp->IsPlanComplete()) 181 return false; 182 183 // If our current sub plan failed, then let's just run to our backstop. If we can't do that then just stop. 184 if (!m_sub_plan_sp->PlanSucceeded()) 185 { 186 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) 187 { 188 m_sub_plan_sp.reset(); 189 return false; 190 } 191 else 192 { 193 SetPlanComplete(false); 194 return true; 195 } 196 } 197 198 // Next see if there is a specific step through plan at our current pc (these might 199 // chain, for instance stepping through a dylib trampoline to the objc dispatch function...) 200 LookForPlanToStepThroughFromCurrentPC(); 201 if (m_sub_plan_sp) 202 { 203 PushPlan (m_sub_plan_sp); 204 return false; 205 } 206 else 207 { 208 SetPlanComplete(); 209 return true; 210 } 211} 212 213bool 214ThreadPlanStepThrough::StopOthers () 215{ 216 return m_stop_others; 217} 218 219StateType 220ThreadPlanStepThrough::GetPlanRunState () 221{ 222 return eStateRunning; 223} 224 225bool 226ThreadPlanStepThrough::DoWillResume (StateType resume_state, bool current_plan) 227{ 228 return true; 229} 230 231bool 232ThreadPlanStepThrough::WillStop () 233{ 234 return true; 235} 236 237void 238ThreadPlanStepThrough::ClearBackstopBreakpoint () 239{ 240 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) 241 { 242 m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id); 243 m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; 244 } 245} 246 247bool 248ThreadPlanStepThrough::MischiefManaged () 249{ 250 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 251 252 if (!IsPlanComplete()) 253 { 254 return false; 255 } 256 else 257 { 258 if (log) 259 log->Printf("Completed step through step plan."); 260 261 ClearBackstopBreakpoint (); 262 ThreadPlan::MischiefManaged (); 263 return true; 264 } 265} 266 267bool 268ThreadPlanStepThrough::HitOurBackstopBreakpoint() 269{ 270 StopInfoSP stop_info_sp(m_thread.GetStopInfo()); 271 if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) 272 { 273 break_id_t stop_value = (break_id_t) stop_info_sp->GetValue(); 274 BreakpointSiteSP cur_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value); 275 if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) 276 { 277 StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 278 279 if (cur_frame_zero_id == m_return_stack_id) 280 { 281 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 282 if (log) 283 log->PutCString ("ThreadPlanStepThrough hit backstop breakpoint."); 284 return true; 285 } 286 } 287 } 288 return false; 289} 290 291