1 //===-- ThreadPlanStepInstruction.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/ThreadPlanStepInstruction.h" 10 #include "lldb/Target/Process.h" 11 #include "lldb/Target/RegisterContext.h" 12 #include "lldb/Target/RegisterContext.h" 13 #include "lldb/Target/StopInfo.h" 14 #include "lldb/Target/Target.h" 15 #include "lldb/Utility/Log.h" 16 #include "lldb/Utility/Stream.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 // ThreadPlanStepInstruction: Step over the current instruction 22 23 ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread, 24 bool step_over, 25 bool stop_other_threads, 26 Vote stop_vote, 27 Vote run_vote) 28 : ThreadPlan(ThreadPlan::eKindStepInstruction, 29 "Step over single instruction", thread, stop_vote, run_vote), 30 m_instruction_addr(0), m_stop_other_threads(stop_other_threads), 31 m_step_over(step_over) { 32 m_takes_iteration_count = true; 33 SetUpState(); 34 } 35 36 ThreadPlanStepInstruction::~ThreadPlanStepInstruction() = default; 37 38 void ThreadPlanStepInstruction::SetUpState() { 39 m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0); 40 StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0)); 41 m_stack_id = start_frame_sp->GetStackID(); 42 43 m_start_has_symbol = 44 start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr; 45 46 StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1); 47 if (parent_frame_sp) 48 m_parent_frame_id = parent_frame_sp->GetStackID(); 49 } 50 51 void ThreadPlanStepInstruction::GetDescription(Stream *s, 52 lldb::DescriptionLevel level) { 53 auto PrintFailureIfAny = [&]() { 54 if (m_status.Success()) 55 return; 56 s->Printf(" failed (%s)", m_status.AsCString()); 57 }; 58 59 if (level == lldb::eDescriptionLevelBrief) { 60 if (m_step_over) 61 s->Printf("instruction step over"); 62 else 63 s->Printf("instruction step into"); 64 65 PrintFailureIfAny(); 66 } else { 67 s->Printf("Stepping one instruction past "); 68 s->Address(m_instruction_addr, sizeof(addr_t)); 69 if (!m_start_has_symbol) 70 s->Printf(" which has no symbol"); 71 72 if (m_step_over) 73 s->Printf(" stepping over calls"); 74 else 75 s->Printf(" stepping into calls"); 76 77 PrintFailureIfAny(); 78 } 79 } 80 81 bool ThreadPlanStepInstruction::ValidatePlan(Stream *error) { 82 // Since we read the instruction we're stepping over from the thread, this 83 // plan will always work. 84 return true; 85 } 86 87 bool ThreadPlanStepInstruction::DoPlanExplainsStop(Event *event_ptr) { 88 StopInfoSP stop_info_sp = GetPrivateStopInfo(); 89 if (stop_info_sp) { 90 StopReason reason = stop_info_sp->GetStopReason(); 91 return (reason == eStopReasonTrace || reason == eStopReasonNone); 92 } 93 return false; 94 } 95 96 bool ThreadPlanStepInstruction::IsPlanStale() { 97 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 98 StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 99 if (cur_frame_id == m_stack_id) { 100 // Set plan Complete when we reach next instruction 101 uint64_t pc = m_thread.GetRegisterContext()->GetPC(0); 102 uint32_t max_opcode_size = m_thread.CalculateTarget() 103 ->GetArchitecture().GetMaximumOpcodeByteSize(); 104 bool next_instruction_reached = (pc > m_instruction_addr) && 105 (pc <= m_instruction_addr + max_opcode_size); 106 if (next_instruction_reached) { 107 SetPlanComplete(); 108 } 109 return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr); 110 } else if (cur_frame_id < m_stack_id) { 111 // If the current frame is younger than the start frame and we are stepping 112 // over, then we need to continue, but if we are doing just one step, we're 113 // done. 114 return !m_step_over; 115 } else { 116 if (log) { 117 log->Printf("ThreadPlanStepInstruction::IsPlanStale - Current frame is " 118 "older than start frame, plan is stale."); 119 } 120 return true; 121 } 122 } 123 124 bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { 125 if (m_step_over) { 126 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 127 128 StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0); 129 if (!cur_frame_sp) { 130 if (log) 131 log->Printf( 132 "ThreadPlanStepInstruction couldn't get the 0th frame, stopping."); 133 SetPlanComplete(); 134 return true; 135 } 136 137 StackID cur_frame_zero_id = cur_frame_sp->GetStackID(); 138 139 if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) { 140 if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) { 141 if (--m_iteration_count <= 0) { 142 SetPlanComplete(); 143 return true; 144 } else { 145 // We are still stepping, reset the start pc, and in case we've 146 // stepped out, reset the current stack id. 147 SetUpState(); 148 return false; 149 } 150 } else 151 return false; 152 } else { 153 // We've stepped in, step back out again: 154 StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get(); 155 if (return_frame) { 156 if (return_frame->GetStackID() != m_parent_frame_id || 157 m_start_has_symbol) { 158 // next-instruction shouldn't step out of inlined functions. But we 159 // may have stepped into a real function that starts with an inlined 160 // function, and we do want to step out of that... 161 162 if (cur_frame_sp->IsInlined()) { 163 StackFrameSP parent_frame_sp = 164 m_thread.GetFrameWithStackID(m_stack_id); 165 166 if (parent_frame_sp && 167 parent_frame_sp->GetConcreteFrameIndex() == 168 cur_frame_sp->GetConcreteFrameIndex()) { 169 SetPlanComplete(); 170 if (log) { 171 log->Printf("Frame we stepped into is inlined into the frame " 172 "we were stepping from, stopping."); 173 } 174 return true; 175 } 176 } 177 178 if (log) { 179 StreamString s; 180 s.PutCString("Stepped in to: "); 181 addr_t stop_addr = 182 m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); 183 s.Address(stop_addr, m_thread.CalculateTarget() 184 ->GetArchitecture() 185 .GetAddressByteSize()); 186 s.PutCString(" stepping out to: "); 187 addr_t return_addr = return_frame->GetRegisterContext()->GetPC(); 188 s.Address(return_addr, m_thread.CalculateTarget() 189 ->GetArchitecture() 190 .GetAddressByteSize()); 191 log->Printf("%s.", s.GetData()); 192 } 193 194 // StepInstruction should probably have the tri-state RunMode, but 195 // for now it is safer to run others. 196 const bool stop_others = false; 197 m_thread.QueueThreadPlanForStepOutNoShouldStop( 198 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, 199 m_status); 200 return false; 201 } else { 202 if (log) { 203 log->PutCString( 204 "The stack id we are stepping in changed, but our parent frame " 205 "did not when stepping from code with no symbols. " 206 "We are probably just confused about where we are, stopping."); 207 } 208 SetPlanComplete(); 209 return true; 210 } 211 } else { 212 if (log) 213 log->Printf("Could not find previous frame, stopping."); 214 SetPlanComplete(); 215 return true; 216 } 217 } 218 } else { 219 lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(0); 220 if (pc_addr != m_instruction_addr) { 221 if (--m_iteration_count <= 0) { 222 SetPlanComplete(); 223 return true; 224 } else { 225 // We are still stepping, reset the start pc, and in case we've stepped 226 // in or out, reset the current stack id. 227 SetUpState(); 228 return false; 229 } 230 } else 231 return false; 232 } 233 } 234 235 bool ThreadPlanStepInstruction::StopOthers() { return m_stop_other_threads; } 236 237 StateType ThreadPlanStepInstruction::GetPlanRunState() { 238 return eStateStepping; 239 } 240 241 bool ThreadPlanStepInstruction::WillStop() { return true; } 242 243 bool ThreadPlanStepInstruction::MischiefManaged() { 244 if (IsPlanComplete()) { 245 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 246 if (log) 247 log->Printf("Completed single instruction step plan."); 248 ThreadPlan::MischiefManaged(); 249 return true; 250 } else { 251 return false; 252 } 253 } 254