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