lldb 0.2.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 +43 -4
  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 +7934 -877
  10. data/ext/lldb/lldb_wrapper.h +596 -333
  11. data/lib/lldb/address.rb +81 -0
  12. data/lib/lldb/api_support.rb +23 -6
  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 +50 -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 +313 -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 +109 -17
  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 +8 -3
  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 +102 -40
  44. data/lib/lldb/symbol.rb +117 -0
  45. data/lib/lldb/symbol_context.rb +9 -4
  46. data/lib/lldb/target.rb +69 -67
  47. data/lib/lldb/thread.rb +51 -18
  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 +78 -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 +247 -21
  61. data/sig/lldb/weak_ref.rbs +7 -0
  62. metadata +30 -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/target.rb CHANGED
@@ -4,19 +4,24 @@
4
4
 
5
5
  module LLDB
6
6
  class Target
7
+ prepend NativeLifecycle
8
+
7
9
  # @rbs return: Debugger
8
10
  attr_reader :debugger
9
11
 
10
12
  # @rbs ptr: FFI::Pointer
11
13
  # @rbs debugger: Debugger
12
14
  # @rbs return: void
13
- def initialize(ptr, debugger:)
14
- @ptr = ptr # : FFI::Pointer
15
+ def initialize(ptr, debugger:, context: debugger.context)
15
16
  @debugger = debugger
16
17
  @breakpoints = [] # : Array[Breakpoint]
17
18
  @watchpoints = [] # : Array[Watchpoint]
18
19
  @process = nil # : Process?
19
- ObjectSpace.define_finalizer(self, self.class.release(@ptr))
20
+ initialize_native_object(
21
+ ptr,
22
+ release: ->(released) { FFIBindings.lldb_target_destroy(released) },
23
+ context: context
24
+ )
20
25
  end
21
26
 
22
27
  # @rbs ptr: FFI::Pointer
@@ -33,38 +38,16 @@ module LLDB
33
38
  # @rbs args: Array[String]?
34
39
  # @rbs env: Hash[String, String]?
35
40
  # @rbs working_dir: String?
41
+ # @rbs launch_flags: Integer?
36
42
  # @rbs return: Process
37
- def launch(args: nil, env: nil, working_dir: nil)
43
+ def launch(args: nil, env: nil, working_dir: nil, launch_flags: nil)
38
44
  raise InvalidObjectError, 'Target is not valid' unless valid?
39
45
 
40
- # Use LaunchInfo with STOP_AT_ENTRY flag for reliable cross-platform behavior
41
- launch_info = LaunchInfo.new(args)
42
- launch_info.launch_flags = LaunchFlags::STOP_AT_ENTRY
46
+ launch_info = LaunchInfo.new(args, context: context)
47
+ launch_info.launch_flags = launch_flags unless launch_flags.nil?
43
48
  launch_info.working_directory = working_dir if working_dir
44
49
  launch_info.set_environment(env) if env
45
-
46
- error = Error.new
47
- process_ptr = FFIBindings.lldb_target_launch(@ptr, launch_info.to_ptr, error.to_ptr)
48
-
49
- error.raise_if_error!
50
- raise LaunchError, 'Failed to launch process' if process_ptr.nil? || process_ptr.null?
51
-
52
- @process = Process.new(process_ptr, target: self)
53
-
54
- # Wait for process to stop when in synchronous mode
55
- # On some platforms (Linux), the process may not be immediately stopped
56
- unless @debugger.async?
57
- wait_for_process_stop(@process)
58
-
59
- # STOP_AT_ENTRY stops at the program entry point, not at breakpoints.
60
- # If there are breakpoints set, continue to let the process run to the first breakpoint.
61
- if num_breakpoints > 0 && @process.state == State::STOPPED && @process.valid?
62
- @process.continue
63
- wait_for_process_stop(@process)
64
- end
65
- end
66
-
67
- @process
50
+ launch_with_info(launch_info)
68
51
  end
69
52
 
70
53
  # @rbs launch_info: LaunchInfo
@@ -76,10 +59,10 @@ module LLDB
76
59
  error = Error.new
77
60
  process_ptr = FFIBindings.lldb_target_launch(@ptr, launch_info.to_ptr, error.to_ptr)
78
61
 
