lldb 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -3
  3. data/README.md +86 -2
  4. data/Rakefile +36 -0
  5. data/bindings/constants.yml +137 -0
  6. data/bindings/surface.yml +3072 -0
  7. data/ext/lldb/discovery.rb +101 -0
  8. data/ext/lldb/extconf.rb +206 -88
  9. data/ext/lldb/lldb_wrapper.cpp +7977 -856
  10. data/ext/lldb/lldb_wrapper.h +599 -324
  11. data/lib/lldb/address.rb +81 -0
  12. data/lib/lldb/api_support.rb +91 -0
  13. data/lib/lldb/attach_info.rb +122 -0
  14. data/lib/lldb/block.rb +121 -0
  15. data/lib/lldb/breakpoint.rb +11 -6
  16. data/lib/lldb/breakpoint_location.rb +20 -5
  17. data/lib/lldb/broadcaster.rb +79 -0
  18. data/lib/lldb/command_interpreter.rb +9 -4
  19. data/lib/lldb/command_return_object.rb +24 -5
  20. data/lib/lldb/compile_unit.rb +64 -0
  21. data/lib/lldb/context.rb +81 -0
  22. data/lib/lldb/debugger.rb +55 -12
  23. data/lib/lldb/error.rb +51 -3
  24. data/lib/lldb/event.rb +109 -0
  25. data/lib/lldb/expression_options.rb +124 -0
  26. data/lib/lldb/ffi_bindings.rb +326 -31
  27. data/lib/lldb/file_spec.rb +90 -0
  28. data/lib/lldb/file_spec_list.rb +78 -0
  29. data/lib/lldb/frame.rb +113 -18
  30. data/lib/lldb/function.rb +121 -0
  31. data/lib/lldb/instruction.rb +83 -0
  32. data/lib/lldb/instruction_list.rb +68 -0
  33. data/lib/lldb/launch_info.rb +145 -19
  34. data/lib/lldb/line_entry.rb +75 -0
  35. data/lib/lldb/listener.rb +96 -0
  36. data/lib/lldb/memory_region_info.rb +109 -0
  37. data/lib/lldb/module.rb +46 -5
  38. data/lib/lldb/native.rb +36 -0
  39. data/lib/lldb/native_buffer.rb +32 -0
  40. data/lib/lldb/native_handle.rb +60 -0
  41. data/lib/lldb/native_lifecycle.rb +64 -0
  42. data/lib/lldb/native_string_array.rb +34 -0
  43. data/lib/lldb/process.rb +121 -38
  44. data/lib/lldb/symbol.rb +117 -0
  45. data/lib/lldb/symbol_context.rb +9 -4
  46. data/lib/lldb/target.rb +73 -67
  47. data/lib/lldb/thread.rb +56 -19
  48. data/lib/lldb/type.rb +40 -3
  49. data/lib/lldb/type_member.rb +67 -0
  50. data/lib/lldb/types.rb +69 -4
  51. data/lib/lldb/value.rb +27 -17
  52. data/lib/lldb/value_list.rb +9 -5
  53. data/lib/lldb/version.rb +1 -1
  54. data/lib/lldb/watchpoint.rb +26 -9
  55. data/lib/lldb.rb +80 -10
  56. data/lldb.gemspec +4 -1
  57. data/rbs_collection.yaml +1 -1
  58. data/script/check_bindings +259 -0
  59. data/script/guard_c_exports +139 -0
  60. data/sig/lldb/ffi_bindings.rbs +258 -21
  61. data/sig/lldb/weak_ref.rbs +7 -0
  62. metadata +32 -6
  63. data/ext/lldb/Makefile +0 -24
  64. data/ext/lldb/liblldb_wrapper.dylib +0 -0
  65. data/ext/lldb/lldb_wrapper.o +0 -0
  66. data/ext/lldb/mkmf.log +0 -24
data/lib/lldb/types.rb CHANGED
@@ -3,6 +3,21 @@
3
3
  # rbs_inline: enabled
4
4
 
5
5
  module LLDB
