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