79
- error.raise_if_error!
62
+ error.raise_if_error!('target.launch')
80
63
  raise LaunchError, 'Failed to launch process' if process_ptr.nil? || process_ptr.null?
81
64
 
82
- @process = Process.new(process_ptr, target: self)
65
+ @process = Process.new(process_ptr, target: self, context: context)
83
66
  end
84
67
 
85
68
  # @rbs pid: Integer
@@ -93,7 +76,22 @@ module LLDB
93
76
  error.raise_if_error!
94
77
  raise AttachError, "Failed to attach to process #{pid}" if process_ptr.nil? || process_ptr.null?
95
78
 
96
- @process = Process.new(process_ptr, target: self)
79
+ @process = Process.new(process_ptr, target: self, context: context)
80
+ end
81
+
82
+ # @rbs attach_info: AttachInfo
83
+ # @rbs return: Process
84
+ def attach_with_info(attach_info)
85
+ raise InvalidObjectError, 'Target is not valid' unless valid?
86
+ raise ArgumentError, 'attach_info is required' unless attach_info.is_a?(AttachInfo)
87
+
88
+ error = Error.new
89
+ process_ptr = FFIBindings.lldb_target_attach_with_info(@ptr, attach_info.to_ptr, error.to_ptr)
90
+
91
+ error.raise_if_error!('target.attach')
92
+ raise AttachError, 'Failed to attach using attach info' if process_ptr.nil? || process_ptr.null?
93
+
94
+ @process = Process.new(process_ptr, target: self, context: context)
97
95
  end
98
96
 
99
97
  # @rbs symbol_name: String
@@ -105,7 +103,7 @@ module LLDB
105
103
  bp_ptr = FFIBindings.lldb_target_breakpoint_create_by_name(@ptr, symbol_name, module_name)
106
104
  raise BreakpointError, "Failed to create breakpoint for '#{symbol_name}'" if bp_ptr.nil? || bp_ptr.null?
107
105
 
108
- bp = Breakpoint.new(bp_ptr, target: self)
106
+ bp = Breakpoint.new(bp_ptr, target: self, context: context)
109
107
  @breakpoints << bp
110
108
  bp
111
109
  end
@@ -119,7 +117,7 @@ module LLDB
119
117
  bp_ptr = FFIBindings.lldb_target_breakpoint_create_by_location(@ptr, file, line)
120
118
  raise BreakpointError, "Failed to create breakpoint at #{file}:#{line}" if bp_ptr.nil? || bp_ptr.null?
121
119
 
122
- bp = Breakpoint.new(bp_ptr, target: self)
120
+ bp = Breakpoint.new(bp_ptr, target: self, context: context)
123
121
  @breakpoints << bp
124
122
  bp
125
123
  end
@@ -137,7 +135,7 @@ module LLDB
137
135
  "Failed to create breakpoint at address 0x#{address.to_s(16)}"
138
136
  end
139
137
 
140
- bp = Breakpoint.new(bp_ptr, target: self)
138
+ bp = Breakpoint.new(bp_ptr, target: self, context: context)
141
139
  @breakpoints << bp
142
140
  bp
143
141
  end
@@ -160,7 +158,7 @@ module LLDB
160
158
  bp_ptr = FFIBindings.lldb_target_find_breakpoint_by_id(@ptr, id)
161
159
  return nil if bp_ptr.nil? || bp_ptr.null?
162
160
 
163
- Breakpoint.new(bp_ptr, target: self)
161
+ Breakpoint.new(bp_ptr, target: self, context: context)
164
162
  end
165
163
 
166
164
  # @rbs return: Integer
@@ -178,7 +176,7 @@ module LLDB
178
176
  bp_ptr = FFIBindings.lldb_target_get_breakpoint_at_index(@ptr, index)
179
177
  return nil if bp_ptr.nil? || bp_ptr.null?
180
178
 
181
- Breakpoint.new(bp_ptr, target: self)
179
+ Breakpoint.new(bp_ptr, target: self, context: context)
182
180
  end
183
181
 
184
182
  # @rbs return: Array[Breakpoint]
@@ -193,14 +191,24 @@ module LLDB
193
191
  process_ptr = FFIBindings.lldb_target_get_process(@ptr)
194
192
  return nil if process_ptr.nil? || process_ptr.null?
195
193
 
196
- Process.new(process_ptr, target: self)
194
+ Process.new(process_ptr, target: self, context: context)
197
195
  end