6
+ INVALID_ADDRESS = (1 << 64) - 1 # : Integer
7
+ INVALID_PROCESS_ID = 0 # : Integer
8
+ INVALID_THREAD_ID = 0 # : Integer
9
+ INVALID_BREAK_ID = 0 # : Integer
10
+ INVALID_LINE_NUMBER = 0xFFFFFFFF # : Integer
11
+
12
+ module NativeStatus
13
+ OK = 0 # : Integer
14
+ INVALID_ARGUMENT = 1 # : Integer
15
+ INVALID_HANDLE = 2 # : Integer
16
+ UNSUPPORTED = 3 # : Integer
17
+ LLDB_ERROR = 4 # : Integer
18
+ INTERNAL_ERROR = 5 # : Integer
19
+ end
20
+
6
21
  module State
7
22
  INVALID = 0 # : Integer
8
23
  UNLOADED = 1 # : Integer
@@ -51,6 +66,10 @@ module LLDB
51
66
  PLAN_COMPLETE = 8 # : Integer
52
67
  THREAD_EXITING = 9 # : Integer
53
68
  INSTRUMENTATION = 10 # : Integer
69
+ PROCESSOR_TRACE = 11 # : Integer
70
+ FORK = 12 # : Integer
71
+ VFORK = 13 # : Integer
72
+ VFORK_DONE = 14 # : Integer
54
73
 
55
74
  NAMES = { # : Hash[Integer, String]
56
75
  INVALID => 'invalid',
@@ -63,7 +82,11 @@ module LLDB
63
82
  EXEC => 'exec',
64
83
  PLAN_COMPLETE => 'plan complete',
65
84
  THREAD_EXITING => 'thread exiting',
66
- INSTRUMENTATION => 'instrumentation'
85
+ INSTRUMENTATION => 'instrumentation',
86
+ PROCESSOR_TRACE => 'processor trace',
87
+ FORK => 'fork',
88
+ VFORK => 'vfork',
89
+ VFORK_DONE => 'vfork done'
67
90
  }.freeze
68
91
 
69
92
  # @rbs reason: Integer
@@ -81,7 +104,8 @@ module LLDB
81
104
  BLOCK = 1 << 4 # : Integer
82
105
  LINE_ENTRY = 1 << 5 # : Integer
83
106
  SYMBOL = 1 << 6 # : Integer
84
- EVERYTHING = 0xFFFF # : Integer
107
+ VARIABLE = 1 << 7 # : Integer
108
+ EVERYTHING = 0x7F # : Integer
85
109
  end
86
110
 
87
111
  module ValueType
@@ -93,6 +117,7 @@ module LLDB
93
117
  REGISTER = 5 # : Integer
94
118
  REGISTER_SET = 6 # : Integer
95
119
  CONSTANT_RESULT = 7 # : Integer
120
+ VARIABLE_THREAD_LOCAL = 8 # : Integer
96
121
 
97
122
  NAMES = { # : Hash[Integer, String]
98
123
  INVALID => 'invalid',
@@ -102,7 +127,8 @@ module LLDB
102
127
  VARIABLE_LOCAL => 'local',
103
128
  REGISTER => 'register',
104
129
  REGISTER_SET => 'register set',
105
- CONSTANT_RESULT => 'constant result'
130
+ CONSTANT_RESULT => 'constant result',
131
+ VARIABLE_THREAD_LOCAL => 'thread local'
106
132
  }.freeze
107
133
 
108
134
  # @rbs value_type: Integer
@@ -145,6 +171,9 @@ module LLDB
145
171
  OBJ_C_CLASS = 29 # : Integer
146
172
  OBJ_C_SEL = 30 # : Integer
147
173
  NULL_PTR = 31 # : Integer
174
+ # LLDB inserted eBasicTypeChar8 before SHORT in newer releases. The
175
+ # wrapper normalizes it to this value so the public Ruby enum is stable.
176
+ CHAR8 = 32 # : Integer
148
177
 
149
178
  NAMES = { # : Hash[Integer, String]
150
179
  INVALID => 'invalid',
@@ -178,7 +207,8 @@ module LLDB
178
207
  OBJ_C_ID => 'id',
179
208
  OBJ_C_CLASS => 'Class',
180
209
  OBJ_C_SEL => 'SEL',
181
- NULL_PTR => 'nullptr_t'
210
+ NULL_PTR => 'nullptr_t',
211
+ CHAR8 => 'char8_t'
182
212
  }.freeze
