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