198
196
 
199
197
  # @rbs return: String?
200
198
  def executable_path
201
199
  raise InvalidObjectError, 'Target is not valid' unless valid?
202
200
 
203
- FFIBindings.lldb_target_get_executable_path(@ptr)
201
+ executable_file&.path
202
+ end
203
+
204
+ # @rbs return: FileSpec?
205
+ def executable_file
206
+ raise InvalidObjectError, 'Target is not valid' unless valid?
207
+
208
+ file_ptr = FFIBindings.lldb_target_get_executable_file(@ptr)
209
+ return nil if file_ptr.nil? || file_ptr.null?
210
+
211
+ FileSpec.from_ptr(file_ptr, context: context)
204
212
  end
205
213
 
206
214
  # @rbs return: Integer
@@ -218,7 +226,7 @@ module LLDB
218
226
  mod_ptr = FFIBindings.lldb_target_get_module_at_index(@ptr, index)
219
227
  return nil if mod_ptr.nil? || mod_ptr.null?
220
228
 
221
- Module.new(mod_ptr, target: self)
229
+ Module.new(mod_ptr, target: self, context: context)
222
230
  end
223
231
 
224
232
  # @rbs return: Array[Module]
@@ -238,7 +246,7 @@ module LLDB
238
246
  error.raise_if_error!
239
247
  raise AttachError, "Failed to attach to process '#{name}'" if process_ptr.nil? || process_ptr.null?
240
248
 
241
- @process = Process.new(process_ptr, target: self)
249
+ @process = Process.new(process_ptr, target: self, context: context)
242
250
  end
243
251
 
244
252
  # @rbs regex: String
@@ -252,7 +260,7 @@ module LLDB
252
260
  bp_ptr = FFIBindings.lldb_target_breakpoint_create_by_regex(@ptr, regex, module_name)
253
261
  raise BreakpointError, "Failed to create breakpoint for regex '#{regex}'" if bp_ptr.nil? || bp_ptr.null?
254
262
 
255
- bp = Breakpoint.new(bp_ptr, target: self)
263
+ bp = Breakpoint.new(bp_ptr, target: self, context: context)
256
264
  @breakpoints << bp
257
265
  bp
258
266
  end
@@ -266,7 +274,7 @@ module LLDB
266
274
  bp_ptr = FFIBindings.lldb_target_breakpoint_create_by_source_regex(@ptr, regex, source_file)
267
275
  raise BreakpointError, "Failed to create breakpoint for source regex '#{regex}'" if bp_ptr.nil? || bp_ptr.null?
268
276
 
269
- bp = Breakpoint.new(bp_ptr, target: self)
277
+ bp = Breakpoint.new(bp_ptr, target: self, context: context)
270
278
  @breakpoints << bp
271
279
  bp
272
280
  end
@@ -295,14 +303,25 @@ module LLDB
295
303
  end
296
304
 
297
305
  # @rbs expression: String
306
+ # @rbs options: ExpressionOptions?
298
307
  # @rbs return: Value?
299
- def evaluate_expression(expression)
308
+ def evaluate_expression(expression, options: nil)
300
309
  raise InvalidObjectError, 'Target is not valid' unless valid?
301
310
 
302
- value_ptr = FFIBindings.lldb_target_evaluate_expression(@ptr, expression)
311
+ value_ptr = if options
312
+ unless options.is_a?(ExpressionOptions)
313
+ raise ArgumentError, 'options must be an ExpressionOptions'
314
+ end
315
+
316
+ FFIBindings.lldb_target_evaluate_expression_with_options(
317
+ @ptr, expression, options.to_ptr
318
+ )
319
+ else
320
+ FFIBindings.lldb_target_evaluate_expression(@ptr, expression)
321
+ end
303
322
  return nil if value_ptr.nil? || value_ptr.null?
304
323
 
305
- Value.new(value_ptr, parent: self)
324
+ Value.new(value_ptr, parent: self, context: context)
306
325
  end
307
326
 
308
327
  # @rbs address: Integer
@@ -347,7 +366,7 @@ module LLDB
347
366
  error.raise_if_error!
348
367
  raise LLDBError, "Failed to create watchpoint at address 0x#{address.to_s(16)}" if wp_ptr.nil? || wp_ptr.null?
349
368
 