183
213
 
184
214
  # @rbs basic_type: Integer
@@ -187,4 +217,39 @@ module LLDB
187
217
  NAMES[basic_type] || 'unknown'
188
218
  end
189
219
  end
220
+
221
+ module ErrorType
222
+ INVALID = 0 # : Integer
223
+ GENERIC = 1 # : Integer
224
+ MACH_KERNEL = 2 # : Integer
225
+ POSIX = 3 # : Integer
226
+ EXPRESSION = 4 # : Integer
227
+ WIN32 = 5 # : Integer
228
+
229
+ NAMES = { # : Hash[Integer, String]
230
+ INVALID => 'invalid',
231
+ GENERIC => 'generic',
232
+ MACH_KERNEL => 'mach kernel',
233
+ POSIX => 'POSIX',
234
+ EXPRESSION => 'expression',
235
+ WIN32 => 'Win32'
236
+ }.freeze
237
+ end
238
+
239
+ module ReturnStatus
240
+ INVALID = 0 # : Integer
241
+ SUCCESS_FINISH_NO_RESULT = 1 # : Integer
242
+ SUCCESS_FINISH_RESULT = 2 # : Integer
243
+ SUCCESS_CONTINUING_NO_RESULT = 3 # : Integer
244
+ SUCCESS_CONTINUING_RESULT = 4 # : Integer
245
+ STARTED = 5 # : Integer
246
+ FAILED = 6 # : Integer
247
+ QUIT = 7 # : Integer
248
+ end
249
+
250
+ module RunMode
251
+ ONLY_THIS_THREAD = 0 # : Integer
252
+ ALL_THREADS = 1 # : Integer
253
+ ONLY_DURING_STEPPING = 2 # : Integer
254
+ end
190
255
  end
data/lib/lldb/value.rb CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  module LLDB
6
6
  class Value
7
+ prepend NativeLifecycle
7
8
  include Enumerable #[Value]
8
9
 
9
10
  # @rbs return: Frame | Value | Target
@@ -12,10 +13,13 @@ module LLDB
12
13
  # @rbs ptr: FFI::Pointer
13
14
  # @rbs parent: Frame | Value | Target
14
15
  # @rbs return: void
15
- def initialize(ptr, parent:)
16
- @ptr = ptr # : FFI::Pointer
16
+ def initialize(ptr, parent:, context: parent.context)
17
17
  @parent = parent
18
- ObjectSpace.define_finalizer(self, self.class.release(@ptr))
18
+ initialize_native_object(
19
+ ptr,
20
+ release: ->(released) { FFIBindings.lldb_value_destroy(released) },
21
+ context: context
22
+ )
19
23
  end
20
24
 
21
25
  # @rbs ptr: FFI::Pointer
@@ -72,7 +76,7 @@ module LLDB
72
76
  child_ptr = FFIBindings.lldb_value_get_child_at_index(@ptr, index)
73
77
  return nil if child_ptr.nil? || child_ptr.null?
74
78
 
75
- Value.new(child_ptr, parent: self)
79
+ Value.new(child_ptr, parent: self, context: context)
76
80
  end
77
81
 
78
82
  # @rbs name: String
@@ -83,7 +87,7 @@ module LLDB
83
87
  child_ptr = FFIBindings.lldb_value_get_child_member_with_name(@ptr, name)
84
88
  return nil if child_ptr.nil? || child_ptr.null?
85
89
 
86
- Value.new(child_ptr, parent: self)
90
+ Value.new(child_ptr, parent: self, context: context)
87
91
  end
88
92
 
89
93
  alias [] child_member
@@ -105,7 +109,10 @@ module LLDB
105
109
  def value_as_signed
106
110
  return 0 unless valid?
107
111
 
108
- FFIBindings.lldb_value_get_value_as_signed(@ptr)
112
+ error = Error.new
113
+ result = FFIBindings.lldb_value_get_value_as_signed(@ptr, error.to_ptr, 0)
114
+ error.raise_if_error!('value.value_as_signed')
115
+ result
109
116
  end
