1 //===-- ThreadPlanStepThrough.cpp -------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Target/ThreadPlanStepThrough.h" 10 #include "lldb/Breakpoint/Breakpoint.h" 11 #include "lldb/Target/CPPLanguageRuntime.h" 12 #include "lldb/Target/DynamicLoader.h" 13 #include "lldb/Target/ObjCLanguageRuntime.h" 14 #include "lldb/Target/Process.h" 15 #include "lldb/Target/RegisterContext.h" 16 #include "lldb/Target/Target.h" 17 #include "lldb/Utility/Log.h" 18 #include "lldb/Utility/Stream.h" 19 20 using namespace lldb; 21 using namespace lldb_private; 22 23 // ThreadPlanStepThrough: If the current instruction is a trampoline, step 24 // through it If it is the beginning of the prologue of a function, step 25 // through that as well. 26 // FIXME: At present only handles DYLD trampolines. 27 28 ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread, 29 StackID &m_stack_id, 30 bool stop_others) 31 : ThreadPlan(ThreadPlan::eKindStepThrough, 32 "Step through trampolines and prologues", thread, 33 eVoteNoOpinion, eVoteNoOpinion), 34 m_start_address(0), m_backstop_bkpt_id(LLDB_INVALID_BREAK_ID), 35 m_backstop_addr(LLDB_INVALID_ADDRESS), m_return_stack_id(m_stack_id), 36 m_stop_others(stop_others) { 37 LookForPlanToStepThroughFromCurrentPC(); 38 39 // If we don't get a valid step through plan, don't bother to set up a 40 // backstop. 41 if (m_sub_plan_sp) { 42 m_start_address = GetThread().GetRegisterContext()->GetPC(0); 43 44 // We are going to return back to the concrete frame 1, we might pass by 45 // some inlined code that we're in the middle of by doing this, but it's 46 // easier than trying to figure out where the inlined code might return to. 47 48 StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID(m_stack_id); 49 50 if (return_frame_sp) { 51 m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress( 52 m_thread.CalculateTarget().get()); 53 Breakpoint *return_bp = 54 m_thread.GetProcess() 55 ->GetTarget() 56 .CreateBreakpoint(m_backstop_addr, true, false) 57 .get(); 58 59 if (return_bp != nullptr) { 60 if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) 61 m_could_not_resolve_hw_bp = true; 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 if (m_could_not_resolve_hw_bp) { 139 if (error) 140 error->PutCString( 141 "Could not create hardware breakpoint for thread plan."); 142 return false; 143 } 144 145 if (m_backstop_bkpt_id == LLDB_INVALID_BREAK_ID) { 146 if (error) 147 error->PutCString("Could not create backstop breakpoint."); 148 return false; 149 } 150 151 if (!m_sub_plan_sp.get()) { 152 if (error) 153 error->PutCString("Does not have a subplan."); 154 return false; 155 } 156 157 return true; 158 } 159 160 bool ThreadPlanStepThrough::DoPlanExplainsStop(Event *event_ptr) { 161 // If we have a sub-plan, it will have been asked first if we explain the 162 // stop, and we won't get asked. The only time we would be the one directly 163 // asked this question is if we hit our backstop breakpoint. 164 165 return HitOurBackstopBreakpoint(); 166 } 167 168 bool ThreadPlanStepThrough::ShouldStop(Event *event_ptr) { 169 // If we've already marked ourselves done, then we're done... 170 if (IsPlanComplete()) 171 return true; 172 173 // First, did we hit the backstop breakpoint? 174 if (HitOurBackstopBreakpoint()) { 175 SetPlanComplete(true); 176 return true; 177 } 178 179 // If we don't have a sub-plan, then we're also done (can't see how we would 180 // ever get here without a plan, but just in case. 181 182 if (!m_sub_plan_sp) { 183 SetPlanComplete(); 184 return true; 185 } 186 187 // If the current sub plan is not done, we don't want to stop. Actually, we 188 // probably won't ever get here in this state, since we generally won't get 189 // asked any questions if out current sub-plan is not done... 190 if (!m_sub_plan_sp->IsPlanComplete()) 191 return false; 192 193 // If our current sub plan failed, then let's just run to our backstop. If 194 // we can't do that then just stop. 195 if (!m_sub_plan_sp->PlanSucceeded()) { 196 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { 197 m_sub_plan_sp.reset(); 198 return false; 199 } else { 200 SetPlanComplete(false); 201 return true; 202 } 203 } 204 205 // Next see if there is a specific step through plan at our current pc (these 206 // might chain, for instance stepping through a dylib trampoline to the objc 207 // dispatch function...) 208 LookForPlanToStepThroughFromCurrentPC(); 209 if (m_sub_plan_sp) { 210 PushPlan(m_sub_plan_sp); 211 return false; 212 } else { 213 SetPlanComplete(); 214 return true; 215 } 216 } 217 218 bool ThreadPlanStepThrough::StopOthers() { return m_stop_others; } 219 220 StateType ThreadPlanStepThrough::GetPlanRunState() { return eStateRunning; } 221 222 bool ThreadPlanStepThrough::DoWillResume(StateType resume_state, 223 bool current_plan) { 224 return true; 225 } 226 227 bool ThreadPlanStepThrough::WillStop() { return true; } 228 229 void ThreadPlanStepThrough::ClearBackstopBreakpoint() { 230 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { 231 m_thread.GetProcess()->GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id); 232 m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; 233 m_could_not_resolve_hw_bp = false; 234 } 235 } 236 237 bool ThreadPlanStepThrough::MischiefManaged() { 238 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 239 240 if (!IsPlanComplete()) { 241 return false; 242 } else { 243 if (log) 244 log->Printf("Completed step through step plan."); 245 246 ClearBackstopBreakpoint(); 247 ThreadPlan::MischiefManaged(); 248 return true; 249 } 250 } 251 252 bool ThreadPlanStepThrough::HitOurBackstopBreakpoint() { 253 StopInfoSP stop_info_sp(m_thread.GetStopInfo()); 254 if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) { 255 break_id_t stop_value = (break_id_t)stop_info_sp->GetValue(); 256 BreakpointSiteSP cur_site_sp = 257 m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value); 258 if (cur_site_sp && 259 cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) { 260 StackID cur_frame_zero_id = 261 m_thread.GetStackFrameAtIndex(0)->GetStackID(); 262 263 if (cur_frame_zero_id == m_return_stack_id) { 264 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 265 if (log) 266 log->PutCString("ThreadPlanStepThrough hit backstop breakpoint."); 267 return true; 268 } 269 } 270 } 271 return false; 272 } 273