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