lldb 0.1.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.
@@ -0,0 +1,427 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module LLDB
6
+ class Target
7
+ # @rbs return: Debugger
8
+ attr_reader :debugger
9
+
10
+ # @rbs ptr: FFI::Pointer
11
+ # @rbs debugger: Debugger
12
+ # @rbs return: void
13
+ def initialize(ptr, debugger:)
14
+ @ptr = ptr # : FFI::Pointer
15
+ @debugger = debugger
16
+ @breakpoints = [] # : Array[Breakpoint]
17
+ @watchpoints = [] # : Array[Watchpoint]
18
+ @process = nil # : Process?
19
+ ObjectSpace.define_finalizer(self, self.class.release(@ptr))
20
+ end
21
+
22
+ # @rbs ptr: FFI::Pointer
23
+ # @rbs return: ^(Integer) -> void
24
+ def self.release(ptr)
25
+ ->(_id) { FFIBindings.lldb_target_destroy(ptr) unless ptr.null? }
26
+ end
27
+
28
+ # @rbs return: bool
29
+ def valid?
30
+ !@ptr.null? && FFIBindings.lldb_target_is_valid(@ptr) != 0
31
+ end
32
+
33
+ # @rbs args: Array[String]?
34
+ # @rbs env: Hash[String, String]?
35
+ # @rbs working_dir: String?
36
+ # @rbs return: Process
37
+ def launch(args: nil, env: nil, working_dir: nil)
38
+ raise InvalidObjectError, 'Target is not valid' unless valid?
39
+
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
43
+ launch_info.working_directory = working_dir if working_dir
44
+ 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
68
+ end
69
+
70
+ # @rbs launch_info: LaunchInfo
71
+ # @rbs return: Process
72
+ def launch_with_info(launch_info)
73
+ raise InvalidObjectError, 'Target is not valid' unless valid?
74
+ raise ArgumentError, 'launch_info is required' unless launch_info
75
+
76
+ error = Error.new
77
+ process_ptr = FFIBindings.lldb_target_launch(@ptr, launch_info.to_ptr, error.to_ptr)
78
+
79
+ error.raise_if_error!
80
+ raise LaunchError, 'Failed to launch process' if process_ptr.nil? || process_ptr.null?
81
+
82
+ @process = Process.new(process_ptr, target: self)
83
+ end
84
+
85
+ # @rbs pid: Integer
86
+ # @rbs return: Process
87
+ def attach(pid:)
88
+ raise InvalidObjectError, 'Target is not valid' unless valid?
89
+
90
+ error = Error.new
91
+ process_ptr = FFIBindings.lldb_target_attach_to_process_with_id(@ptr, pid, error.to_ptr)
92
+
93
+ error.raise_if_error!
94
+ raise AttachError, "Failed to attach to process #{pid}" if process_ptr.nil? || process_ptr.null?
95
+
96
+ @process = Process.new(process_ptr, target: self)
97
+ end
98
+
99
+ # @rbs symbol_name: String
100
+ # @rbs module_name: String?
101
+ # @rbs return: Breakpoint
102
+ def breakpoint_create_by_name(symbol_name, module_name: nil)
103
+ raise InvalidObjectError, 'Target is not valid' unless valid?
104
+
105
+ bp_ptr = FFIBindings.lldb_target_breakpoint_create_by_name(@ptr, symbol_name, module_name)
106
+ raise BreakpointError, "Failed to create breakpoint for '#{symbol_name}'" if bp_ptr.nil? || bp_ptr.null?
107
+
108
+ bp = Breakpoint.new(bp_ptr, target: self)
109
+ @breakpoints << bp
110
+ bp
111
+ end
112
+
113
+ # @rbs file: String
114
+ # @rbs line: Integer
115
+ # @rbs return: Breakpoint
116
+ def breakpoint_create_by_location(file, line)
117
+ raise InvalidObjectError, 'Target is not valid' unless valid?
118
+
119
+ bp_ptr = FFIBindings.lldb_target_breakpoint_create_by_location(@ptr, file, line)
120
+ raise BreakpointError, "Failed to create breakpoint at #{file}:#{line}" if bp_ptr.nil? || bp_ptr.null?
121
+
122
+ bp = Breakpoint.new(bp_ptr, target: self)
123
+ @breakpoints << bp
124
+ bp
125
+ end
126
+
127
+ # @rbs address: Integer
128
+ # @rbs return: Breakpoint
129
+ def breakpoint_create_by_address(address)
130
+ raise InvalidObjectError, 'Target is not valid' unless valid?
131
+
132
+ bp_ptr = FFIBindings.lldb_target_breakpoint_create_by_address(@ptr, address)
133
+ if bp_ptr.nil? || bp_ptr.null?
134
+ raise BreakpointError,
135
+ "Failed to create breakpoint at address 0x#{address.to_s(16)}"
136
+ end
137
+
138
+ bp = Breakpoint.new(bp_ptr, target: self)
139
+ @breakpoints << bp
140
+ bp
141
+ end
142
+
143
+ # @rbs breakpoint_id: Integer
144
+ # @rbs return: bool
145
+ def delete_breakpoint(breakpoint_id)
146
+ raise InvalidObjectError, 'Target is not valid' unless valid?
147
+
148
+ result = FFIBindings.lldb_target_delete_breakpoint(@ptr, breakpoint_id)
149
+ @breakpoints.reject! { |bp| bp.id == breakpoint_id } if result != 0
150
+ result != 0
151
+ end
152
+
153
+ # @rbs id: Integer
154
+ # @rbs return: Breakpoint?
155
+ def find_breakpoint_by_id(id)
156
+ raise InvalidObjectError, 'Target is not valid' unless valid?
157
+
158
+ bp_ptr = FFIBindings.lldb_target_find_breakpoint_by_id(@ptr, id)
159
+ return nil if bp_ptr.nil? || bp_ptr.null?
160
+
161
+ Breakpoint.new(bp_ptr, target: self)
162
+ end
163
+
164
+ # @rbs return: Integer
165
+ def num_breakpoints
166
+ return 0 unless valid?
167
+
168
+ FFIBindings.lldb_target_get_num_breakpoints(@ptr)
169
+ end
170
+
171
+ # @rbs index: Integer
172
+ # @rbs return: Breakpoint?
173
+ def breakpoint_at_index(index)
174
+ raise InvalidObjectError, 'Target is not valid' unless valid?
175
+
176
+ bp_ptr = FFIBindings.lldb_target_get_breakpoint_at_index(@ptr, index)
177
+ return nil if bp_ptr.nil? || bp_ptr.null?
178
+
179
+ Breakpoint.new(bp_ptr, target: self)
180
+ end
181
+
182
+ # @rbs return: Array[Breakpoint]
183
+ def breakpoints
184
+ (0...num_breakpoints).map { |i| breakpoint_at_index(i) }.compact
185
+ end
186
+
187
+ # @rbs return: Process?
188
+ def process
189
+ raise InvalidObjectError, 'Target is not valid' unless valid?
190
+
191
+ process_ptr = FFIBindings.lldb_target_get_process(@ptr)
192
+ return nil if process_ptr.nil? || process_ptr.null?
193
+
194
+ Process.new(process_ptr, target: self)
195
+ end
196
+
197
+ # @rbs return: String?
198
+ def executable_path
199
+ raise InvalidObjectError, 'Target is not valid' unless valid?
200
+
201
+ FFIBindings.lldb_target_get_executable_path(@ptr)
202
+ end
203
+
204
+ # @rbs return: Integer
205
+ def num_modules
206
+ return 0 unless valid?
207
+
208
+ FFIBindings.lldb_target_get_num_modules(@ptr)
209
+ end
210
+
211
+ # @rbs index: Integer
212
+ # @rbs return: Module?
213
+ def module_at_index(index)
214
+ raise InvalidObjectError, 'Target is not valid' unless valid?
215
+
216
+ mod_ptr = FFIBindings.lldb_target_get_module_at_index(@ptr, index)
217
+ return nil if mod_ptr.nil? || mod_ptr.null?
218
+
219
+ Module.new(mod_ptr, target: self)
220
+ end
221
+
222
+ # @rbs return: Array[Module]
223
+ def modules
224
+ (0...num_modules).map { |i| module_at_index(i) }.compact
225
+ end
226
+
227
+ # @rbs name: String
228
+ # @rbs wait_for: bool
229
+ # @rbs return: Process
230
+ def attach_with_name(name, wait_for: false)
231
+ raise InvalidObjectError, 'Target is not valid' unless valid?
232
+
233
+ error = Error.new
234
+ process_ptr = FFIBindings.lldb_target_attach_to_process_with_name(@ptr, name, wait_for ? 1 : 0, error.to_ptr)
235
+
236
+ error.raise_if_error!
237
+ raise AttachError, "Failed to attach to process '#{name}'" if process_ptr.nil? || process_ptr.null?
238
+
239
+ @process = Process.new(process_ptr, target: self)
240
+ end
241
+
242
+ # @rbs regex: String
243
+ # @rbs module_name: String?
244
+ # @rbs return: Breakpoint
245
+ def breakpoint_create_by_regex(regex, module_name: nil)
246
+ raise InvalidObjectError, 'Target is not valid' unless valid?
247
+
248
+ bp_ptr = FFIBindings.lldb_target_breakpoint_create_by_regex(@ptr, regex, module_name)
249
+ raise BreakpointError, "Failed to create breakpoint for regex '#{regex}'" if bp_ptr.nil? || bp_ptr.null?
250
+
251
+ bp = Breakpoint.new(bp_ptr, target: self)
252
+ @breakpoints << bp
253
+ bp
254
+ end
255
+
256
+ # @rbs regex: String
257
+ # @rbs source_file: String?
258
+ # @rbs return: Breakpoint
259
+ def breakpoint_create_by_source_regex(regex, source_file: nil)
260
+ raise InvalidObjectError, 'Target is not valid' unless valid?
261
+
262
+ bp_ptr = FFIBindings.lldb_target_breakpoint_create_by_source_regex(@ptr, regex, source_file)
263
+ raise BreakpointError, "Failed to create breakpoint for source regex '#{regex}'" if bp_ptr.nil? || bp_ptr.null?
264
+
265
+ bp = Breakpoint.new(bp_ptr, target: self)
266
+ @breakpoints << bp
267
+ bp
268
+ end
269
+
270
+ # @rbs return: bool
271
+ def delete_all_breakpoints
272
+ raise InvalidObjectError, 'Target is not valid' unless valid?
273
+
274
+ result = FFIBindings.lldb_target_delete_all_breakpoints(@ptr) != 0
275
+ @breakpoints.clear if result
276
+ result
277
+ end
278
+
279
+ # @rbs return: bool
280
+ def enable_all_breakpoints
281
+ raise InvalidObjectError, 'Target is not valid' unless valid?
282
+
283
+ FFIBindings.lldb_target_enable_all_breakpoints(@ptr) != 0
284
+ end
285
+
286
+ # @rbs return: bool
287
+ def disable_all_breakpoints
288
+ raise InvalidObjectError, 'Target is not valid' unless valid?
289
+
290
+ FFIBindings.lldb_target_disable_all_breakpoints(@ptr) != 0
291
+ end
292
+
293
+ # @rbs expression: String
294
+ # @rbs return: Value?
295
+ def evaluate_expression(expression)
296
+ raise InvalidObjectError, 'Target is not valid' unless valid?
297
+
298
+ value_ptr = FFIBindings.lldb_target_evaluate_expression(@ptr, expression)
299
+ return nil if value_ptr.nil? || value_ptr.null?
300
+
301
+ Value.new(value_ptr, parent: self)
302
+ end
303
+
304
+ # @rbs address: Integer
305
+ # @rbs size: Integer
306
+ # @rbs return: String
307
+ def read_memory(address, size)
308
+ raise InvalidObjectError, 'Target is not valid' unless valid?
309
+
310
+ buffer = FFI::MemoryPointer.new(:uint8, size)
311
+ error = Error.new
312
+ bytes_read = FFIBindings.lldb_target_read_memory(@ptr, address, buffer, size, error.to_ptr)
313
+
314
+ error.raise_if_error!
315
+ buffer.read_string(bytes_read)
316
+ end
317
+
318
+ # @rbs return: Integer
319
+ def address_byte_size
320
+ return 0 unless valid?
321
+
322
+ FFIBindings.lldb_target_get_address_byte_size(@ptr)
323
+ end
324
+
325
+ # @rbs return: String?
326
+ def triple
327
+ return nil unless valid?
328
+
329
+ FFIBindings.lldb_target_get_triple(@ptr)
330
+ end
331
+
332
+ # @rbs address: Integer
333
+ # @rbs size: Integer
334
+ # @rbs read: bool
335
+ # @rbs write: bool
336
+ # @rbs return: Watchpoint
337
+ def watch_address(address, size, read: false, write: true)
338
+ raise InvalidObjectError, 'Target is not valid' unless valid?
339
+
340
+ error = Error.new
341
+ wp_ptr = FFIBindings.lldb_target_watch_address(@ptr, address, size, read ? 1 : 0, write ? 1 : 0, error.to_ptr)
342
+
343
+ error.raise_if_error!
344
+ raise LLDBError, "Failed to create watchpoint at address 0x#{address.to_s(16)}" if wp_ptr.nil? || wp_ptr.null?
345
+
346
+ wp = Watchpoint.new(wp_ptr, target: self)
347
+ @watchpoints << wp
348
+ wp
349
+ end
350
+
351
+ # @rbs watchpoint_id: Integer
352
+ # @rbs return: bool
353
+ def delete_watchpoint(watchpoint_id)
354
+ raise InvalidObjectError, 'Target is not valid' unless valid?
355
+
356
+ result = FFIBindings.lldb_target_delete_watchpoint(@ptr, watchpoint_id)
357
+ @watchpoints.reject! { |wp| wp.id == watchpoint_id } if result != 0
358
+ result != 0
359
+ end
360
+
361
+ # @rbs return: bool
362
+ def delete_all_watchpoints
363
+ raise InvalidObjectError, 'Target is not valid' unless valid?
364
+
365
+ result = FFIBindings.lldb_target_delete_all_watchpoints(@ptr) != 0
366
+ @watchpoints.clear if result
367
+ result
368
+ end
369
+
370
+ # @rbs id: Integer
371
+ # @rbs return: Watchpoint?
372
+ def find_watchpoint_by_id(id)
373
+ raise InvalidObjectError, 'Target is not valid' unless valid?
374
+
375
+ wp_ptr = FFIBindings.lldb_target_find_watchpoint_by_id(@ptr, id)
376
+ return nil if wp_ptr.nil? || wp_ptr.null?
377
+
378
+ Watchpoint.new(wp_ptr, target: self)
379
+ end
380
+
381
+ # @rbs return: Integer
382
+ def num_watchpoints
383
+ return 0 unless valid?
384
+
385
+ FFIBindings.lldb_target_get_num_watchpoints(@ptr)
386
+ end
387
+
388
+ # @rbs index: Integer
389
+ # @rbs return: Watchpoint?
390
+ def watchpoint_at_index(index)
391
+ raise InvalidObjectError, 'Target is not valid' unless valid?
392
+
393
+ wp_ptr = FFIBindings.lldb_target_get_watchpoint_at_index(@ptr, index)
394
+ return nil if wp_ptr.nil? || wp_ptr.null?
395
+
396
+ Watchpoint.new(wp_ptr, target: self)
397
+ end
398
+
399
+ # @rbs return: Array[Watchpoint]
400
+ def watchpoints
401
+ (0...num_watchpoints).map { |i| watchpoint_at_index(i) }.compact
402
+ end
403
+
404
+ # @rbs return: FFI::Pointer
405
+ def to_ptr
406
+ @ptr
407
+ end
408
+
409
+ private
410
+
411
+ # @rbs process: Process
412
+ # @rbs timeout: Float
413
+ # @rbs return: void
414
+ def wait_for_process_stop(process, timeout: 10.0)
415
+ require 'timeout'
416
+
417
+ Timeout.timeout(timeout, LaunchError, "Process failed to stop within #{timeout} seconds") do
418
+ loop do
419
+ state = process.state
420
+ break if state == State::STOPPED || state == State::EXITED || state == State::CRASHED
421
+
422
+ sleep(0.01)
423
+ end
424
+ end
425
+ end
426
+ end
427
+ end
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module LLDB
6
+ class Thread
7
+ # @rbs return: Process
8
+ attr_reader :process
9
+
10
+ # @rbs ptr: FFI::Pointer
11
+ # @rbs process: Process
12
+ # @rbs return: void
13
+ def initialize(ptr, process:)
14
+ @ptr = ptr # : FFI::Pointer
15
+ @process = process
16
+ ObjectSpace.define_finalizer(self, self.class.release(@ptr))
17
+ end
18
+
19
+ # @rbs ptr: FFI::Pointer
20
+ # @rbs return: ^(Integer) -> void
21
+ def self.release(ptr)
22
+ ->(_id) { FFIBindings.lldb_thread_destroy(ptr) unless ptr.null? }
23
+ end
24
+
25
+ # @rbs return: bool
26
+ def valid?
27
+ !@ptr.null? && FFIBindings.lldb_thread_is_valid(@ptr) != 0
28
+ end
29
+
30
+ # @rbs return: bool
31
+ def step_over
32
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
33
+
34
+ FFIBindings.lldb_thread_step_over(@ptr) != 0
35
+ end
36
+
37
+ # @rbs return: bool
38
+ def step_into
39
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
40
+
41
+ FFIBindings.lldb_thread_step_into(@ptr) != 0
42
+ end
43
+
44
+ # @rbs return: bool
45
+ def step_out
46
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
47
+
48
+ FFIBindings.lldb_thread_step_out(@ptr) != 0
49
+ end
50
+
51
+ # @rbs step_over: bool
52
+ # @rbs return: bool
53
+ def step_instruction(step_over: false)
54
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
55
+
56
+ FFIBindings.lldb_thread_step_instruction(@ptr, step_over ? 1 : 0) != 0
57
+ end
58
+
59
+ # @rbs return: Integer
60
+ def num_frames
61
+ return 0 unless valid?
62
+
63
+ FFIBindings.lldb_thread_get_num_frames(@ptr)
64
+ end
65
+
66
+ # @rbs index: Integer
67
+ # @rbs return: Frame?
68
+ def frame_at_index(index)
69
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
70
+
71
+ frame_ptr = FFIBindings.lldb_thread_get_frame_at_index(@ptr, index)
72
+ return nil if frame_ptr.nil? || frame_ptr.null?
73
+
74
+ Frame.new(frame_ptr, thread: self)
75
+ end
76
+
77
+ # @rbs return: Frame?
78
+ def selected_frame
79
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
80
+
81
+ frame_ptr = FFIBindings.lldb_thread_get_selected_frame(@ptr)
82
+ return nil if frame_ptr.nil? || frame_ptr.null?
83
+
84
+ Frame.new(frame_ptr, thread: self)
85
+ end
86
+
87
+ # @rbs index: Integer
88
+ # @rbs return: bool
89
+ def select_frame(index)
90
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
91
+
92
+ FFIBindings.lldb_thread_set_selected_frame(@ptr, index) != 0
93
+ end
94
+
95
+ # @rbs return: Array[Frame]
96
+ def frames
97
+ (0...num_frames).map { |i| frame_at_index(i) }.compact
98
+ end
99
+
100
+ # @rbs return: Integer
101
+ def thread_id
102
+ return 0 unless valid?
103
+
104
+ FFIBindings.lldb_thread_get_thread_id(@ptr)
105
+ end
106
+
107
+ alias id thread_id
108
+
109
+ # @rbs return: String?
110
+ def name
111
+ return nil unless valid?
112
+
113
+ FFIBindings.lldb_thread_get_name(@ptr)
114
+ end
115
+
116
+ # @rbs return: Integer
117
+ def stop_reason
118
+ return StopReason::INVALID unless valid?
119
+
120
+ FFIBindings.lldb_thread_get_stop_reason(@ptr)
121
+ end
122
+
123
+ # @rbs return: String
124
+ def stop_reason_name
125
+ StopReason.name(stop_reason)
126
+ end
127
+
128
+ # @rbs return: bool
129
+ def stopped_at_breakpoint?
130
+ stop_reason == StopReason::BREAKPOINT
131
+ end
132
+
133
+ # @rbs return: Integer
134
+ def stop_reason_data_count
135
+ return 0 unless valid?
136
+
137
+ FFIBindings.lldb_thread_get_stop_reason_data_count(@ptr)
138
+ end
139
+
140
+ # @rbs index: Integer
141
+ # @rbs return: Integer
142
+ def stop_reason_data_at_index(index)
143
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
144
+
145
+ FFIBindings.lldb_thread_get_stop_reason_data_at_index(@ptr, index)
146
+ end
147
+
148
+ # @rbs return: Array[Integer]
149
+ def stop_reason_data
150
+ (0...stop_reason_data_count).map { |i| stop_reason_data_at_index(i) }
151
+ end
152
+
153
+ # @rbs address: Integer
154
+ # @rbs return: bool
155
+ def run_to_address(address)
156
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
157
+
158
+ FFIBindings.lldb_thread_run_to_address(@ptr, address) != 0
159
+ end
160
+
161
+ # @rbs return: Integer
162
+ def index_id
163
+ return 0 unless valid?
164
+
165
+ FFIBindings.lldb_thread_get_index_id(@ptr)
166
+ end
167
+
168
+ # @rbs return: String?
169
+ def queue_name
170
+ return nil unless valid?
171
+
172
+ FFIBindings.lldb_thread_get_queue_name(@ptr)
173
+ end
174
+
175
+ # @rbs max_size: Integer
176
+ # @rbs return: String?
177
+ def stop_description(max_size = 256)
178
+ return nil unless valid?
179
+
180
+ FFIBindings.lldb_thread_get_stop_description(@ptr, max_size)
181
+ end
182
+
183
+ # @rbs return: bool
184
+ def stopped?
185
+ return false unless valid?
186
+
187
+ FFIBindings.lldb_thread_is_stopped(@ptr) != 0
188
+ end
189
+
190
+ # @rbs return: bool
191
+ def suspended?
192
+ return false unless valid?
193
+
194
+ FFIBindings.lldb_thread_is_suspended(@ptr) != 0
195
+ end
196
+
197
+ # @rbs return: bool
198
+ def suspend
199
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
200
+
201
+ FFIBindings.lldb_thread_suspend(@ptr) != 0
202
+ end
203
+
204
+ # @rbs return: bool
205
+ def resume
206
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
207
+
208
+ FFIBindings.lldb_thread_resume(@ptr) != 0
209
+ end
210
+
211
+ # @rbs return: Process?
212
+ def get_process
213
+ raise InvalidObjectError, 'Thread is not valid' unless valid?
214
+
215
+ process_ptr = FFIBindings.lldb_thread_get_process(@ptr)
216
+ return nil if process_ptr.nil? || process_ptr.null?
217
+
218
+ Process.new(process_ptr, target: @process.target)
219
+ end
220
+
221
+ # @rbs return: FFI::Pointer
222
+ def to_ptr
223
+ @ptr
224
+ end
225
+ end
226
+ end