110
117
 
111
118
  alias to_i value_as_signed
@@ -114,7 +121,10 @@ module LLDB
114
121
  def value_as_unsigned
115
122
  return 0 unless valid?
116
123
 
117
- FFIBindings.lldb_value_get_value_as_unsigned(@ptr)
124
+ error = Error.new
125
+ result = FFIBindings.lldb_value_get_value_as_unsigned(@ptr, error.to_ptr, 0)
126
+ error.raise_if_error!('value.value_as_unsigned')
127
+ result
118
128
  end
119
129
 
120
130
  # @rbs return: Integer
@@ -153,7 +163,7 @@ module LLDB
153
163
  deref_ptr = FFIBindings.lldb_value_dereference(@ptr)
154
164
  return nil if deref_ptr.nil? || deref_ptr.null?
155
165
 
156
- Value.new(deref_ptr, parent: self)
166
+ Value.new(deref_ptr, parent: self, context: context)
157
167
  end
158
168
 
159
169
  # @rbs return: Value?
@@ -163,7 +173,7 @@ module LLDB
163
173
  addr_ptr = FFIBindings.lldb_value_address_of(@ptr)
164
174
  return nil if addr_ptr.nil? || addr_ptr.null?
165
175
 
166
- Value.new(addr_ptr, parent: self)
176
+ Value.new(addr_ptr, parent: self, context: context)
167
177
  end
168
178
 
169
179
  # @rbs return: String
@@ -189,7 +199,7 @@ module LLDB
189
199
  type_ptr = FFIBindings.lldb_value_get_type(@ptr)
190
200
  return nil if type_ptr.nil? || type_ptr.null?
191
201
 
192
- Type.new(type_ptr)
202
+ Type.new(type_ptr, context: context)
193
203
  end
194
204
 
195
205
  # @rbs target_type: Type
@@ -200,12 +210,12 @@ module LLDB
200
210
  cast_ptr = FFIBindings.lldb_value_cast(@ptr, target_type.to_ptr)
201
211
  return nil if cast_ptr.nil? || cast_ptr.null?
202
212
 
203
- Value.new(cast_ptr, parent: self)
213
+ Value.new(cast_ptr, parent: self, context: context)
204
214
  end
205
215
 
206
216
  # @rbs return: Integer
207
217
  def load_address
208
- return 0 unless valid?
218
+ return INVALID_ADDRESS unless valid?
209
219
 
210
220
  FFIBindings.lldb_value_get_load_address(@ptr)
211
221
  end
@@ -243,7 +253,7 @@ module LLDB
243
253
  child_ptr = FFIBindings.lldb_value_create_child_at_offset(@ptr, name, value_type.to_ptr, offset)
244
254
  return nil if child_ptr.nil? || child_ptr.null?
245
255
 
246
- Value.new(child_ptr, parent: self)
256
+ Value.new(child_ptr, parent: self, context: context)
247
257
  end
248
258
 
249
259
  # @rbs name: String
@@ -256,7 +266,7 @@ module LLDB
256
266
  value_ptr = FFIBindings.lldb_value_create_value_from_address(@ptr, name, address, value_type.to_ptr)
257
267
  return nil if value_ptr.nil? || value_ptr.null?
258
268
 
259
- Value.new(value_ptr, parent: self)
269
+ Value.new(value_ptr, parent: self, context: context)
260
270
  end
261
271
 
262
272
  # @rbs name: String
@@ -268,7 +278,7 @@ module LLDB
268
278
  value_ptr = FFIBindings.lldb_value_create_value_from_expression(@ptr, name, expression)
269
279
  return nil if value_ptr.nil? || value_ptr.null?
270
280
 
271
- Value.new(value_ptr, parent: self)
281
+ Value.new(value_ptr, parent: self, context: context)
272
282
  end
273
283
 
274
284
  # @rbs resolve: bool
@@ -285,7 +295,7 @@ module LLDB
285
295
  return nil if wp_ptr.nil? || wp_ptr.null?
286
296
 
287
297
  target = get_target_from_parent