350
- wp = Watchpoint.new(wp_ptr, target: self)
369
+ wp = Watchpoint.new(wp_ptr, target: self, context: context)
351
370
  @watchpoints << wp
352
371
  wp
353
372
  end
@@ -379,7 +398,7 @@ module LLDB
379
398
  wp_ptr = FFIBindings.lldb_target_find_watchpoint_by_id(@ptr, id)
380
399
  return nil if wp_ptr.nil? || wp_ptr.null?
381
400
 
382
- Watchpoint.new(wp_ptr, target: self)
401
+ Watchpoint.new(wp_ptr, target: self, context: context)
383
402
  end
384
403
 
385
404
  # @rbs return: Integer
@@ -397,7 +416,7 @@ module LLDB
397
416
  wp_ptr = FFIBindings.lldb_target_get_watchpoint_at_index(@ptr, index)
398
417
  return nil if wp_ptr.nil? || wp_ptr.null?
399
418
 
400
- Watchpoint.new(wp_ptr, target: self)
419
+ Watchpoint.new(wp_ptr, target: self, context: context)
401
420
  end
402
421
 
403
422
  # @rbs return: Array[Watchpoint]
@@ -410,22 +429,5 @@ module LLDB
410
429
  @ptr
411
430
  end
412
431
 
413
- private
414
-
415
- # @rbs process: Process
416
- # @rbs timeout: Float
417
- # @rbs return: void
418
- def wait_for_process_stop(process, timeout: 10.0)
419
- require 'timeout'
420
-
421
- Timeout.timeout(timeout, LaunchError, "Process failed to stop within #{timeout} seconds") do
422
- loop do
423
- state = process.state
424
- break if state == State::STOPPED || state == State::EXITED || state == State::CRASHED
425
-
426
- sleep(0.01)
427
- end
428
- end
429
- end
430
432
  end
431
433
  end
data/lib/lldb/thread.rb CHANGED
@@ -4,16 +4,21 @@
4
4
 
5
5
  module LLDB
6
6
  class Thread
7
+ prepend NativeLifecycle
8
+
7
9
  # @rbs return: Process
8
10
  attr_reader :process
9
11
 
10
12
  # @rbs ptr: FFI::Pointer
11
13
  # @rbs process: Process
12
14
  # @rbs return: void
13
- def initialize(ptr, process:)
14
- @ptr = ptr # : FFI::Pointer
15
+ def initialize(ptr, process:, context: process.context)
15
16
  @process = process
16
- ObjectSpace.define_finalizer(self, self.class.release(@ptr))
17
+ initialize_native_object(
18
+ ptr,
19
+ release: ->(released) { FFIBindings.lldb_thread_destroy(released) },
20
+ context: context
21
+ )
17
22
  end
18
23
 
19
24
  # @rbs ptr: FFI::Pointer
@@ -27,37 +32,59 @@ module LLDB
27
32
  !@ptr.null? && FFIBindings.lldb_thread_is_valid(@ptr) != 0
28
33
  end
29
34
 
30
- # @rbs return: bool
31
- def step_over
35
+ # @rbs run_mode: Integer
36
+ # @rbs return: true
37
+ def step_over(run_mode: RunMode::ONLY_DURING_STEPPING)
32
38
  raise InvalidObjectError, 'Thread is not valid' unless valid?
33
39
  APISupport.require_method!(:lldb_thread_step_over, 'step_over')
34
40
 
35
- FFIBindings.lldb_thread_step_over(@ptr) != 0
41
+ error = Error.new
42
+ status = FFIBindings.lldb_thread_step_over(@ptr, run_mode, error.to_ptr)
43
+ Native.check_status!(status, 'thread.step_over', error)
44
+ true
36
45
  end
37
46
 
38
- # @rbs return: bool
39
- def step_into
47
+ # @rbs target_name: String?
48
+ # @rbs end_line: Integer
49
+ # @rbs run_mode: Integer
50
+ # @rbs return: true
51
+ def step_into(target_name: nil, end_line: INVALID_LINE_NUMBER, run_mode: RunMode::ONLY_DURING_STEPPING)
40
52
  raise InvalidObjectError, 'Thread is not valid' unless valid?
41
53
  APISupport.require_method!(:lldb_thread_step_into, 'step_into')
42
54
 
