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