LLDB  mainline
ThreadPlanStepUntil.cpp
Go to the documentation of this file.
1 //===-- ThreadPlanStepUntil.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 
13 #include "lldb/Target/Process.h"
15 #include "lldb/Target/StopInfo.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/Log.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 
22 // ThreadPlanStepUntil: Run until we reach a given line number or step out of
23 // the current frame
24 
25 ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
26  lldb::addr_t *address_list,
27  size_t num_addresses, bool stop_others,
28  uint32_t frame_idx)
29  : ThreadPlan(ThreadPlan::eKindStepUntil, "Step until", thread,
31  m_step_from_insn(LLDB_INVALID_ADDRESS),
32  m_return_bp_id(LLDB_INVALID_BREAK_ID),
33  m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false),
34  m_should_stop(false), m_ran_analyze(false), m_explains_stop(false),
35  m_until_points(), m_stop_others(stop_others) {
36  // Stash away our "until" addresses:
37  TargetSP target_sp(thread.CalculateTarget());
38 
39  StackFrameSP frame_sp(thread.GetStackFrameAtIndex(frame_idx));
40  if (frame_sp) {
41  m_step_from_insn = frame_sp->GetStackID().GetPC();
42 
43  // Find the return address and set a breakpoint there:
44  // FIXME - can we do this more securely if we know first_insn?
45 
46  StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(frame_idx + 1));
47  if (return_frame_sp) {
48  // TODO: add inline functionality
49  m_return_addr = return_frame_sp->GetStackID().GetPC();
50  Breakpoint *return_bp =
51  target_sp->CreateBreakpoint(m_return_addr, true, false).get();
52 
53  if (return_bp != nullptr) {
54  if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
56  return_bp->SetThreadID(m_tid);
57  m_return_bp_id = return_bp->GetID();
58  return_bp->SetBreakpointKind("until-return-backstop");
59  }
60  }
61 
62  m_stack_id = frame_sp->GetStackID();
63 
64  // Now set breakpoints on all our return addresses:
65  for (size_t i = 0; i < num_addresses; i++) {
66  Breakpoint *until_bp =
67  target_sp->CreateBreakpoint(address_list[i], true, false).get();
68  if (until_bp != nullptr) {
69  until_bp->SetThreadID(m_tid);
70  m_until_points[address_list[i]] = until_bp->GetID();
71  until_bp->SetBreakpointKind("until-target");
72  } else {
73  m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
74  }
75  }
76  }
77 }
78 
80 
82  Target &target = GetTarget();
86  }
87 
88  until_collection::iterator pos, end = m_until_points.end();
89  for (pos = m_until_points.begin(); pos != end; pos++) {
90  target.RemoveBreakpointByID((*pos).second);
91  }
92  m_until_points.clear();
94 }
95 
97  lldb::DescriptionLevel level) {
98  if (level == lldb::eDescriptionLevelBrief) {
99  s->Printf("step until");
100  if (m_stepped_out)
101  s->Printf(" - stepped out");
102  } else {
103  if (m_until_points.size() == 1)
104  s->Printf("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64
105  " using breakpoint %d",
106  (uint64_t)m_step_from_insn,
107  (uint64_t)(*m_until_points.begin()).first,
108  (*m_until_points.begin()).second);
109  else {
110  until_collection::iterator pos, end = m_until_points.end();
111  s->Printf("Stepping from address 0x%" PRIx64 " until we reach one of:",
112  (uint64_t)m_step_from_insn);
113  for (pos = m_until_points.begin(); pos != end; pos++) {
114  s->Printf("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t)(*pos).first,
115  (*pos).second);
116  }
117  }
118  s->Printf(" stepped out address is 0x%" PRIx64 ".",
119  (uint64_t)m_return_addr);
120  }
121 }
122 
125  if (error)
126  error->PutCString(
127  "Could not create hardware breakpoint for thread plan.");
128  return false;
129  } else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
130  if (error)
131  error->PutCString("Could not create return breakpoint.");
132  return false;
133  } else {
134  until_collection::iterator pos, end = m_until_points.end();
135  for (pos = m_until_points.begin(); pos != end; pos++) {
136  if (!LLDB_BREAK_ID_IS_VALID((*pos).second))
137  return false;
138  }
139  return true;
140  }
141 }
142 
144  if (m_ran_analyze)
145  return;
146 
147  StopInfoSP stop_info_sp = GetPrivateStopInfo();
148  m_should_stop = true;
149  m_explains_stop = false;
150 
151  if (stop_info_sp) {
152  StopReason reason = stop_info_sp->GetStopReason();
153 
154  if (reason == eStopReasonBreakpoint) {
155  // If this is OUR breakpoint, we're fine, otherwise we don't know why
156  // this happened...
157  BreakpointSiteSP this_site =
158  m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue());
159  if (!this_site) {
160  m_explains_stop = false;
161  return;
162  }
163 
164  if (this_site->IsBreakpointAtThisSite(m_return_bp_id)) {
165  // If we are at our "step out" breakpoint, and the stack depth has
166  // shrunk, then this is indeed our stop. If the stack depth has grown,
167  // then we've hit our step out breakpoint recursively. If we are the
168  // only breakpoint at that location, then we do explain the stop, and
169  // we'll just continue. If there was another breakpoint here, then we
170  // don't explain the stop, but we won't mark ourselves Completed,
171  // because maybe that breakpoint will continue, and then we'll finish
172  // the "until".
173  bool done;
174  StackID cur_frame_zero_id;
175 
176  done = (m_stack_id < cur_frame_zero_id);
177 
178  if (done) {
179  m_stepped_out = true;
180  SetPlanComplete();
181  } else
182  m_should_stop = false;
183 
184  if (this_site->GetNumberOfOwners() == 1)
185  m_explains_stop = true;
186  else
187  m_explains_stop = false;
188  return;
189  } else {
190  // Check if we've hit one of our "until" breakpoints.
191  until_collection::iterator pos, end = m_until_points.end();
192  for (pos = m_until_points.begin(); pos != end; pos++) {
193  if (this_site->IsBreakpointAtThisSite((*pos).second)) {
194  // If we're at the right stack depth, then we're done.
195  Thread &thread = GetThread();
196  bool done;
197  StackID frame_zero_id =
198  thread.GetStackFrameAtIndex(0)->GetStackID();
199 
200  if (frame_zero_id == m_stack_id)
201  done = true;
202  else if (frame_zero_id < m_stack_id)
203  done = false;
204  else {
205  StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(1);
206 
207  // But if we can't even unwind one frame we should just get out
208  // of here & stop...
209  if (older_frame_sp) {
210  const SymbolContext &older_context =
211  older_frame_sp->GetSymbolContext(eSymbolContextEverything);
212  SymbolContext stack_context;
214  &stack_context);
215 
216  done = (older_context == stack_context);
217  } else
218  done = false;
219  }
220 
221  if (done)
222  SetPlanComplete();
223  else
224  m_should_stop = false;
225 
226  // Otherwise we've hit this breakpoint recursively. If we're the
227  // only breakpoint here, then we do explain the stop, and we'll
228  // continue. If not then we should let higher plans handle this
229  // stop.
230  if (this_site->GetNumberOfOwners() == 1)
231  m_explains_stop = true;
232  else {
233  m_should_stop = true;
234  m_explains_stop = false;
235  }
236  return;
237  }
238  }
239  }
240  // If we get here we haven't hit any of our breakpoints, so let the
241  // higher plans take care of the stop.
242  m_explains_stop = false;
243  return;
244  } else if (IsUsuallyUnexplainedStopReason(reason)) {
245  m_explains_stop = false;
246  } else {
247  m_explains_stop = true;
248  }
249  }
250 }
251 
253  // We don't explain signals or breakpoints (breakpoints that handle stepping
254  // in or out will be handled by a child plan.
255  AnalyzeStop();
256  return m_explains_stop;
257 }
258 
260  // If we've told our self in ExplainsStop that we plan to continue, then do
261  // so here. Otherwise, as long as this thread has stopped for a reason, we
262  // will stop.
263 
264  StopInfoSP stop_info_sp = GetPrivateStopInfo();
265  if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
266  return false;
267 
268  AnalyzeStop();
269  return m_should_stop;
270 }
271 
273 
275 
277  bool current_plan) {
278  if (current_plan) {
279  Target &target = GetTarget();
280  Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
281  if (return_bp != nullptr)
282  return_bp->SetEnabled(true);
283 
284  until_collection::iterator pos, end = m_until_points.end();
285  for (pos = m_until_points.begin(); pos != end; pos++) {
286  Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
287  if (until_bp != nullptr)
288  until_bp->SetEnabled(true);
289  }
290  }
291 
292  m_should_stop = true;
293  m_ran_analyze = false;
294  m_explains_stop = false;
295  return true;
296 }
297 
299  Target &target = GetTarget();
300  Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
301  if (return_bp != nullptr)
302  return_bp->SetEnabled(false);
303 
304  until_collection::iterator pos, end = m_until_points.end();
305  for (pos = m_until_points.begin(); pos != end; pos++) {
306  Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
307  if (until_bp != nullptr)
308  until_bp->SetEnabled(false);
309  }
310  return true;
311 }
312 
314  // I'm letting "PlanExplainsStop" do all the work, and just reporting that
315  // here.
316  bool done = false;
317  if (IsPlanComplete()) {
319  LLDB_LOGF(log, "Completed step until plan.");
320 
321  Clear();
322  done = true;
323  }
324  if (done)
326 
327  return done;
328 }
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:63
bool IsUsuallyUnexplainedStopReason(lldb::StopReason)
Definition: ThreadPlan.cpp:164
lldb::StopInfoSP GetPrivateStopInfo()
Definition: ThreadPlan.h:570
bool RemoveBreakpointByID(lldb::break_id_t break_id)
Definition: Target.cpp:916
A class that represents a running process on the host machine.
bool DoWillResume(lldb::StateType resume_state, bool current_plan) override
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
Defines a symbol context baton that can be handed other debug core functions.
Definition: SymbolContext.h:33
General Outline: A breakpoint has four main parts, a filter, a resolver, the list of breakpoint locat...
Definition: Breakpoint.h:78
void SetBreakpointKind(const char *kind)
Set the "kind" description for a breakpoint.
Definition: Breakpoint.h:441
DescriptionLevel
Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls.
Thread & GetThread()
Returns the Thread that is using this thread plan.
Definition: ThreadPlan.cpp:41
SymbolContextScope * GetSymbolContextScope() const
Definition: StackID.h:37
StopReason
Thread stop reasons.
void SetEnabled(bool enable) override
If enable is true, enable the breakpoint, if false disable it.
Definition: Breakpoint.cpp:299
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
lldb::BreakpointSP GetBreakpointByID(lldb::break_id_t break_id)
Definition: Target.cpp:295
static llvm::raw_ostream & error(Stream &strm)
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:58
lldb::TargetSP CalculateTarget() override
Definition: Thread.cpp:1390
void GetDescription(Stream *s, lldb::DescriptionLevel level) override
Print a description of this thread to the stream s.
StateType
Process and Thread States.
BreakpointSiteList & GetBreakpointSiteList()
Definition: Process.cpp:1661
lldb::break_id_t GetID() const
Definition: Stoppoint.cpp:22
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 IsHardware() const
Definition: Breakpoint.h:509
lldb::BreakpointSiteSP FindByID(lldb::break_id_t breakID)
Returns a shared pointer to the breakpoint site with id breakID.
void SetPlanComplete(bool success=true)
Definition: ThreadPlan.cpp:65
bool HasResolvedLocations() const
Return whether this breakpoint has any resolved locations.
Definition: Breakpoint.cpp:861
#define LLDB_LOGF(log,...)
Definition: Log.h:249
virtual void CalculateSymbolContext(SymbolContext *sc)=0
Reconstruct the object&#39;s symbol context into sc.
uint64_t addr_t
Definition: lldb-types.h:83
bool ShouldStop(Event *event_ptr) override
Definition: SBAddress.h:15
void SetThreadID(lldb::tid_t thread_id)
Set the valid thread to be checked when the breakpoint is hit.
Definition: Breakpoint.cpp:361
#define LLDB_INVALID_BREAK_ID
Definition: lldb-defines.h:49
bool ValidatePlan(Stream *error) override
Returns whether this plan could be successfully created.
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:398
#define LLDB_BREAK_ID_IS_VALID(bid)
Definition: lldb-defines.h:51
lldb::StateType GetPlanRunState() override
#define LIBLLDB_LOG_STEP
Definition: Logging.h:21
bool DoPlanExplainsStop(Event *event_ptr) override
Process or thread is running and can&#39;t be examined.