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 LLDB_LOGF(log, "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 LLDB_LOGF(log, "Found step through plan from 0x%" PRIx64 ": %s", 107 current_address, s.GetData()); 108 } else { 109 LLDB_LOGF(log, 110 "Couldn't find step through plan from address 0x%" PRIx64 ".", 111 current_address); 112 } 113 } 114 } 115 116 void ThreadPlanStepThrough::GetDescription(Stream *s, 117 lldb::DescriptionLevel level) { 118 if (level == lldb::eDescriptionLevelBrief) 119 s->Printf("Step through"); 120 else { 121 s->PutCString("Stepping through trampoline code from: "); 122 DumpAddress(s->AsRawOstream(), m_start_address, sizeof(addr_t)); 123 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { 124 s->Printf(" with backstop breakpoint ID: %d at address: ", 125 m_backstop_bkpt_id); 126 DumpAddress(s->AsRawOstream(), m_backstop_addr, sizeof(addr_t)); 127 } else 128 s->PutCString(" unable to set a backstop breakpoint."); 129 } 130 } 131 132 bool ThreadPlanStepThrough::ValidatePlan(Stream *error) { 133 if (m_could_not_resolve_hw_bp) { 134 if (error) 135 error->PutCString( 136 "Could not create hardware breakpoint for thread plan."); 137 return false; 138 } 139 140 if (m_backstop_bkpt_id == LLDB_INVALID_BREAK_ID) { 141 if (error) 142 error->PutCString("Could not create backstop breakpoint."); 143 return false; 144 } 145 146 if (!m_sub_plan_sp.get()) { 147 if (error) 148 error->PutCString("Does not have a subplan."); 149 return false; 150 } 151 152 return true; 153 } 154 155 bool ThreadPlanStepThrough::DoPlanExplainsStop(Event *event_ptr) { 156 // If we have a sub-plan, it will have been asked first if we explain the 157 // stop, and we won't get asked. The only time we would be the one directly 158 // asked this question is if we hit our backstop breakpoint. 159 160 return HitOurBackstopBreakpoint(); 161 } 162 163 bool ThreadPlanStepThrough::ShouldStop(Event *event_ptr) { 164 // If we've already marked ourselves done, then we're done... 165 if (IsPlanComplete()) 166 return true; 167 168 // First, did we hit the backstop breakpoint? 169 if (HitOurBackstopBreakpoint()) { 170 SetPlanComplete(true); 171 return true; 172 } 173 174 // If we don't have a sub-plan, then we're also done (can't see how we would 175 // ever get here without a plan, but just in case. 176 177 if (!m_sub_plan_sp) { 178 SetPlanComplete(); 179 return true; 180 } 181 182 // If the current sub plan is not done, we don't want to stop. Actually, we 183 // probably won't ever get here in this state, since we generally won't get 184 // asked any questions if out current sub-plan is not done... 185 if (!m_sub_plan_sp->IsPlanComplete()) 186 return false; 187 188 // If our current sub plan failed, then let's just run to our backstop. If 189 // we can't do that then just stop. 190 if (!m_sub_plan_sp->PlanSucceeded()) { 191 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { 192 m_sub_plan_sp.reset(); 193 return false; 194 } else { 195 SetPlanComplete(false); 196 return true; 197 } 198 } 199 200 // Next see if there is a specific step through plan at our current pc (these 201 // might chain, for instance stepping through a dylib trampoline to the objc 202 // dispatch function...) 203 LookForPlanToStepThroughFromCurrentPC(); 204 if (m_sub_plan_sp) { 205 PushPlan(m_sub_plan_sp); 206 return false; 207 } else { 208 SetPlanComplete(); 209 return true; 210 } 211 } 212 213 bool ThreadPlanStepThrough::StopOthers() { return m_stop_others; } 214 215 StateType ThreadPlanStepThrough::GetPlanRunState() { return eStateRunning; } 216 217 bool ThreadPlanStepThrough::DoWillResume(StateType resume_state, 218 bool current_plan) { 219 return true; 220 } 221 222 bool ThreadPlanStepThrough::WillStop() { return true; } 223 224 void ThreadPlanStepThrough::ClearBackstopBreakpoint() { 225 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { 226 m_thread.GetProcess()->GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id); 227 m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; 228 m_could_not_resolve_hw_bp = false; 229 } 230 } 231 232 bool ThreadPlanStepThrough::MischiefManaged() { 233 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 234 235 if (!IsPlanComplete()) { 236 return false; 237 } else { 238 LLDB_LOGF(log, "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