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 }
lldb_private::ThreadPlanStepUntil::ValidatePlan
bool ValidatePlan(Stream *error) override
Returns whether this plan could be successfully created.
Definition: ThreadPlanStepUntil.cpp:123
lldb_private::Breakpoint::HasResolvedLocations
bool HasResolvedLocations() const
Return whether this breakpoint has any resolved locations.
Definition: Breakpoint.cpp:833
LLDB_BREAK_ID_IS_VALID
#define LLDB_BREAK_ID_IS_VALID(bid)
Definition: lldb-defines.h:51
ThreadPlanStepUntil.h
lldb_private::ThreadPlan::GetThread
Thread & GetThread()
Returns the Thread that is using this thread plan.
Definition: ThreadPlan.cpp:41
lldb_private::Stoppoint::GetID
lldb::break_id_t GetID() const
Definition: Stoppoint.cpp:22
lldb_private::Event
Definition: Event.h:180
lldb_private::ThreadPlan::IsPlanComplete
bool IsPlanComplete()
Definition: ThreadPlan.cpp:60
lldb_private::ThreadPlanStepUntil::DoPlanExplainsStop
bool DoPlanExplainsStop(Event *event_ptr) override
Definition: ThreadPlanStepUntil.cpp:252
lldb_private::Breakpoint::SetBreakpointKind
void SetBreakpointKind(const char *kind)
Set the "kind" description for a breakpoint.
Definition: Breakpoint.h:442
lldb_private::ThreadPlanStepUntil::GetPlanRunState
lldb::StateType GetPlanRunState() override
Definition: ThreadPlanStepUntil.cpp:274
lldb_private::ThreadPlanStepUntil::m_should_stop
bool m_should_stop
Definition: ThreadPlanStepUntil.h:45
LLDB_LOGF
#define LLDB_LOGF(log,...)
Definition: Log.h:249
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:96
lldb_private::Thread::CalculateTarget
lldb::TargetSP CalculateTarget() override
Definition: Thread.cpp:1389
lldb_private::Process::GetBreakpointSiteList
BreakpointSiteList & GetBreakpointSiteList()
Definition: Process.cpp:1554
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:450
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:37
lldb_private::ThreadPlan
Definition: ThreadPlan.h:282
Log.h
lldb_private::ThreadPlan::MischiefManaged
virtual bool MischiefManaged()
Definition: ThreadPlan.cpp:71
lldb_private::Thread
Definition: Thread.h:60
lldb_private::ThreadPlanStepUntil::Clear
void Clear()
Definition: ThreadPlanStepUntil.cpp:81
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::GetLogIfAllCategoriesSet
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:58
lldb_private::ThreadPlanStepUntil::StopOthers
bool StopOthers() override
Definition: ThreadPlanStepUntil.cpp:272
lldb_private::ThreadPlanStepUntil::AnalyzeStop
void AnalyzeStop()
Definition: ThreadPlanStepUntil.cpp:143
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:340
lldb_private::ThreadPlanStepUntil::DoWillResume
bool DoWillResume(lldb::StateType resume_state, bool current_plan) override
Definition: ThreadPlanStepUntil.cpp:276
LLDB_INVALID_BREAK_ID
#define LLDB_INVALID_BREAK_ID
Definition: lldb-defines.h:49
lldb_private::Breakpoint::SetEnabled
void SetEnabled(bool enable) override
If enable is true, enable the breakpoint, if false disable it.
Definition: Breakpoint.cpp:294
lldb_private::ThreadPlan::SetPlanComplete
void SetPlanComplete(bool success=true)
Definition: ThreadPlan.cpp:65
lldb_private::ThreadPlan::IsUsuallyUnexplainedStopReason
bool IsUsuallyUnexplainedStopReason(lldb::StopReason)
Definition: ThreadPlan.cpp:165
uint32_t
lldb_private::ThreadPlanStepUntil::WillStop
bool WillStop() override
Definition: ThreadPlanStepUntil.cpp:298
lldb_private::ThreadPlan::m_could_not_resolve_hw_bp
bool m_could_not_resolve_hw_bp
Definition: ThreadPlan.h:528
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:935
LLDB_INVALID_ADDRESS
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:86
lldb_private::ThreadPlanStepUntil::MischiefManaged
bool MischiefManaged() override
Definition: ThreadPlanStepUntil.cpp:313
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:259
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:79
lldb_private::Breakpoint::IsHardware
bool IsHardware() const
Definition: Breakpoint.h:510
Breakpoint.h
LIBLLDB_LOG_STEP
#define LIBLLDB_LOG_STEP
Definition: Logging.h:21
lldb_private::ThreadPlan::m_tid
lldb::tid_t m_tid
Definition: ThreadPlan.h:524
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:49
lldb_private::Target::GetBreakpointByID
lldb::BreakpointSP GetBreakpointByID(lldb::break_id_t break_id)
Definition: Target.cpp:304
lldb_private::Thread::GetStackFrameAtIndex
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:397
lldb_private::ThreadPlan::GetPrivateStopInfo
lldb::StopInfoSP GetPrivateStopInfo()
Definition: ThreadPlan.h:510
lldb_private::ThreadPlan::m_process
Process & m_process
Definition: ThreadPlan.h:523
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
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:79