288
- Watchpoint.new(wp_ptr, target: target)
298
+ Watchpoint.new(wp_ptr, target: target, context: context)
289
299
  end
290
300
 
291
301
  # @rbs return: String?
@@ -309,7 +319,7 @@ module LLDB
309
319
  value_ptr = FFIBindings.lldb_value_get_non_synthetic_value(@ptr)
310
320
  return nil if value_ptr.nil? || value_ptr.null?
311
321
 
312
- Value.new(value_ptr, parent: self)
322
+ Value.new(value_ptr, parent: self, context: context)
313
323
  end
314
324
 
315
325
  # @rbs return: FFI::Pointer
@@ -4,6 +4,7 @@
4
4
 
5
5
  module LLDB
6
6
  class ValueList
7
+ prepend NativeLifecycle
7
8
  include Enumerable #[Value]
8
9
 
9
10
  # @rbs return: Frame | Value
@@ -12,10 +13,13 @@ module LLDB
12
13
  # @rbs ptr: FFI::Pointer
13
14
  # @rbs parent: Frame | Value
14
15
  # @rbs return: void
15
- def initialize(ptr, parent:)
16
- @ptr = ptr # : FFI::Pointer
16
+ def initialize(ptr, parent:, context: parent.context)
17
17
  @parent = parent
18
- ObjectSpace.define_finalizer(self, self.class.release(@ptr))
18
+ initialize_native_object(
19
+ ptr,
20
+ release: ->(released) { FFIBindings.lldb_value_list_destroy(released) },
21
+ context: context
22
+ )
19
23
  end
20
24
 
21
25
  # @rbs ptr: FFI::Pointer
@@ -46,7 +50,7 @@ module LLDB
46
50
  value_ptr = FFIBindings.lldb_value_list_get_value_at_index(@ptr, index)
47
51
  return nil if value_ptr.nil? || value_ptr.null?
48
52
 
49
- Value.new(value_ptr, parent: @parent)
53
+ Value.new(value_ptr, parent: @parent, context: context)
50
54
  end
51
55
 
52
56
  alias [] value_at_index
@@ -59,7 +63,7 @@ module LLDB
59
63
  value_ptr = FFIBindings.lldb_value_list_get_first_value_by_name(@ptr, name)
60
64
  return nil if value_ptr.nil? || value_ptr.null?
61
65
 
62
- Value.new(value_ptr, parent: @parent)
66
+ Value.new(value_ptr, parent: @parent, context: context)
63
67
  end
64
68
 
65
69
  # @rbs return: Array[Value]
data/lib/lldb/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  # rbs_inline: enabled
4
4
 
5
5
  module LLDB
6
- VERSION = '0.1.0' # : String
6
+ VERSION = '0.3.0' # : String
7
7
  end
@@ -4,16 +4,21 @@
4
4
 
5
5
  module LLDB
6
6
  class Watchpoint
7
+ prepend NativeLifecycle
8
+
7
9
  # @rbs return: Target
8
10
  attr_reader :target
9
11
 
10
12
  # @rbs ptr: FFI::Pointer
11
13
  # @rbs target: Target
12
14
  # @rbs return: void
13
- def initialize(ptr, target:)
14
- @ptr = ptr # : FFI::Pointer
15
+ def initialize(ptr, target:, context: target.context)
15
16
  @target = target
16
- ObjectSpace.define_finalizer(self, self.class.release(@ptr))
17
+ initialize_native_object(
18
+ ptr,
19
+ release: ->(released) { FFIBindings.lldb_watchpoint_destroy(released) },
20
+ context: context
21
+ )
17
22
  end
18
23
 
19
24
  # @rbs ptr: FFI::Pointer
@@ -29,7 +34,7 @@ module LLDB
29
34
 
30
35
  # @rbs return: Integer
31
36
  def id
32
- return -1 unless valid?
37
+ return INVALID_BREAK_ID unless valid?
33
38
 
34
39
  FFIBindings.lldb_watchpoint_get_id(@ptr)
35
40
  end
@@ -99,7 +104,7 @@ module LLDB
99
104
 
100
105
  # @rbs return: Integer
101
106
  def watch_address
