summaryrefslogtreecommitdiff
path: root/include/lldb/Breakpoint/BreakpointSite.h
blob: 8a183f93f365255b8648568831388d79021f28de (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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
//===-- BreakpointSite.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_BreakpointSite_h_
#define liblldb_BreakpointSite_h_


#include <list>
#include <mutex>


#include "lldb/Breakpoint/BreakpointLocationCollection.h"
#include "lldb/Breakpoint/StoppointLocation.h"
#include "lldb/Utility/UserID.h"
#include "lldb/lldb-forward.h"

namespace lldb_private {

//----------------------------------------------------------------------
/// @class BreakpointSite BreakpointSite.h "lldb/Breakpoint/BreakpointSite.h"
/// Class that manages the actual breakpoint that will be inserted into the
/// running program.
///
/// The BreakpointSite class handles the physical breakpoint that is actually
/// inserted in the target program.  As such, it is also the one that  gets
/// hit, when the program stops. It keeps a list of all BreakpointLocations
/// that share this physical site. When the breakpoint is hit, all the
/// locations are informed by the breakpoint site. Breakpoint sites are owned
/// by the process.
//----------------------------------------------------------------------

class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
                       public StoppointLocation {
public:
  enum Type {
    eSoftware, // Breakpoint opcode has been written to memory and
               // m_saved_opcode
               // and m_trap_opcode contain the saved and written opcode.
    eHardware, // Breakpoint site is set as a hardware breakpoint
    eExternal  // Breakpoint site is managed by an external debug nub or
               // debug interface where memory reads transparently will not
               // display any breakpoint opcodes.
  };

  ~BreakpointSite() override;

  //----------------------------------------------------------------------
  // This section manages the breakpoint traps
  //----------------------------------------------------------------------

  //------------------------------------------------------------------
  /// Returns the Opcode Bytes for this breakpoint
  //------------------------------------------------------------------
  uint8_t *GetTrapOpcodeBytes();

  //------------------------------------------------------------------
  /// Returns the Opcode Bytes for this breakpoint - const version
  //------------------------------------------------------------------
  const uint8_t *GetTrapOpcodeBytes() const;

  //------------------------------------------------------------------
  /// Get the size of the trap opcode for this address
  //------------------------------------------------------------------
  size_t GetTrapOpcodeMaxByteSize() const;

  //------------------------------------------------------------------
  /// Sets the trap opcode
  //------------------------------------------------------------------
  bool SetTrapOpcode(const uint8_t *trap_opcode, uint32_t trap_opcode_size);

  //------------------------------------------------------------------
  /// Gets the original instruction bytes that were overwritten by the trap
  //------------------------------------------------------------------
  uint8_t *GetSavedOpcodeBytes();

  //------------------------------------------------------------------
  /// Gets the original instruction bytes that were overwritten by the trap
  /// const version
  //------------------------------------------------------------------
  const uint8_t *GetSavedOpcodeBytes() const;

  //------------------------------------------------------------------
  /// Says whether \a addr and size \a size intersects with the address \a
  /// intersect_addr
  //------------------------------------------------------------------
  bool IntersectsRange(lldb::addr_t addr, size_t size,
                       lldb::addr_t *intersect_addr, size_t *intersect_size,
                       size_t *opcode_offset) const;

  //------------------------------------------------------------------
  /// Tells whether the current breakpoint site is enabled or not
  ///
  /// This is a low-level enable bit for the breakpoint sites.  If a
  /// breakpoint site has no enabled owners, it should just get removed.  This
  /// enable/disable is for the low-level target code to enable and disable
  /// breakpoint sites when single stepping, etc.
  //------------------------------------------------------------------
  bool IsEnabled() const;

  //------------------------------------------------------------------
  /// Sets whether the current breakpoint site is enabled or not
  ///
  /// @param[in] enabled
  ///    \b true if the breakpoint is enabled, \b false otherwise.
  //------------------------------------------------------------------
  void SetEnabled(bool enabled);

  //------------------------------------------------------------------
  /// Enquires of the breakpoint locations that produced this breakpoint site
  /// whether we should stop at this location.
  ///
  /// @param[in] context
  ///    This contains the information about this stop.
  ///
  /// @return
  ///    \b true if we should stop, \b false otherwise.
  //------------------------------------------------------------------
  bool ShouldStop(StoppointCallbackContext *context) override;

  //------------------------------------------------------------------
  /// Standard Dump method
  ///
  /// @param[in] context
  ///    The stream to dump this output.
  //------------------------------------------------------------------
  void Dump(Stream *s) const override;

  //------------------------------------------------------------------
  /// The "Owners" are the breakpoint locations that share this breakpoint
  /// site. The method adds the \a owner to this breakpoint site's owner list.
  ///
  /// @param[in] context
  ///    \a owner is the Breakpoint Location to add.
  //------------------------------------------------------------------
  void AddOwner(const lldb::BreakpointLocationSP &owner);

  //------------------------------------------------------------------
  /// This method returns the number of breakpoint locations currently located
  /// at this breakpoint site.
  ///
  /// @return
  ///    The number of owners.
  //------------------------------------------------------------------
  size_t GetNumberOfOwners();

  //------------------------------------------------------------------
  /// This method returns the breakpoint location at index \a index located at
  /// this breakpoint site.  The owners are listed ordinally from 0 to
  /// GetNumberOfOwners() - 1 so you can use this method to iterate over the
  /// owners
  ///
  /// @param[in] index
  ///     The index in the list of owners for which you wish the owner location.
  /// @return
  ///    A shared pointer to the breakpoint location at that index.
  //------------------------------------------------------------------
  lldb::BreakpointLocationSP GetOwnerAtIndex(size_t idx);

  //------------------------------------------------------------------
  /// This method copies the breakpoint site's owners into a new collection.
  /// It does this while the owners mutex is locked.
  ///
  /// @param[out] out_collection
  ///    The BreakpointLocationCollection into which to put the owners
  ///    of this breakpoint site.
  ///
  /// @return
  ///    The number of elements copied into out_collection.
  //------------------------------------------------------------------
  size_t CopyOwnersList(BreakpointLocationCollection &out_collection);

  //------------------------------------------------------------------
  /// Check whether the owners of this breakpoint site have any thread
  /// specifiers, and if yes, is \a thread contained in any of these
  /// specifiers.
  ///
  /// @param[in] thread
  ///     The thread against which to test.
  ///
  /// return
  ///     \b true if the collection contains at least one location that
  ///     would be valid for this thread, false otherwise.
  //------------------------------------------------------------------
  bool ValidForThisThread(Thread *thread);

  //------------------------------------------------------------------
  /// Print a description of this breakpoint site to the stream \a s.
  /// GetDescription tells you about the breakpoint site's owners. Use
  /// BreakpointSite::Dump(Stream *) to get information about the breakpoint
  /// site itself.
  ///
  /// @param[in] s
  ///     The stream to which to print the description.
  ///
  /// @param[in] level
  ///     The description level that indicates the detail level to
  ///     provide.
  ///
  /// @see lldb::DescriptionLevel
  //------------------------------------------------------------------
  void GetDescription(Stream *s, lldb::DescriptionLevel level);

  //------------------------------------------------------------------
  /// Tell whether a breakpoint has a location at this site.
  ///
  /// @param[in] bp_id
  ///     The breakpoint id to query.
  ///
  /// @result
  ///     \b true if bp_id has a location that is at this site,
  ///     \b false otherwise.
  //------------------------------------------------------------------
  bool IsBreakpointAtThisSite(lldb::break_id_t bp_id);

  //------------------------------------------------------------------
  /// Tell whether ALL the breakpoints in the location collection are
  /// internal.
  ///
  /// @result
  ///     \b true if all breakpoint locations are owned by internal breakpoints,
  ///     \b false otherwise.
  //------------------------------------------------------------------
  bool IsInternal() const;

  BreakpointSite::Type GetType() const { return m_type; }

  void SetType(BreakpointSite::Type type) { m_type = type; }

private:
  friend class Process;
  friend class BreakpointLocation;
  // The StopInfoBreakpoint knows when it is processing a hit for a thread for
  // a site, so let it be the one to manage setting the location hit count once
  // and only once.
  friend class StopInfoBreakpoint;

  void BumpHitCounts();

  //------------------------------------------------------------------
  /// The method removes the owner at \a break_loc_id from this breakpoint
  /// list.
  ///
  /// @param[in] context
  ///    \a break_loc_id is the Breakpoint Location to remove.
  //------------------------------------------------------------------
  size_t RemoveOwner(lldb::break_id_t break_id, lldb::break_id_t break_loc_id);

  BreakpointSite::Type m_type; ///< The type of this breakpoint site.
  uint8_t m_saved_opcode[8]; ///< The saved opcode bytes if this breakpoint site
                             ///uses trap opcodes.
  uint8_t m_trap_opcode[8];  ///< The opcode that was used to create the
                             ///breakpoint if it is a software breakpoint site.
  bool
      m_enabled; ///< Boolean indicating if this breakpoint site enabled or not.

  // Consider adding an optimization where if there is only one owner, we don't
  // store a list.  The usual case will be only one owner...
  BreakpointLocationCollection m_owners; ///< This has the BreakpointLocations
                                         ///that share this breakpoint site.
  std::recursive_mutex
      m_owners_mutex; ///< This mutex protects the owners collection.

  static lldb::break_id_t GetNextID();

  // Only the Process can create breakpoint sites in
  // Process::CreateBreakpointSite (lldb::BreakpointLocationSP &, bool).
  BreakpointSite(BreakpointSiteList *list,
                 const lldb::BreakpointLocationSP &owner, lldb::addr_t m_addr,
                 bool use_hardware);

  DISALLOW_COPY_AND_ASSIGN(BreakpointSite);
};

} // namespace lldb_private

#endif // liblldb_BreakpointSite_h_