130fdc8d8SChris Lattner //===-- ThreadPlanStepInstruction.cpp ---------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner 1030fdc8d8SChris Lattner // C Includes 1130fdc8d8SChris Lattner // C++ Includes 1230fdc8d8SChris Lattner // Other libraries and framework includes 1330fdc8d8SChris Lattner // Project includes 14*e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlanStepInstruction.h" 1530fdc8d8SChris Lattner #include "lldb/Core/Log.h" 1630fdc8d8SChris Lattner #include "lldb/Core/Stream.h" 1730fdc8d8SChris Lattner #include "lldb/Target/Process.h" 18f4b47e15SGreg Clayton #include "lldb/Target/RegisterContext.h" 19f4b47e15SGreg Clayton #include "lldb/Target/RegisterContext.h" 20f4b47e15SGreg Clayton #include "lldb/Target/StopInfo.h" 21f4b47e15SGreg Clayton #include "lldb/Target/Target.h" 2230fdc8d8SChris Lattner 2330fdc8d8SChris Lattner using namespace lldb; 2430fdc8d8SChris Lattner using namespace lldb_private; 2530fdc8d8SChris Lattner 2630fdc8d8SChris Lattner //---------------------------------------------------------------------- 2730fdc8d8SChris Lattner // ThreadPlanStepInstruction: Step over the current instruction 2830fdc8d8SChris Lattner //---------------------------------------------------------------------- 2930fdc8d8SChris Lattner 3030fdc8d8SChris Lattner ThreadPlanStepInstruction::ThreadPlanStepInstruction 3130fdc8d8SChris Lattner ( 3230fdc8d8SChris Lattner Thread &thread, 3330fdc8d8SChris Lattner bool step_over, 3430fdc8d8SChris Lattner bool stop_other_threads, 3530fdc8d8SChris Lattner Vote stop_vote, 3630fdc8d8SChris Lattner Vote run_vote 3730fdc8d8SChris Lattner ) : 38b01e742aSJim Ingham ThreadPlan (ThreadPlan::eKindStepInstruction, "Step over single instruction", thread, stop_vote, run_vote), 3930fdc8d8SChris Lattner m_instruction_addr (0), 401ee0d4f7SBenjamin Kramer m_stop_other_threads (stop_other_threads), 416b35c86fSJim Ingham m_step_over (step_over) 421ee0d4f7SBenjamin Kramer { 437a88ec9aSJim Ingham m_takes_iteration_count = true; 447a88ec9aSJim Ingham SetUpState(); 4530fdc8d8SChris Lattner } 4630fdc8d8SChris Lattner 47*e65b2cf2SEugene Zelenko ThreadPlanStepInstruction::~ThreadPlanStepInstruction() = default; 4830fdc8d8SChris Lattner 4930fdc8d8SChris Lattner void 507a88ec9aSJim Ingham ThreadPlanStepInstruction::SetUpState() 517a88ec9aSJim Ingham { 527a88ec9aSJim Ingham m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0); 537a88ec9aSJim Ingham StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0)); 547a88ec9aSJim Ingham m_stack_id = start_frame_sp->GetStackID(); 557a88ec9aSJim Ingham 56*e65b2cf2SEugene Zelenko m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr; 577a88ec9aSJim Ingham 587a88ec9aSJim Ingham StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1); 597a88ec9aSJim Ingham if (parent_frame_sp) 607a88ec9aSJim Ingham m_parent_frame_id = parent_frame_sp->GetStackID(); 617a88ec9aSJim Ingham } 627a88ec9aSJim Ingham 637a88ec9aSJim Ingham void 6430fdc8d8SChris Lattner ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level) 6530fdc8d8SChris Lattner { 6630fdc8d8SChris Lattner if (level == lldb::eDescriptionLevelBrief) 6730fdc8d8SChris Lattner { 6830fdc8d8SChris Lattner if (m_step_over) 6930fdc8d8SChris Lattner s->Printf ("instruction step over"); 7030fdc8d8SChris Lattner else 7130fdc8d8SChris Lattner s->Printf ("instruction step into"); 7230fdc8d8SChris Lattner } 7330fdc8d8SChris Lattner else 7430fdc8d8SChris Lattner { 7530fdc8d8SChris Lattner s->Printf ("Stepping one instruction past "); 7630fdc8d8SChris Lattner s->Address(m_instruction_addr, sizeof (addr_t)); 77a7d4822cSJim Ingham if (!m_start_has_symbol) 78a7d4822cSJim Ingham s->Printf(" which has no symbol"); 79a7d4822cSJim Ingham 8030fdc8d8SChris Lattner if (m_step_over) 8130fdc8d8SChris Lattner s->Printf(" stepping over calls"); 8230fdc8d8SChris Lattner else 8330fdc8d8SChris Lattner s->Printf(" stepping into calls"); 8430fdc8d8SChris Lattner } 8530fdc8d8SChris Lattner } 8630fdc8d8SChris Lattner 8730fdc8d8SChris Lattner bool 8830fdc8d8SChris Lattner ThreadPlanStepInstruction::ValidatePlan (Stream *error) 8930fdc8d8SChris Lattner { 9030fdc8d8SChris Lattner // Since we read the instruction we're stepping over from the thread, 9130fdc8d8SChris Lattner // this plan will always work. 9230fdc8d8SChris Lattner return true; 9330fdc8d8SChris Lattner } 9430fdc8d8SChris Lattner 9530fdc8d8SChris Lattner bool 96221d51cfSJim Ingham ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr) 9730fdc8d8SChris Lattner { 9860c4118cSJim Ingham StopInfoSP stop_info_sp = GetPrivateStopInfo (); 99b15bfc75SJim Ingham if (stop_info_sp) 10030fdc8d8SChris Lattner { 101b15bfc75SJim Ingham StopReason reason = stop_info_sp->GetStopReason(); 102*e65b2cf2SEugene Zelenko return (reason == eStopReasonTrace || reason == eStopReasonNone); 10330fdc8d8SChris Lattner } 10430fdc8d8SChris Lattner return false; 10530fdc8d8SChris Lattner } 10630fdc8d8SChris Lattner 10730fdc8d8SChris Lattner bool 1087a88ec9aSJim Ingham ThreadPlanStepInstruction::IsPlanStale () 1097a88ec9aSJim Ingham { 1107a88ec9aSJim Ingham Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 1117a88ec9aSJim Ingham StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 1127a88ec9aSJim Ingham if (cur_frame_id == m_stack_id) 1137a88ec9aSJim Ingham { 114*e65b2cf2SEugene Zelenko return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr); 1157a88ec9aSJim Ingham } 1167a88ec9aSJim Ingham else if (cur_frame_id < m_stack_id) 1177a88ec9aSJim Ingham { 1187a88ec9aSJim Ingham // If the current frame is younger than the start frame and we are stepping over, then we need to continue, 1197a88ec9aSJim Ingham // but if we are doing just one step, we're done. 120*e65b2cf2SEugene Zelenko return !m_step_over; 1217a88ec9aSJim Ingham } 1227a88ec9aSJim Ingham else 1237a88ec9aSJim Ingham { 1247a88ec9aSJim Ingham if (log) 1257a88ec9aSJim Ingham { 1267a88ec9aSJim Ingham log->Printf ("ThreadPlanStepInstruction::IsPlanStale - Current frame is older than start frame, plan is stale."); 1277a88ec9aSJim Ingham } 1287a88ec9aSJim Ingham return true; 1297a88ec9aSJim Ingham } 1307a88ec9aSJim Ingham } 1317a88ec9aSJim Ingham 1327a88ec9aSJim Ingham bool 13330fdc8d8SChris Lattner ThreadPlanStepInstruction::ShouldStop (Event *event_ptr) 13430fdc8d8SChris Lattner { 13530fdc8d8SChris Lattner if (m_step_over) 13630fdc8d8SChris Lattner { 1375160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 1386b35c86fSJim Ingham 139c0b4d5a1SJim Ingham StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0); 140c0b4d5a1SJim Ingham if (!cur_frame_sp) 141c0b4d5a1SJim Ingham { 142c0b4d5a1SJim Ingham if (log) 143c0b4d5a1SJim Ingham log->Printf ("ThreadPlanStepInstruction couldn't get the 0th frame, stopping."); 144c0b4d5a1SJim Ingham SetPlanComplete(); 145c0b4d5a1SJim Ingham return true; 146c0b4d5a1SJim Ingham } 147c0b4d5a1SJim Ingham 148c0b4d5a1SJim Ingham StackID cur_frame_zero_id = cur_frame_sp->GetStackID(); 1496b35c86fSJim Ingham 1506b35c86fSJim Ingham if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) 15130fdc8d8SChris Lattner { 15230fdc8d8SChris Lattner if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) 15330fdc8d8SChris Lattner { 1547a88ec9aSJim Ingham if (--m_iteration_count <= 0) 1557a88ec9aSJim Ingham { 15630fdc8d8SChris Lattner SetPlanComplete(); 15730fdc8d8SChris Lattner return true; 15830fdc8d8SChris Lattner } 15930fdc8d8SChris Lattner else 1607a88ec9aSJim Ingham { 1617a88ec9aSJim Ingham // We are still stepping, reset the start pc, and in case we've stepped out, 1627a88ec9aSJim Ingham // reset the current stack id. 1637a88ec9aSJim Ingham SetUpState(); 1647a88ec9aSJim Ingham return false; 1657a88ec9aSJim Ingham } 1667a88ec9aSJim Ingham } 1677a88ec9aSJim Ingham else 16830fdc8d8SChris Lattner return false; 16930fdc8d8SChris Lattner } 17030fdc8d8SChris Lattner else 17130fdc8d8SChris Lattner { 17230fdc8d8SChris Lattner // We've stepped in, step back out again: 173b57e4a1bSJason Molenda StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get(); 17430fdc8d8SChris Lattner if (return_frame) 17530fdc8d8SChris Lattner { 176a7d4822cSJim Ingham if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol) 177886a3e2cSJim Ingham { 178c0b4d5a1SJim Ingham // next-instruction shouldn't step out of inlined functions. But we may have stepped into a 179c0b4d5a1SJim Ingham // real function that starts with an inlined function, and we do want to step out of that... 180c0b4d5a1SJim Ingham 181c0b4d5a1SJim Ingham if (cur_frame_sp->IsInlined()) 182c0b4d5a1SJim Ingham { 183c0b4d5a1SJim Ingham StackFrameSP parent_frame_sp = m_thread.GetFrameWithStackID(m_stack_id); 184c0b4d5a1SJim Ingham 185c0b4d5a1SJim Ingham if(parent_frame_sp && parent_frame_sp->GetConcreteFrameIndex() == cur_frame_sp->GetConcreteFrameIndex()) 186c0b4d5a1SJim Ingham { 187c0b4d5a1SJim Ingham SetPlanComplete(); 188c0b4d5a1SJim Ingham if (log) 189c0b4d5a1SJim Ingham { 190c0b4d5a1SJim Ingham log->Printf("Frame we stepped into is inlined into the frame we were stepping from, stopping."); 191c0b4d5a1SJim Ingham } 192c0b4d5a1SJim Ingham return true; 193c0b4d5a1SJim Ingham } 194c0b4d5a1SJim Ingham } 195c0b4d5a1SJim Ingham 19630fdc8d8SChris Lattner if (log) 19730fdc8d8SChris Lattner { 19830fdc8d8SChris Lattner StreamString s; 19930fdc8d8SChris Lattner s.PutCString ("Stepped in to: "); 2009da7bd07SGreg Clayton addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); 2011ac04c30SGreg Clayton s.Address (stop_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); 20230fdc8d8SChris Lattner s.PutCString (" stepping out to: "); 2039da7bd07SGreg Clayton addr_t return_addr = return_frame->GetRegisterContext()->GetPC(); 2041ac04c30SGreg Clayton s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); 20530fdc8d8SChris Lattner log->Printf("%s.", s.GetData()); 20630fdc8d8SChris Lattner } 2074a58e968SJim Ingham 2084a58e968SJim Ingham // StepInstruction should probably have the tri-state RunMode, but for now it is safer to 2094a58e968SJim Ingham // run others. 2104a58e968SJim Ingham const bool stop_others = false; 2114b4b2478SJim Ingham m_thread.QueueThreadPlanForStepOutNoShouldStop(false, 212*e65b2cf2SEugene Zelenko nullptr, 21364e7ead1SJim Ingham true, 2144a58e968SJim Ingham stop_others, 21564e7ead1SJim Ingham eVoteNo, 21664e7ead1SJim Ingham eVoteNoOpinion, 21764e7ead1SJim Ingham 0); 21830fdc8d8SChris Lattner return false; 21930fdc8d8SChris Lattner } 22030fdc8d8SChris Lattner else 22130fdc8d8SChris Lattner { 22230fdc8d8SChris Lattner if (log) 223886a3e2cSJim Ingham { 224a7d4822cSJim Ingham log->PutCString("The stack id we are stepping in changed, but our parent frame did not when stepping from code with no symbols. " 225886a3e2cSJim Ingham "We are probably just confused about where we are, stopping."); 226886a3e2cSJim Ingham } 227886a3e2cSJim Ingham SetPlanComplete(); 228886a3e2cSJim Ingham return true; 229886a3e2cSJim Ingham } 230886a3e2cSJim Ingham } 231886a3e2cSJim Ingham else 232886a3e2cSJim Ingham { 233886a3e2cSJim Ingham if (log) 23430fdc8d8SChris Lattner log->Printf("Could not find previous frame, stopping."); 23530fdc8d8SChris Lattner SetPlanComplete(); 23630fdc8d8SChris Lattner return true; 23730fdc8d8SChris Lattner } 23830fdc8d8SChris Lattner } 23930fdc8d8SChris Lattner } 24030fdc8d8SChris Lattner else 24130fdc8d8SChris Lattner { 24230fdc8d8SChris Lattner if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) 24330fdc8d8SChris Lattner { 2447a88ec9aSJim Ingham if (--m_iteration_count <= 0) 2457a88ec9aSJim Ingham { 24630fdc8d8SChris Lattner SetPlanComplete(); 24730fdc8d8SChris Lattner return true; 24830fdc8d8SChris Lattner } 24930fdc8d8SChris Lattner else 2507a88ec9aSJim Ingham { 2517a88ec9aSJim Ingham // We are still stepping, reset the start pc, and in case we've stepped in or out, 2527a88ec9aSJim Ingham // reset the current stack id. 2537a88ec9aSJim Ingham SetUpState(); 2547a88ec9aSJim Ingham return false; 2557a88ec9aSJim Ingham } 2567a88ec9aSJim Ingham } 2577a88ec9aSJim Ingham else 25830fdc8d8SChris Lattner return false; 25930fdc8d8SChris Lattner } 26030fdc8d8SChris Lattner } 26130fdc8d8SChris Lattner 26230fdc8d8SChris Lattner bool 26330fdc8d8SChris Lattner ThreadPlanStepInstruction::StopOthers () 26430fdc8d8SChris Lattner { 26530fdc8d8SChris Lattner return m_stop_other_threads; 26630fdc8d8SChris Lattner } 26730fdc8d8SChris Lattner 26830fdc8d8SChris Lattner StateType 26906e827ccSJim Ingham ThreadPlanStepInstruction::GetPlanRunState () 27030fdc8d8SChris Lattner { 27130fdc8d8SChris Lattner return eStateStepping; 27230fdc8d8SChris Lattner } 27330fdc8d8SChris Lattner 27430fdc8d8SChris Lattner bool 27530fdc8d8SChris Lattner ThreadPlanStepInstruction::WillStop () 27630fdc8d8SChris Lattner { 27730fdc8d8SChris Lattner return true; 27830fdc8d8SChris Lattner } 27930fdc8d8SChris Lattner 28030fdc8d8SChris Lattner bool 28130fdc8d8SChris Lattner ThreadPlanStepInstruction::MischiefManaged () 28230fdc8d8SChris Lattner { 28330fdc8d8SChris Lattner if (IsPlanComplete()) 28430fdc8d8SChris Lattner { 2855160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 28630fdc8d8SChris Lattner if (log) 28730fdc8d8SChris Lattner log->Printf("Completed single instruction step plan."); 28830fdc8d8SChris Lattner ThreadPlan::MischiefManaged (); 28930fdc8d8SChris Lattner return true; 29030fdc8d8SChris Lattner } 29130fdc8d8SChris Lattner else 29230fdc8d8SChris Lattner { 29330fdc8d8SChris Lattner return false; 29430fdc8d8SChris Lattner } 29530fdc8d8SChris Lattner } 296