summaryrefslogtreecommitdiff
path: root/include/lldb/Target/StopInfo.h
blob: 811841d1797e97c1df4f44e9a2a0f00048f652dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//===-- StopInfo.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_StopInfo_h_
#define liblldb_StopInfo_h_

#include <string>

#include "lldb/Target/Process.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-public.h"

namespace lldb_private {

class StopInfo {
  friend class Process::ProcessEventData;
  friend class ThreadPlanBase;

public:
  //------------------------------------------------------------------
  // Constructors and Destructors
  //------------------------------------------------------------------
  StopInfo(Thread &thread, uint64_t value);

  virtual ~StopInfo() {}

  bool IsValid() const;

  void SetThread(const lldb::ThreadSP &thread_sp) { m_thread_wp = thread_sp; }

  lldb::ThreadSP GetThread() const { return m_thread_wp.lock(); }

  // The value of the StopInfo depends on the StopReason. StopReason
  // Meaning ----------------------------------------------
  // eStopReasonBreakpoint       BreakpointSiteID eStopReasonSignal
  // Signal number eStopReasonWatchpoint       WatchpointLocationID
  // eStopReasonPlanComplete     No significance

  uint64_t GetValue() const { return m_value; }

  virtual lldb::StopReason GetStopReason() const = 0;

  // ShouldStopSynchronous will get called before any thread plans are
  // consulted, and if it says we should resume the target, then we will just
  // immediately resume.  This should not run any code in or resume the target.

  virtual bool ShouldStopSynchronous(Event *event_ptr) { return true; }

  void OverrideShouldNotify(bool override_value) {
    m_override_should_notify = override_value ? eLazyBoolYes : eLazyBoolNo;
  }

  // If should stop returns false, check if we should notify of this event
  virtual bool ShouldNotify(Event *event_ptr) {
    if (m_override_should_notify == eLazyBoolCalculate)
      return DoShouldNotify(event_ptr);
    else
      return m_override_should_notify == eLazyBoolYes;
  }

  virtual void WillResume(lldb::StateType resume_state) {
    // By default, don't do anything
  }

  virtual const char *GetDescription() { return m_description.c_str(); }

  virtual void SetDescription(const char *desc_cstr) {
    if (desc_cstr && desc_cstr[0])
      m_description.assign(desc_cstr);
    else
      m_description.clear();
  }

  virtual bool IsValidForOperatingSystemThread(Thread &thread) { return true; }

  // Sometimes the thread plan logic will know that it wants a given stop to
  // stop or not, regardless of what the ordinary logic for that StopInfo would
  // dictate.  The main example of this is the ThreadPlanCallFunction, which
  // for instance knows - based on how that particular expression was executed
  // - whether it wants all breakpoints to auto-continue or not. Use
  // OverrideShouldStop on the StopInfo to implement this.

  void OverrideShouldStop(bool override_value) {
    m_override_should_stop = override_value ? eLazyBoolYes : eLazyBoolNo;
  }

  bool GetOverrideShouldStop() {
    return m_override_should_stop != eLazyBoolCalculate;
  }

  bool GetOverriddenShouldStopValue() {
    return m_override_should_stop == eLazyBoolYes;
  }

  StructuredData::ObjectSP GetExtendedInfo() { return m_extended_info; }

  static lldb::StopInfoSP
  CreateStopReasonWithBreakpointSiteID(Thread &thread,
                                       lldb::break_id_t break_id);

  // This creates a StopInfo for the thread where the should_stop is already
  // set, and won't be recalculated.
  static lldb::StopInfoSP CreateStopReasonWithBreakpointSiteID(
      Thread &thread, lldb::break_id_t break_id, bool should_stop);

  static lldb::StopInfoSP CreateStopReasonWithWatchpointID(
      Thread &thread, lldb::break_id_t watch_id,
      lldb::addr_t watch_hit_addr = LLDB_INVALID_ADDRESS);

  static lldb::StopInfoSP
  CreateStopReasonWithSignal(Thread &thread, int signo,
                             const char *description = nullptr);

  static lldb::StopInfoSP CreateStopReasonToTrace(Thread &thread);

  static lldb::StopInfoSP
  CreateStopReasonWithPlan(lldb::ThreadPlanSP &plan,
                           lldb::ValueObjectSP return_valobj_sp,
                           lldb::ExpressionVariableSP expression_variable_sp);

  static lldb::StopInfoSP
  CreateStopReasonWithException(Thread &thread, const char *description);

  static lldb::StopInfoSP CreateStopReasonWithExec(Thread &thread);

  static lldb::ValueObjectSP
  GetReturnValueObject(lldb::StopInfoSP &stop_info_sp);

  static lldb::ExpressionVariableSP
  GetExpressionVariable(lldb::StopInfoSP &stop_info_sp);

  static lldb::ValueObjectSP
  GetCrashingDereference(lldb::StopInfoSP &stop_info_sp,
                         lldb::addr_t *crashing_address = nullptr);

protected:
  // Perform any action that is associated with this stop.  This is done as the
  // Event is removed from the event queue.  ProcessEventData::DoOnRemoval does
  // the job.

  virtual void PerformAction(Event *event_ptr) {}

  virtual bool DoShouldNotify(Event *event_ptr) { return false; }

  // Stop the thread by default. Subclasses can override this to allow the
  // thread to continue if desired.  The ShouldStop method should not do
  // anything that might run code.  If you need to run code when deciding
  // whether to stop at this StopInfo, that must be done in the PerformAction.
  // The PerformAction will always get called before the ShouldStop.  This is
  // done by the ProcessEventData::DoOnRemoval, though the ThreadPlanBase needs
  // to consult this later on.
  virtual bool ShouldStop(Event *event_ptr) { return true; }

  //------------------------------------------------------------------
  // Classes that inherit from StackID can see and modify these
  //------------------------------------------------------------------
  lldb::ThreadWP m_thread_wp; // The thread corresponding to the stop reason.
  uint32_t m_stop_id;   // The process stop ID for which this stop info is valid
  uint32_t m_resume_id; // This is the resume ID when we made this stop ID.
  uint64_t m_value; // A generic value that can be used for things pertaining to
                    // this stop info
  std::string m_description; // A textual description describing this stop.
  LazyBool m_override_should_notify;
  LazyBool m_override_should_stop;

  StructuredData::ObjectSP
      m_extended_info; // The extended info for this stop info

  // This determines whether the target has run since this stop info. N.B.
  // running to evaluate a user expression does not count.
  bool HasTargetRunSinceMe();

  // MakeStopInfoValid is necessary to allow saved stop infos to resurrect
  // themselves as valid. It should only be used by
  // Thread::RestoreThreadStateFromCheckpoint and to make sure the one-step
  // needed for before-the-fact watchpoints does not prevent us from stopping
  void MakeStopInfoValid();

private:
  friend class Thread;

  DISALLOW_COPY_AND_ASSIGN(StopInfo);
};

} // namespace lldb_private

#endif // liblldb_StopInfo_h_