43
- FFIBindings.lldb_thread_step_into(@ptr) != 0
55
+ error = Error.new
56
+ status = FFIBindings.lldb_thread_step_into(
57
+ @ptr,
58
+ target_name,
59
+ end_line,
60
+ run_mode,
61
+ error.to_ptr
62
+ )
63
+ Native.check_status!(status, 'thread.step_into', error)
64
+ true
44
65
  end
45
66
 
46
- # @rbs return: bool
67
+ # @rbs return: true
47
68
  def step_out
48
69
  raise InvalidObjectError, 'Thread is not valid' unless valid?
49
70
  APISupport.require_method!(:lldb_thread_step_out, 'step_out')
50
71
 
51
- FFIBindings.lldb_thread_step_out(@ptr) != 0
72
+ error = Error.new
73
+ status = FFIBindings.lldb_thread_step_out(@ptr, error.to_ptr)
74
+ Native.check_status!(status, 'thread.step_out', error)
75
+ true
52
76
  end
53
77
 
54
78
  # @rbs step_over: bool
55
- # @rbs return: bool
79
+ # @rbs return: true
56
80
  def step_instruction(step_over: false)
57
81
  raise InvalidObjectError, 'Thread is not valid' unless valid?
58
82
  APISupport.require_method!(:lldb_thread_step_instruction, 'step_instruction')
59
83
 
60
- FFIBindings.lldb_thread_step_instruction(@ptr, step_over ? 1 : 0) != 0
84
+ error = Error.new
85
+ status = FFIBindings.lldb_thread_step_instruction(@ptr, step_over ? 1 : 0, error.to_ptr)
86
+ Native.check_status!(status, 'thread.step_instruction', error)
87
+ true
61
88
  end
62
89
 
63
90
  # @rbs return: Integer
@@ -75,7 +102,7 @@ module LLDB
75
102
  frame_ptr = FFIBindings.lldb_thread_get_frame_at_index(@ptr, index)
76
103
  return nil if frame_ptr.nil? || frame_ptr.null?
77
104
 
78
- Frame.new(frame_ptr, thread: self)
105
+ Frame.new(frame_ptr, thread: self, context: context)
79
106
  end
80
107
 
81
108
  # @rbs return: Frame?
@@ -85,7 +112,7 @@ module LLDB
85
112
  frame_ptr = FFIBindings.lldb_thread_get_selected_frame(@ptr)
86
113
  return nil if frame_ptr.nil? || frame_ptr.null?
87
114
 
88
- Frame.new(frame_ptr, thread: self)
115
+ Frame.new(frame_ptr, thread: self, context: context)
89
116
  end
90
117
 
91
118
  # @rbs index: Integer
@@ -159,7 +186,10 @@ module LLDB
159
186
  def run_to_address(address)
160
187
  raise InvalidObjectError, 'Thread is not valid' unless valid?
161
188
 
162
- FFIBindings.lldb_thread_run_to_address(@ptr, address) != 0
189
+ error = Error.new
190
+ status = FFIBindings.lldb_thread_run_to_address(@ptr, address, error.to_ptr)
191
+ Native.check_status!(status, 'thread.run_to_address', error)
192
+ true
163
193
  end
164
194
 
165
195
  # @rbs return: Integer
@@ -180,8 +210,11 @@ module LLDB
180
210
  # @rbs return: String?
181
211
  def stop_description(max_size = 256)
182
212
  return nil unless valid?
213
+ return '' if max_size.zero?
183
214
 
184
- FFIBindings.lldb_thread_get_stop_description(@ptr, max_size)
215
+ NativeBuffer.read_c_string(max_size: max_size) do |buffer, length|
216
+ FFIBindings.lldb_thread_get_stop_description(@ptr, buffer, length)
217
+ end
185
218
  end
186
219
 
187
220
  # @rbs return: bool
@@ -219,7 +252,7 @@ module LLDB
219
252
  process_ptr = FFIBindings.lldb_thread_get_process(@ptr)
220
253
  return nil if process_ptr.nil? || process_ptr.null?
221
254
 
222
- Process.new(process_ptr, target: @process.target)
255
+ Process.new(process_ptr, target: @process.target, context: context)
223
256
  end
224
257
 
225
258
  # @rbs return: FFI::Pointer
data/lib/lldb/type.rb CHANGED
@@ -4,11 +4,16 @@
4
4
 
