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