LLDB  mainline
ThreadPlanStepInstruction.cpp
Go to the documentation of this file.
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-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  Thread &thread = GetThread();
40  m_instruction_addr = thread.GetRegisterContext()->GetPC(0);
41  StackFrameSP start_frame_sp(thread.GetStackFrameAtIndex(0));
42  m_stack_id = start_frame_sp->GetStackID();
43 
45  start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr;
46 
47  StackFrameSP parent_frame_sp = thread.GetStackFrameAtIndex(1);
48  if (parent_frame_sp)
49  m_parent_frame_id = parent_frame_sp->GetStackID();
50 }
51 
53  lldb::DescriptionLevel level) {
54  auto PrintFailureIfAny = [&]() {
55  if (m_status.Success())
56  return;
57  s->Printf(" failed (%s)", m_status.AsCString());
58  };
59 
60  if (level == lldb::eDescriptionLevelBrief) {
61  if (m_step_over)
62  s->Printf("instruction step over");
63  else
64  s->Printf("instruction step into");
65 
66  PrintFailureIfAny();
67  } else {
68  s->Printf("Stepping one instruction past ");
70  if (!m_start_has_symbol)
71  s->Printf(" which has no symbol");
72 
73  if (m_step_over)
74  s->Printf(" stepping over calls");
75  else
76  s->Printf(" stepping into calls");
77 
78  PrintFailureIfAny();
79  }
80 }
81 
83  // Since we read the instruction we're stepping over from the thread, this
84  // plan will always work.
85  return true;
86 }
87 
89  StopInfoSP stop_info_sp = GetPrivateStopInfo();
90  if (stop_info_sp) {
91  StopReason reason = stop_info_sp->GetStopReason();
92  return (reason == eStopReasonTrace || reason == eStopReasonNone);
93  }
94  return false;
95 }
96 
99  Thread &thread = GetThread();
100  StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID();
101  if (cur_frame_id == m_stack_id) {
102  // Set plan Complete when we reach next instruction
103  uint64_t pc = thread.GetRegisterContext()->GetPC(0);
104  uint32_t max_opcode_size =
106  bool next_instruction_reached = (pc > m_instruction_addr) &&
107  (pc <= m_instruction_addr + max_opcode_size);
108  if (next_instruction_reached) {
109  SetPlanComplete();
110  }
111  return (thread.GetRegisterContext()->GetPC(0) != m_instruction_addr);
112  } else if (cur_frame_id < m_stack_id) {
113  // If the current frame is younger than the start frame and we are stepping
114  // over, then we need to continue, but if we are doing just one step, we're
115  // done.
116  return !m_step_over;
117  } else {
118  if (log) {
119  LLDB_LOGF(log,
120  "ThreadPlanStepInstruction::IsPlanStale - Current frame is "
121  "older than start frame, plan is stale.");
122  }
123  return true;
124  }
125 }
126 
128  Thread &thread = GetThread();
129  if (m_step_over) {
131  StackFrameSP cur_frame_sp = thread.GetStackFrameAtIndex(0);
132  if (!cur_frame_sp) {
133  LLDB_LOGF(
134  log,
135  "ThreadPlanStepInstruction couldn't get the 0th frame, stopping.");
136  SetPlanComplete();
137  return true;
138  }
139 
140  StackID cur_frame_zero_id = cur_frame_sp->GetStackID();
141 
142  if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) {
143  if (thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) {
144  if (--m_iteration_count <= 0) {
145  SetPlanComplete();
146  return true;
147  } else {
148  // We are still stepping, reset the start pc, and in case we've
149  // stepped out, reset the current stack id.
150  SetUpState();
151  return false;
152  }
153  } else
154  return false;
155  } else {
156  // We've stepped in, step back out again:
157  StackFrame *return_frame = thread.GetStackFrameAtIndex(1).get();
158  if (return_frame) {
159  if (return_frame->GetStackID() != m_parent_frame_id ||
161  // next-instruction shouldn't step out of inlined functions. But we
162  // may have stepped into a real function that starts with an inlined
163  // function, and we do want to step out of that...
164 
165  if (cur_frame_sp->IsInlined()) {
166  StackFrameSP parent_frame_sp =
168 
169  if (parent_frame_sp &&
170  parent_frame_sp->GetConcreteFrameIndex() ==
171  cur_frame_sp->GetConcreteFrameIndex()) {
172  SetPlanComplete();
173  if (log) {
174  LLDB_LOGF(log,
175  "Frame we stepped into is inlined into the frame "
176  "we were stepping from, stopping.");
177  }
178  return true;
179  }
180  }
181 
182  if (log) {
183  StreamString s;
184  s.PutCString("Stepped in to: ");
185  addr_t stop_addr =
186  thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
187  DumpAddress(s.AsRawOstream(), stop_addr,
189  s.PutCString(" stepping out to: ");
190  addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
191  DumpAddress(s.AsRawOstream(), return_addr,
193  LLDB_LOGF(log, "%s.", s.GetData());
194  }
195 
196  // StepInstruction should probably have the tri-state RunMode, but
197  // for now it is safer to run others.
198  const bool stop_others = false;
200  false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
201  m_status);
202  return false;
203  } else {
204  if (log) {
205  log->PutCString(
206  "The stack id we are stepping in changed, but our parent frame "
207  "did not when stepping from code with no symbols. "
208  "We are probably just confused about where we are, stopping.");
209  }
210  SetPlanComplete();
211  return true;
212  }
213  } else {
214  LLDB_LOGF(log, "Could not find previous frame, stopping.");
215  SetPlanComplete();
216  return true;
217  }
218  }
219  } else {
220  lldb::addr_t pc_addr = thread.GetRegisterContext()->GetPC(0);
221  if (pc_addr != m_instruction_addr) {
222  if (--m_iteration_count <= 0) {
223  SetPlanComplete();
224  return true;
225  } else {
226  // We are still stepping, reset the start pc, and in case we've stepped
227  // in or out, reset the current stack id.
228  SetUpState();
229  return false;
230  }
231  } else
232  return false;
233  }
234 }
235 
237 
239  return eStateStepping;
240 }
241 
242 bool ThreadPlanStepInstruction::WillStop() { return true; }
243 
245  if (IsPlanComplete()) {
247  LLDB_LOGF(log, "Completed single instruction step plan.");
249  return true;
250  } else {
251  return false;
252  }
253 }
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:63
lldb::StopInfoSP GetPrivateStopInfo()
Definition: ThreadPlan.h:570
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
Definition: Stream.h:357
A class that represents a running process on the host machine.
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:1318
const ArchSpec & GetArchitecture() const
Definition: Target.h:942
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:424
uint32_t GetAddressByteSize() const
Returns the size in bytes of an address of the current architecture.
Definition: ArchSpec.cpp:730
bool DoPlanExplainsStop(Event *event_ptr) override
const char * GetData() const
Definition: StreamString.h:43
DescriptionLevel
Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls.
Thread & GetThread()
Returns the Thread that is using this thread plan.
Definition: ThreadPlan.cpp:41
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.
StopReason
Thread stop reasons.
void DumpAddress(llvm::raw_ostream &s, 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:81
static llvm::raw_ostream & error(Stream &strm)
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:58
StateType
Process and Thread States.
virtual lldb::RegisterContextSP GetRegisterContext()=0
virtual bool MischiefManaged()
Definition: ThreadPlan.cpp:71
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
bool Success() const
Test for success condition.
Definition: Status.cpp:288
Process or thread is in the process of stepping and can not be examined.
void SetPlanComplete(bool success=true)
Definition: ThreadPlan.cpp:65
#define LLDB_LOGF(log,...)
Definition: Log.h:249
uint64_t addr_t
Definition: lldb-types.h:83
void PutCString(const char *cstr)
Definition: Log.cpp:117
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:131
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:398
uint32_t GetMaximumOpcodeByteSize() const
Definition: ArchSpec.cpp:961
#define LIBLLDB_LOG_STEP
Definition: Logging.h:21
This base class provides an interface to stack frames.
Definition: StackFrame.h:40