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