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 26 using namespace lldb; 27 using 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 35 ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, 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_stop_others (stop_others) 41 { 42 43 LookForPlanToStepThroughFromCurrentPC(); 44 45 // If we don't get a valid step through plan, don't bother to set up a backstop. 46 if (m_sub_plan_sp) 47 { 48 m_start_address = GetThread().GetRegisterContext()->GetPC(0); 49 m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 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.GetFrameWithConcreteFrameIndex(1)); 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 } 65 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 66 if (log) 67 { 68 log->Printf ("Setting backstop breakpoint %d at address: 0x%llx", m_backstop_bkpt_id, m_backstop_addr); 69 } 70 } 71 } 72 } 73 74 ThreadPlanStepThrough::~ThreadPlanStepThrough () 75 { 76 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) 77 { 78 m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id); 79 m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; 80 } 81 } 82 83 void 84 ThreadPlanStepThrough::DidPush () 85 { 86 if (m_sub_plan_sp) 87 PushPlan(m_sub_plan_sp); 88 } 89 90 void 91 ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() 92 { 93 m_sub_plan_sp = m_thread.GetProcess()->GetDynamicLoader()->GetStepThroughTrampolinePlan (m_thread, m_stop_others); 94 // If that didn't come up with anything, try the ObjC runtime plugin: 95 if (!m_sub_plan_sp.get()) 96 { 97 ObjCLanguageRuntime *objc_runtime = m_thread.GetProcess()->GetObjCLanguageRuntime(); 98 if (objc_runtime) 99 m_sub_plan_sp = objc_runtime->GetStepThroughTrampolinePlan (m_thread, m_stop_others); 100 } 101 102 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 103 if (log) 104 { 105 lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0); 106 if (m_sub_plan_sp) 107 { 108 StreamString s; 109 m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); 110 log->Printf ("Found step through plan from 0x%llx: %s", current_address, s.GetData()); 111 } 112 else 113 { 114 log->Printf ("Couldn't find step through plan from address 0x%llx.", current_address); 115 } 116 } 117 } 118 119 void 120 ThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level) 121 { 122 if (level == lldb::eDescriptionLevelBrief) 123 s->Printf ("Step through"); 124 else 125 { 126 s->PutCString ("Stepping through trampoline code from: "); 127 s->Address(m_start_address, sizeof (addr_t)); 128 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) 129 { 130 s->Printf (" with backstop breakpoint id: %d at address: ", m_backstop_bkpt_id); 131 s->Address (m_backstop_addr, sizeof (addr_t)); 132 } 133 else 134 s->PutCString (" unable to set a backstop breakpoint."); 135 } 136 } 137 138 bool 139 ThreadPlanStepThrough::ValidatePlan (Stream *error) 140 { 141 return m_sub_plan_sp.get() != NULL; 142 } 143 144 bool 145 ThreadPlanStepThrough::PlanExplainsStop () 146 { 147 // If we have a sub-plan, it will have been asked first if we explain the stop, and 148 // we won't get asked. The only time we would be the one directly asked this question 149 // is if we hit our backstop breakpoint. 150 151 if (HitOurBackstopBreakpoint()) 152 return true; 153 else 154 return false; 155 } 156 157 bool 158 ThreadPlanStepThrough::ShouldStop (Event *event_ptr) 159 { 160 // If we've already marked ourselves done, then we're done... 161 if (IsPlanComplete()) 162 return true; 163 164 // If we don't have a sub-plan, then we're also done (can't see how we would ever get here 165 // without a plan, but just in case. 166 167 if (!m_sub_plan_sp) 168 { 169 SetPlanComplete(); 170 return true; 171 } 172 173 // First, did we hit the backstop breakpoint? 174 if (HitOurBackstopBreakpoint()) 175 { 176 SetPlanComplete(); 177 return true; 178 } 179 180 181 // If the current sub plan is not done, we don't want to stop. Actually, we probably won't 182 // ever get here in this state, since we generally won't get asked any questions if out 183 // current sub-plan is not done... 184 if (!m_sub_plan_sp->IsPlanComplete()) 185 return false; 186 187 // Next see if there is a specific step through plan at our current pc (these might 188 // chain, for instance stepping through a dylib trampoline to the objc dispatch function...) 189 LookForPlanToStepThroughFromCurrentPC(); 190 if (m_sub_plan_sp) 191 { 192 PushPlan (m_sub_plan_sp); 193 return false; 194 } 195 else 196 { 197 SetPlanComplete(); 198 return true; 199 } 200 } 201 202 bool 203 ThreadPlanStepThrough::StopOthers () 204 { 205 return m_stop_others; 206 } 207 208 StateType 209 ThreadPlanStepThrough::GetPlanRunState () 210 { 211 return eStateStepping; 212 } 213 214 bool 215 ThreadPlanStepThrough::WillResume (StateType resume_state, bool current_plan) 216 { 217 ThreadPlan::WillResume(resume_state, current_plan); 218 return true; 219 } 220 221 bool 222 ThreadPlanStepThrough::WillStop () 223 { 224 return true; 225 } 226 227 bool 228 ThreadPlanStepThrough::MischiefManaged () 229 { 230 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 231 232 // ShouldStop will call HappyToStopHere, which will set the plan to complete if 233 // we're done. So we can just check that here. 234 235 if (!IsPlanComplete()) 236 { 237 return false; 238 } 239 else 240 { 241 if (log) 242 log->Printf("Completed step through step plan."); 243 ThreadPlan::MischiefManaged (); 244 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) 245 { 246 m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id); 247 m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; 248 } 249 return true; 250 } 251 } 252 253 bool 254 ThreadPlanStepThrough::HitOurBackstopBreakpoint() 255 { 256 StopInfoSP stop_info_sp(m_thread.GetStopInfo()); 257 if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) 258 { 259 break_id_t stop_value = (break_id_t) stop_info_sp->GetValue(); 260 BreakpointSiteSP cur_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value); 261 if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) 262 { 263 StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 264 265 if (cur_frame_zero_id == m_stack_id) 266 { 267 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 268 if (log) 269 log->PutCString ("ThreadPlanStepThrough hit backstop breakpoint."); 270 return true; 271 } 272 } 273 } 274 return false; 275 } 276 277