LLDB  mainline
ThreadPlanStepInstruction.cpp
Go to the documentation of this file.
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 
10 #include "lldb/Target/Process.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) {
33  SetUpState();
34 }
35 
37 
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 
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 
82  // Since we read the instruction we're stepping over from the thread, this
83  // plan will always work.
84  return true;
85 }
86 
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 
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 
125  if (m_step_over) {
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;
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 
238  return eStateStepping;
239 }
240 
241 bool ThreadPlanStepInstruction::WillStop() { return true; }
242 
244  if (IsPlanComplete()) {
246  if (log)
247  log->Printf("Completed single instruction step plan.");
249  return true;
250  } else {
251  return false;
252  }
253 }
void Address(uint64_t addr, uint32_t addr_size, const char *prefix=nullptr, const char *suffix=nullptr)
Output an address value to this stream.
Definition: Stream.cpp:79
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
lldb::StopInfoSP GetPrivateStopInfo()
Definition: ThreadPlan.h:564
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop(bool abort_other_plans, SymbolContext *addr_context, bool first_insn, bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx, Status &status, bool continue_to_next_branch=false)
Queue the plan used to step out of the function at the current PC of a thread.
Definition: Thread.cpp:1454
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
virtual lldb::StackFrameSP GetFrameWithStackID(const StackID &stack_id)
Definition: Thread.h:421
bool DoPlanExplainsStop(Event *event_ptr) override
const char * GetData() const
Definition: StreamString.h:43
bool ValidatePlan(Stream *error) override
Returns whether this plan could be successfully created.
void GetDescription(Stream *s, lldb::DescriptionLevel level) override
Print a description of this thread to the stream s.
lldb::RegisterContextSP GetRegisterContext()
Get the RegisterContext for this frame, if possible.
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:57
lldb::TargetSP CalculateTarget() override
Definition: Thread.cpp:1584
virtual lldb::RegisterContextSP GetRegisterContext()=0
virtual bool MischiefManaged()
Definition: ThreadPlan.cpp:57
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
bool Success() const
Test for success condition.
Definition: Status.cpp:287
Process or thread is in the process of stepping and can not be examined.
void SetPlanComplete(bool success=true)
Definition: ThreadPlan.cpp:51
uint64_t addr_t
Definition: lldb-types.h:83
void PutCString(const char *cstr)
Definition: Log.cpp:109
Definition: SBAddress.h:15
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:130
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:395
#define LIBLLDB_LOG_STEP
Definition: Logging.h:21
void Printf(const char *format,...) __attribute__((format(printf
Definition: Log.cpp:113
This base class provides an interface to stack frames.
Definition: StackFrame.h:40