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 DumpAddress(s->AsRawOstream(), 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 LLDB_LOGF(log, 118 "ThreadPlanStepInstruction::IsPlanStale - Current frame is " 119 "older than start frame, plan is stale."); 120 } 121 return true; 122 } 123 } 124 125 bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { 126 if (m_step_over) { 127 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 128 129 StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0); 130 if (!cur_frame_sp) { 131 LLDB_LOGF( 132 log, 133 "ThreadPlanStepInstruction couldn't get the 0th frame, stopping."); 134 SetPlanComplete(); 135 return true; 136 } 137 138 StackID cur_frame_zero_id = cur_frame_sp->GetStackID(); 139 140 if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) { 141 if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) { 142 if (--m_iteration_count <= 0) { 143 SetPlanComplete(); 144 return true; 145 } else { 146 // We are still stepping, reset the start pc, and in case we've 147 // stepped out, reset the current stack id. 148 SetUpState(); 149 return false; 150 } 151 } else 152 return false; 153 } else { 154 // We've stepped in, step back out again: 155 StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get(); 156 if (return_frame) { 157 if (return_frame->GetStackID() != m_parent_frame_id || 158 m_start_has_symbol) { 159 // next-instruction shouldn't step out of inlined functions. But we 160 // may have stepped into a real function that starts with an inlined 161 // function, and we do want to step out of that... 162 163 if (cur_frame_sp->IsInlined()) { 164 StackFrameSP parent_frame_sp = 165 m_thread.GetFrameWithStackID(m_stack_id); 166 167 if (parent_frame_sp && 168 parent_frame_sp->GetConcreteFrameIndex() == 169 cur_frame_sp->GetConcreteFrameIndex()) { 170 SetPlanComplete(); 171 if (log) { 172 LLDB_LOGF(log, 173 "Frame we stepped into is inlined into the frame " 174 "we were stepping from, stopping."); 175 } 176 return true; 177 } 178 } 179 180 if (log) { 181 StreamString s; 182 s.PutCString("Stepped in to: "); 183 addr_t stop_addr = 184 m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); 185 DumpAddress(s.AsRawOstream(), stop_addr, 186 m_thread.CalculateTarget() 187 ->GetArchitecture() 188 .GetAddressByteSize()); 189 s.PutCString(" stepping out to: "); 190 addr_t return_addr = return_frame->GetRegisterContext()->GetPC(); 191 DumpAddress(s.AsRawOstream(), return_addr, 192 m_thread.CalculateTarget() 193 ->GetArchitecture() 194 .GetAddressByteSize()); 195 LLDB_LOGF(log, "%s.", s.GetData()); 196 } 197 198 // StepInstruction should probably have the tri-state RunMode, but 199 // for now it is safer to run others. 200 const bool stop_others = false; 201 m_thread.QueueThreadPlanForStepOutNoShouldStop( 202 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, 203 m_status); 204 return false; 205 } else { 206 if (log) { 207 log->PutCString( 208 "The stack id we are stepping in changed, but our parent frame " 209 "did not when stepping from code with no symbols. " 210 "We are probably just confused about where we are, stopping."); 211 } 212 SetPlanComplete(); 213 return true; 214 } 215 } else { 216 LLDB_LOGF(log, "Could not find previous frame, stopping."); 217 SetPlanComplete(); 218 return true; 219 } 220 } 221 } else { 222 lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(0); 223 if (pc_addr != m_instruction_addr) { 224 if (--m_iteration_count <= 0) { 225 SetPlanComplete(); 226 return true; 227 } else { 228 // We are still stepping, reset the start pc, and in case we've stepped 229 // in or out, reset the current stack id. 230 SetUpState(); 231 return false; 232 } 233 } else 234 return false; 235 } 236 } 237 238 bool ThreadPlanStepInstruction::StopOthers() { return m_stop_other_threads; } 239 240 StateType ThreadPlanStepInstruction::GetPlanRunState() { 241 return eStateStepping; 242 } 243 244 bool ThreadPlanStepInstruction::WillStop() { return true; } 245 246 bool ThreadPlanStepInstruction::MischiefManaged() { 247 if (IsPlanComplete()) { 248 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 249 LLDB_LOGF(log, "Completed single instruction step plan."); 250 ThreadPlan::MischiefManaged(); 251 return true; 252 } else { 253 return false; 254 } 255 } 256