5
5
  module LLDB
6
6
  class Type
7
+ prepend NativeLifecycle
8
+
7
9
  # @rbs ptr: FFI::Pointer
8
10
  # @rbs return: void
9
- def initialize(ptr)
10
- @ptr = ptr # : FFI::Pointer
11
- ObjectSpace.define_finalizer(self, self.class.release(@ptr))
11
+ def initialize(ptr, context: nil)
12
+ initialize_native_object(
13
+ ptr,
14
+ release: ->(released) { FFIBindings.lldb_type_destroy(released) },
15
+ context: context
16
+ )
12
17
  end
13
18
 
14
19
  # @rbs ptr: FFI::Pointer
@@ -190,6 +195,24 @@ module LLDB
190
195
  FFIBindings.lldb_type_get_num_virtual_base_classes(@ptr)
191
196
  end
192
197
 
198
+ # @rbs index: Integer
199
+ # @rbs return: TypeMember?
200
+ def field_at_index(index)
201
+ member_at(index, :lldb_type_get_field_at_index)
202
+ end
203
+
204
+ # @rbs index: Integer
205
+ # @rbs return: TypeMember?
206
+ def direct_base_class_at_index(index)
207
+ member_at(index, :lldb_type_get_direct_base_class_at_index)
208
+ end
209
+
210
+ # @rbs index: Integer
211
+ # @rbs return: TypeMember?
212
+ def virtual_base_class_at_index(index)
213
+ member_at(index, :lldb_type_get_virtual_base_class_at_index)
214
+ end
215
+
193
216
  # @rbs return: Integer
194
217
  def basic_type
195
218
  return BasicType::INVALID unless valid?
@@ -211,5 +234,19 @@ module LLDB
211
234
  def to_ptr
212
235
  @ptr
213
236
  end
237
+
238
+ private
239
+
240
+ # @rbs index: Integer
241
+ # @rbs method_name: ::Symbol
242
+ # @rbs return: TypeMember?
243
+ def member_at(index, method_name)
244
+ raise InvalidObjectError, 'Type is not valid' unless valid?
245
+
246
+ member_ptr = FFIBindings.public_send(method_name, @ptr, index)
247
+ return nil if member_ptr.nil? || member_ptr.null?
248
+
249
+ TypeMember.new(member_ptr, context: context)
250
+ end
214
251
  end
215
252
  end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module LLDB
6
+ class TypeMember
7
+ prepend NativeLifecycle
8
+
9
+ # @rbs context: Context?
10
+ # @rbs return: void
11
+ def initialize(ptr, context: nil)
12
+ initialize_native_object(
13
+ ptr,
14
+ release: ->(released) { FFIBindings.lldb_type_member_destroy(released) },
15
+ context: context
16
+ )
17
+ end
18
+
19
+ # @rbs return: bool
20
+ def valid?
21
+ !@ptr.null? && FFIBindings.lldb_type_member_is_valid(@ptr) != 0
22
+ end
23
+
24
+ # @rbs return: String?
25
+ def name
26
+ return nil unless valid?
27
+
28
+ FFIBindings.lldb_type_member_get_name(@ptr)
29
+ end
30
+
31
+ # @rbs return: Type?
32
+ def type
33
+ return nil unless valid?
34
+
35
+ ptr = FFIBindings.lldb_type_member_get_type(@ptr)
36
+ return nil if ptr.nil? || ptr.null?
37
+
38
+ Type.new(ptr, context: context)
39
+ end
40
+
41
+ # @rbs return: Integer
42
+ def offset_in_bytes
43
+ return 0 unless valid?
44
+
45
+ FFIBindings.lldb_type_member_get_offset_in_bytes(@ptr)
46
+ end
47
+
48
+ # @rbs return: Integer
49
+ def offset_in_bits
50
+ return 0 unless valid?
51
+
52
+ FFIBindings.lldb_type_member_get_offset_in_bits(@ptr)
53
+ end
54
+
55
+ # @rbs return: Integer
56
+ def bitfield_size_in_bits
57
+ return 0 unless valid?
58
+
59
+ FFIBindings.lldb_type_member_get_bitfield_size_in_bits(@ptr)
60
+ end
61
+
62
+ # @rbs return: FFI::Pointer
63
+ def to_ptr
64
+ @ptr
65
+ end
66
+ end
67
+ end
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