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