102
- return 0 unless valid?
107
+ return INVALID_ADDRESS unless valid?
103
108
 
104
109
  FFIBindings.lldb_watchpoint_get_watch_address(@ptr)
105
110
  end
@@ -113,16 +118,28 @@ module LLDB
113
118
 
114
119
  # @rbs return: bool
115
120
  def watching_reads?
116
- return false unless valid?
121
+ raise InvalidObjectError, 'Watchpoint is not valid' unless valid?
122
+ APISupport.require_feature!(:watchpoint_access_kind)
117
123
 
118
- FFIBindings.lldb_watchpoint_is_watching_reads(@ptr) != 0
124
+ result = FFI::MemoryPointer.new(:int)
125
+ status = FFIBindings.lldb_watchpoint_is_watching_reads(@ptr, result)
126
+ raise UnsupportedAPIError, 'Watchpoint read access is unsupported' if status == NativeStatus::UNSUPPORTED
127
+ raise LLDBError, "Failed to query watchpoint read access (status=#{status})" unless status == NativeStatus::OK
128
+
129
+ result.read_int != 0
119
130
  end
120
131
 
121
132
  # @rbs return: bool
122
133
  def watching_writes?
123
- return false unless valid?
134
+ raise InvalidObjectError, 'Watchpoint is not valid' unless valid?
135
+ APISupport.require_feature!(:watchpoint_access_kind)
136
+
137
+ result = FFI::MemoryPointer.new(:int)
138
+ status = FFIBindings.lldb_watchpoint_is_watching_writes(@ptr, result)
139
+ raise UnsupportedAPIError, 'Watchpoint write access is unsupported' if status == NativeStatus::UNSUPPORTED
140
+ raise LLDBError, "Failed to query watchpoint write access (status=#{status})" unless status == NativeStatus::OK
124
141
 
125
- FFIBindings.lldb_watchpoint_is_watching_writes(@ptr) != 0
142
+ result.read_int != 0
126
143
  end
127
144
 
128
145
  # @rbs return: bool
data/lib/lldb.rb CHANGED
@@ -3,13 +3,30 @@
3
3
  # rbs_inline: enabled
4
4
 
5
5
  require_relative 'lldb/version'
6
+ require_relative 'lldb/error'
6
7
  require_relative 'lldb/ffi_bindings'
7
8
  require_relative 'lldb/types'
8
- require_relative 'lldb/error'
9
+ require_relative 'lldb/native'
10
+ require_relative 'lldb/native_handle'
11
+ require_relative 'lldb/context'
12
+ require_relative 'lldb/native_lifecycle'
13
+ require_relative 'lldb/native_buffer'
14
+ require_relative 'lldb/api_support'
15
+ require_relative 'lldb/native_string_array'
16
+ require_relative 'lldb/file_spec'
17
+ require_relative 'lldb/file_spec_list'
18
+ require_relative 'lldb/address'
19
+ require_relative 'lldb/line_entry'
20
+ require_relative 'lldb/attach_info'
21
+ require_relative 'lldb/expression_options'
22
+ require_relative 'lldb/broadcaster'
23
+ require_relative 'lldb/listener'
24
+ require_relative 'lldb/event'
9
25
  require_relative 'lldb/debugger'
10
26
  require_relative 'lldb/target'
11
27
  require_relative 'lldb/launch_info'
12
28
  require_relative 'lldb/process'
29
+ require_relative 'lldb/memory_region_info'
13
30
  require_relative 'lldb/thread'
14
31
  require_relative 'lldb/frame'
15
32
  require_relative 'lldb/breakpoint'
@@ -17,6 +34,13 @@ require_relative 'lldb/breakpoint_location'
17
34
  require_relative 'lldb/value'
18
35
  require_relative 'lldb/value_list'
19
36
  require_relative 'lldb/type'
37
+ require_relative 'lldb/type_member'
38
+ require_relative 'lldb/symbol'
39
+ require_relative 'lldb/function'
40
+ require_relative 'lldb/compile_unit'
41
+ require_relative 'lldb/block'
42
+ require_relative 'lldb/instruction'
43
+ require_relative 'lldb/instruction_list'
20
44
  require_relative 'lldb/watchpoint'
