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