21
45
  require_relative 'lldb/module'
22
46
  require_relative 'lldb/symbol_context'
@@ -27,20 +51,29 @@ module LLDB
27
51
  class << self
28
52
  # @rbs return: void
29
53
  def initialize
30
- return if @initialized
54
+ lifecycle_mutex.synchronize do
55
+ return if @initialized
31
56
 
32
- FFIBindings.lldb_initialize
33
- @initialized = true
57
+ error = Error.new
58
+ status = FFIBindings.lldb_initialize(error.to_ptr)
59
+ Native.check_status!(status, 'lldb.initialize', error)
60
+ @initialized = true
34
61
 
35
- at_exit { terminate }
62
+ at_exit { terminate if open_debugger_count.zero? }
63
+ end
36
64
  end
37
65
 
38
66
  # @rbs return: void
39
67
  def terminate
40
- return unless @initialized
68
+ lifecycle_mutex.synchronize do
69
+ return unless @initialized
70
+ if live_debugger_count.positive?
71
+ raise LifecycleError, 'cannot terminate LLDB while debuggers are open'
72
+ end
41
73
 
42
- FFIBindings.lldb_terminate
43
- @initialized = false
74
+ FFIBindings.lldb_terminate
75
+ @initialized = false
76
+ end
44
77
  end
45
78
 
46
79
  # @rbs return: bool
@@ -56,9 +89,46 @@ module LLDB
56
89
  end
57
90
 
58
91
  # @rbs return: Debugger
59
- def create_debugger
92
+ def create_debugger(source_init_files: false)
60
93
  LLDB.initialize
61
- Debugger.create
94
+ Debugger.create(source_init_files: source_init_files)
95
+ end
96
+
97
+ # @rbs return: Integer
98
+ def open_debugger_count
99
+ lifecycle_mutex.synchronize { live_debugger_count }
100
+ end
101
+
102
+ # @rbs debugger: Debugger
103
+ # @rbs return: void
104
+ def register_debugger(debugger)
105
+ lifecycle_mutex.synchronize do
106
+ debuggers = (@debuggers ||= []) # : Array[WeakRef]
107
+ debuggers << WeakRef.new(debugger)
108
+ end
109
+ end
110
+
111
+ private
112
+
113
+ # @rbs return: Integer
114
+ def live_debugger_count
115
+ live = [] # : Array[WeakRef]
116
+ count = (@debuggers || []).count do |reference|
117
+ begin
118
+ debugger = reference.__getobj__
119
+ live << reference
120
+ !debugger.closed?
121
+ rescue WeakRef::RefError
122
+ false
123
+ end
124
+ end
125
+ @debuggers = live
126
+ count
127
+ end
128
+
129
+ # @rbs return: Mutex
130
+ def lifecycle_mutex
131
+ @lifecycle_mutex ||= Mutex.new
62
132
  end
63
133
  end
64
134
  end
data/lldb.gemspec CHANGED
@@ -25,7 +25,10 @@ Gem::Specification.new do |spec|
25
25
  end
26
26
  end
27
27
 
28
- spec.files += Dir['lib/**/*.rb', 'ext/**/*']
28
+ generated_extension_file = %r{\Aext/lldb/(?:Makefile|mkmf\.log|lldb_wrapper_config\.h|.*\.(?:o|so|dylib|dll))\z}
29
+ spec.files += Dir['lib/**/*.rb', 'ext/**/*'].select do |file|
30
+ File.file?(file) && !file.match?(generated_extension_file)
31
+ end
29
32
  spec.extensions = ['ext/lldb/extconf.rb']
30
33
  spec.require_paths = ['lib']
31
34
 
data/rbs_collection.yaml CHANGED
@@ -3,7 +3,7 @@ sources:
3
3
  - type: git
4
4
  name: ruby/gem_rbs_collection
5
5
  remote: https://github.com/ruby/gem_rbs_collection.git
6
- revision: main
6
+ revision: b01c0409f55afb1c03e43077c61c44bae61026eb
7
7
  repo_dir: gems
8
8
 
9
9
  # You can specify local directories as sources also.