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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -4
- data/README.md +86 -2
- data/Rakefile +36 -0
- data/bindings/constants.yml +137 -0
- data/bindings/surface.yml +3072 -0
- data/ext/lldb/discovery.rb +101 -0
- data/ext/lldb/extconf.rb +206 -88
- data/ext/lldb/lldb_wrapper.cpp +7934 -877
- data/ext/lldb/lldb_wrapper.h +596 -333
- data/lib/lldb/address.rb +81 -0
- data/lib/lldb/api_support.rb +23 -6
- data/lib/lldb/attach_info.rb +122 -0
- data/lib/lldb/block.rb +121 -0
- data/lib/lldb/breakpoint.rb +11 -6
- data/lib/lldb/breakpoint_location.rb +20 -5
- data/lib/lldb/broadcaster.rb +79 -0
- data/lib/lldb/command_interpreter.rb +9 -4
- data/lib/lldb/command_return_object.rb +24 -5
- data/lib/lldb/compile_unit.rb +64 -0
- data/lib/lldb/context.rb +81 -0
- data/lib/lldb/debugger.rb +55 -12
- data/lib/lldb/error.rb +50 -3
- data/lib/lldb/event.rb +109 -0
- data/lib/lldb/expression_options.rb +124 -0
- data/lib/lldb/ffi_bindings.rb +313 -31
- data/lib/lldb/file_spec.rb +90 -0
- data/lib/lldb/file_spec_list.rb +78 -0
- data/lib/lldb/frame.rb +109 -17
- data/lib/lldb/function.rb +121 -0
- data/lib/lldb/instruction.rb +83 -0
- data/lib/lldb/instruction_list.rb +68 -0
- data/lib/lldb/launch_info.rb +145 -19
- data/lib/lldb/line_entry.rb +75 -0
- data/lib/lldb/listener.rb +96 -0
- data/lib/lldb/memory_region_info.rb +8 -3
- data/lib/lldb/module.rb +46 -5
- data/lib/lldb/native.rb +36 -0
- data/lib/lldb/native_buffer.rb +32 -0
- data/lib/lldb/native_handle.rb +60 -0
- data/lib/lldb/native_lifecycle.rb +64 -0
- data/lib/lldb/native_string_array.rb +34 -0
- data/lib/lldb/process.rb +102 -40
- data/lib/lldb/symbol.rb +117 -0
- data/lib/lldb/symbol_context.rb +9 -4
- data/lib/lldb/target.rb +69 -67
- data/lib/lldb/thread.rb +51 -18
- data/lib/lldb/type.rb +40 -3
- data/lib/lldb/type_member.rb +67 -0
- data/lib/lldb/types.rb +69 -4
- data/lib/lldb/value.rb +27 -17
- data/lib/lldb/value_list.rb +9 -5
- data/lib/lldb/version.rb +1 -1
- data/lib/lldb/watchpoint.rb +26 -9
- data/lib/lldb.rb +78 -10
- data/lldb.gemspec +4 -1
- data/rbs_collection.yaml +1 -1
- data/script/check_bindings +259 -0
- data/script/guard_c_exports +139 -0
- data/sig/lldb/ffi_bindings.rbs +247 -21
- data/sig/lldb/weak_ref.rbs +7 -0
- metadata +30 -6
- data/ext/lldb/Makefile +0 -24
- data/ext/lldb/liblldb_wrapper.dylib +0 -0
- data/ext/lldb/lldb_wrapper.o +0 -0
- data/ext/lldb/mkmf.log +0 -24
data/lib/lldb/launch_info.rb
CHANGED
|
@@ -22,20 +22,21 @@ module LLDB
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
class LaunchInfo
|
|
25
|
+
prepend NativeLifecycle
|
|
26
|
+
|
|
25
27
|
# @rbs args: Array[String]?
|
|
26
28
|
# @rbs return: void
|
|
27
|
-
def initialize(args = nil)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
args.each_with_index do |arg, i|
|
|
32
|
-
argv[i].put_pointer(0, FFI::MemoryPointer.from_string(arg))
|
|
33
|
-
end
|
|
34
|
-
argv[args.length].put_pointer(0, nil)
|
|
35
|
-
end
|
|
29
|
+
def initialize(args = nil, context: nil)
|
|
30
|
+
@arguments = if args && !args.empty?
|
|
31
|
+
NativeStringArray.new(args)
|
|
32
|
+
end
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
ptr = FFIBindings.lldb_launch_info_create(@arguments&.to_ptr)
|
|
35
|
+
initialize_native_object(
|
|
36
|
+
ptr,
|
|
37
|
+
release: ->(released) { FFIBindings.lldb_launch_info_destroy(released) },
|
|
38
|
+
context: context
|
|
39
|
+
)
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
# @rbs ptr: FFI::Pointer
|
|
@@ -44,26 +45,151 @@ module LLDB
|
|
|
44
45
|
->(_id) { FFIBindings.lldb_launch_info_destroy(ptr) unless ptr.null? }
|
|
45
46
|
end
|
|
46
47
|
|
|
48
|
+
# @rbs return: bool
|
|
49
|
+
def valid?
|
|
50
|
+
!@ptr.null?
|
|
51
|
+
end
|
|
52
|
+
|
|
47
53
|
# @rbs dir: String
|
|
48
54
|
# @rbs return: void
|
|
49
55
|
def working_directory=(dir)
|
|
56
|
+
NativeStringArray.validate!(dir)
|
|
50
57
|
FFIBindings.lldb_launch_info_set_working_directory(@ptr, dir)
|
|
51
58
|
end
|
|
52
59
|
|
|
53
|
-
# @rbs
|
|
60
|
+
# @rbs return: String?
|
|
61
|
+
def working_directory
|
|
62
|
+
FFIBindings.lldb_launch_info_get_working_directory(@ptr)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @rbs env: Hash[String, String]?
|
|
54
66
|
# @rbs append: bool
|
|
55
67
|
# @rbs return: void
|
|
56
68
|
def set_environment(env, append: true)
|
|
57
|
-
return
|
|
69
|
+
return if env.nil?
|
|
70
|
+
raise ArgumentError, 'environment must be a Hash' unless env.is_a?(Hash)
|
|
71
|
+
|
|
72
|
+
entries = env.map do |key, value|
|
|
73
|
+
key = NativeStringArray.validate!(key)
|
|
74
|
+
value = NativeStringArray.validate!(value)
|
|
75
|
+
raise ArgumentError, 'environment keys must not contain =' if key.include?('=')
|
|
76
|
+
|
|
77
|
+
"#{key}=#{value}"
|
|
78
|
+
end
|
|
79
|
+
strings = NativeStringArray.new(entries)
|
|
80
|
+
FFIBindings.lldb_launch_info_set_environment_entries(@ptr, strings.to_ptr, append ? 1 : 0)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @rbs args: Array[String]
|
|
84
|
+
# @rbs append: bool
|
|
85
|
+
# @rbs return: void
|
|
86
|
+
def arguments=(args, append: false)
|
|
87
|
+
raise ArgumentError, 'arguments must be an Array' unless args.is_a?(Array)
|
|
88
|
+
|
|
89
|
+
@arguments = NativeStringArray.new(args)
|
|
90
|
+
FFIBindings.lldb_launch_info_set_arguments(@ptr, @arguments.to_ptr, append ? 1 : 0)
|
|
91
|
+
end
|
|
58
92
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
93
|
+
# @rbs return: Array[String]
|
|
94
|
+
def arguments
|
|
95
|
+
count = FFIBindings.lldb_launch_info_get_num_arguments(@ptr)
|
|
96
|
+
(0...count).map { |index| FFIBindings.lldb_launch_info_get_argument_at_index(@ptr, index).to_s }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# @rbs return: Array[String]
|
|
100
|
+
def environment_entries
|
|
101
|
+
count = FFIBindings.lldb_launch_info_get_num_environment_entries(@ptr)
|
|
102
|
+
(0...count).map do |index|
|
|
103
|
+
FFIBindings.lldb_launch_info_get_environment_entry_at_index(@ptr, index).to_s
|
|
63
104
|
end
|
|
64
|
-
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @rbs return: FileSpec?
|
|
108
|
+
def executable_file
|
|
109
|
+
file_ptr = FFIBindings.lldb_launch_info_get_executable_file(@ptr)
|
|
110
|
+
return nil if file_ptr.nil? || file_ptr.null?
|
|
111
|
+
|
|
112
|
+
FileSpec.from_ptr(file_ptr, context: context)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @rbs file: FileSpec
|
|
116
|
+
# @rbs add_as_first_arg: bool
|
|
117
|
+
# @rbs return: void
|
|
118
|
+
def executable_file=(file, add_as_first_arg: false)
|
|
119
|
+
raise ArgumentError, 'file must be a FileSpec' unless file.is_a?(FileSpec)
|
|
120
|
+
|
|
121
|
+
FFIBindings.lldb_launch_info_set_executable_file(@ptr, file.to_ptr, add_as_first_arg ? 1 : 0)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @rbs return: Listener?
|
|
125
|
+
def listener
|
|
126
|
+
listener_ptr = FFIBindings.lldb_launch_info_get_listener(@ptr)
|
|
127
|
+
return nil if listener_ptr.nil? || listener_ptr.null?
|
|
128
|
+
|
|
129
|
+
Listener.from_ptr(listener_ptr, context: context)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# @rbs value: Listener
|
|
133
|
+
# @rbs return: void
|
|
134
|
+
def listener=(value)
|
|
135
|
+
raise ArgumentError, 'listener must be a Listener' unless value.is_a?(Listener)
|
|
136
|
+
|
|
137
|
+
FFIBindings.lldb_launch_info_set_listener(@ptr, value.to_ptr)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# @rbs return: String?
|
|
141
|
+
def process_plugin_name
|
|
142
|
+
FFIBindings.lldb_launch_info_get_process_plugin_name(@ptr)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# @rbs value: String
|
|
146
|
+
# @rbs return: void
|
|
147
|
+
def process_plugin_name=(value)
|
|
148
|
+
NativeStringArray.validate!(value)
|
|
149
|
+
FFIBindings.lldb_launch_info_set_process_plugin_name(@ptr, value)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# @rbs return: String?
|
|
153
|
+
def shell
|
|
154
|
+
FFIBindings.lldb_launch_info_get_shell(@ptr)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# @rbs value: String
|
|
158
|
+
# @rbs return: void
|
|
159
|
+
def shell=(value)
|
|
160
|
+
NativeStringArray.validate!(value)
|
|
161
|
+
FFIBindings.lldb_launch_info_set_shell(@ptr, value)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# @rbs fd: Integer
|
|
165
|
+
# @rbs return: bool
|
|
166
|
+
def add_close_file_action(fd)
|
|
167
|
+
FFIBindings.lldb_launch_info_add_close_file_action(@ptr, fd) != 0
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# @rbs fd: Integer
|
|
171
|
+
# @rbs dup_fd: Integer
|
|
172
|
+
# @rbs return: bool
|
|
173
|
+
def add_duplicate_file_action(fd, dup_fd)
|
|
174
|
+
FFIBindings.lldb_launch_info_add_duplicate_file_action(@ptr, fd, dup_fd) != 0
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# @rbs fd: Integer
|
|
178
|
+
# @rbs path: String
|
|
179
|
+
# @rbs read: bool
|
|
180
|
+
# @rbs write: bool
|
|
181
|
+
# @rbs return: bool
|
|
182
|
+
def add_open_file_action(fd, path, read: false, write: false)
|
|
183
|
+
NativeStringArray.validate!(path)
|
|
184
|
+
FFIBindings.lldb_launch_info_add_open_file_action(@ptr, fd, path, read ? 1 : 0, write ? 1 : 0) != 0
|
|
185
|
+
end
|
|
65
186
|
|
|
66
|
-
|
|
187
|
+
# @rbs fd: Integer
|
|
188
|
+
# @rbs read: bool
|
|
189
|
+
# @rbs write: bool
|
|
190
|
+
# @rbs return: bool
|
|
191
|
+
def add_suppress_file_action(fd, read: false, write: false)
|
|
192
|
+
FFIBindings.lldb_launch_info_add_suppress_file_action(@ptr, fd, read ? 1 : 0, write ? 1 : 0) != 0
|
|
67
193
|
end
|
|
68
194
|
|
|
69
195
|
# @rbs return: Integer
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module LLDB
|
|
6
|
+
class LineEntry
|
|
7
|
+
prepend NativeLifecycle
|
|
8
|
+
|
|
9
|
+
# @rbs target: Target?
|
|
10
|
+
# @rbs context: Context?
|
|
11
|
+
# @rbs return: void
|
|
12
|
+
def initialize(ptr, target: nil, context: nil)
|
|
13
|
+
@target = target
|
|
14
|
+
initialize_native_object(
|
|
15
|
+
ptr,
|
|
16
|
+
release: ->(released) { FFIBindings.lldb_line_entry_destroy(released) },
|
|
17
|
+
context: context || target&.context
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @rbs return: bool
|
|
22
|
+
def valid?
|
|
23
|
+
!@ptr.null? && FFIBindings.lldb_line_entry_is_valid(@ptr) != 0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @rbs return: Address?
|
|
27
|
+
def start_address
|
|
28
|
+
return nil unless valid?
|
|
29
|
+
|
|
30
|
+
ptr = FFIBindings.lldb_line_entry_get_start_address(@ptr)
|
|
31
|
+
return nil if ptr.nil? || ptr.null?
|
|
32
|
+
|
|
33
|
+
Address.from_ptr(ptr, target: @target, context: context)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @rbs return: Address?
|
|
37
|
+
def end_address
|
|
38
|
+
return nil unless valid?
|
|
39
|
+
|
|
40
|
+
ptr = FFIBindings.lldb_line_entry_get_end_address(@ptr)
|
|
41
|
+
return nil if ptr.nil? || ptr.null?
|
|
42
|
+
|
|
43
|
+
Address.from_ptr(ptr, target: @target, context: context)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @rbs return: FileSpec?
|
|
47
|
+
def file_spec
|
|
48
|
+
return nil unless valid?
|
|
49
|
+
|
|
50
|
+
ptr = FFIBindings.lldb_line_entry_get_file_spec(@ptr)
|
|
51
|
+
return nil if ptr.nil? || ptr.null?
|
|
52
|
+
|
|
53
|
+
FileSpec.from_ptr(ptr, context: context)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @rbs return: Integer
|
|
57
|
+
def line
|
|
58
|
+
return INVALID_LINE_NUMBER unless valid?
|
|
59
|
+
|
|
60
|
+
FFIBindings.lldb_line_entry_get_line(@ptr)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @rbs return: Integer
|
|
64
|
+
def column
|
|
65
|
+
return 0 unless valid?
|
|
66
|
+
|
|
67
|
+
FFIBindings.lldb_line_entry_get_column(@ptr)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @rbs return: FFI::Pointer
|
|
71
|
+
def to_ptr
|
|
72
|
+
@ptr
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module LLDB
|
|
6
|
+
class Listener
|
|
7
|
+
prepend NativeLifecycle
|
|
8
|
+
|
|
9
|
+
# @rbs name: String?
|
|
10
|
+
# @rbs context: Context?
|
|
11
|
+
# @rbs pointer: FFI::Pointer?
|
|
12
|
+
# @rbs return: void
|
|
13
|
+
def initialize(name = nil, context: nil, pointer: nil)
|
|
14
|
+
ptr = pointer || FFIBindings.lldb_listener_create(name)
|
|
15
|
+
initialize_native_object(
|
|
16
|
+
ptr,
|
|
17
|
+
release: ->(released) { FFIBindings.lldb_listener_destroy(released) },
|
|
18
|
+
context: context
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @rbs ptr: FFI::Pointer
|
|
23
|
+
# @rbs context: Context?
|
|
24
|
+
# @rbs return: Listener
|
|
25
|
+
def self.from_ptr(ptr, context: nil)
|
|
26
|
+
new(context: context, pointer: ptr)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @rbs return: bool
|
|
30
|
+
def valid?
|
|
31
|
+
!@ptr.null? && FFIBindings.lldb_listener_is_valid(@ptr) != 0
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @rbs broadcaster: Broadcaster
|
|
35
|
+
# @rbs event_mask: Integer
|
|
36
|
+
# @rbs return: Integer
|
|
37
|
+
def start_listening_for_events(broadcaster, event_mask)
|
|
38
|
+
ensure_open!
|
|
39
|
+
FFIBindings.lldb_listener_start_listening_for_events(@ptr, broadcaster.to_ptr, event_mask)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @rbs broadcaster: Broadcaster
|
|
43
|
+
# @rbs event_mask: Integer
|
|
44
|
+
# @rbs return: bool
|
|
45
|
+
def stop_listening_for_events(broadcaster, event_mask)
|
|
46
|
+
ensure_open!
|
|
47
|
+
FFIBindings.lldb_listener_stop_listening_for_events(@ptr, broadcaster.to_ptr, event_mask) != 0
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @rbs timeout_seconds: Integer
|
|
51
|
+
# @rbs return: Event?
|
|
52
|
+
def wait_for_event(timeout_seconds: 0)
|
|
53
|
+
ensure_open!
|
|
54
|
+
timeout = normalize_timeout(timeout_seconds)
|
|
55
|
+
event_ptr = FFIBindings.lldb_listener_wait_for_event(@ptr, timeout)
|
|
56
|
+
event_from_ptr(event_ptr)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @rbs return: Event?
|
|
60
|
+
def peek_event
|
|
61
|
+
ensure_open!
|
|
62
|
+
event_from_ptr(FFIBindings.lldb_listener_peek_event(@ptr))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @rbs return: Event?
|
|
66
|
+
def next_event
|
|
67
|
+
ensure_open!
|
|
68
|
+
event_from_ptr(FFIBindings.lldb_listener_next_event(@ptr))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @rbs return: FFI::Pointer
|
|
72
|
+
def to_ptr
|
|
73
|
+
@ptr
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
# @rbs timeout: Integer
|
|
79
|
+
# @rbs return: Integer
|
|
80
|
+
def normalize_timeout(timeout)
|
|
81
|
+
unless timeout.is_a?(Integer) && timeout >= 0 && timeout <= 0xFFFFFFFF
|
|
82
|
+
raise ArgumentError, 'timeout_seconds must be an Integer between 0 and UINT32_MAX'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
timeout
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @rbs ptr: FFI::Pointer
|
|
89
|
+
# @rbs return: Event?
|
|
90
|
+
def event_from_ptr(ptr)
|
|
91
|
+
return nil if ptr.nil? || ptr.null?
|
|
92
|
+
|
|
93
|
+
Event.from_ptr(ptr, context: context)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
module LLDB
|
|
6
6
|
# Represents information about a memory region in the target process.
|
|
7
7
|
class MemoryRegionInfo
|
|
8
|
+
prepend NativeLifecycle
|
|
9
|
+
|
|
8
10
|
# @rbs ptr: FFI::Pointer
|
|
9
11
|
# @rbs return: void
|
|
10
|
-
def initialize(ptr)
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
def initialize(ptr, context: nil)
|
|
13
|
+
initialize_native_object(
|
|
14
|
+
ptr,
|
|
15
|
+
release: ->(released) { FFIBindings.lldb_memory_region_info_destroy(released) },
|
|
16
|
+
context: context
|
|
17
|
+
)
|
|
13
18
|
end
|
|
14
19
|
|
|
15
20
|
# @rbs ptr: FFI::Pointer
|
data/lib/lldb/module.rb
CHANGED
|
@@ -4,16 +4,21 @@
|
|
|
4
4
|
|
|
5
5
|
module LLDB
|
|
6
6
|
class Module
|
|
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
|
-
|
|
17
|
+
initialize_native_object(
|
|
18
|
+
ptr,
|
|
19
|
+
release: ->(released) { FFIBindings.lldb_module_destroy(released) },
|
|
20
|
+
context: context
|
|
21
|
+
)
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
# @rbs ptr: FFI::Pointer
|
|
@@ -31,14 +36,34 @@ module LLDB
|
|
|
31
36
|
def file_path
|
|
32
37
|
return nil unless valid?
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
file&.path
|
|
35
40
|
end
|
|
36
41
|
|
|
37
42
|
# @rbs return: String?
|
|
38
43
|
def platform_file_path
|
|
39
44
|
return nil unless valid?
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
platform_file&.path
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @rbs return: FileSpec?
|
|
50
|
+
def file
|
|
51
|
+
return nil unless valid?
|
|
52
|
+
|
|
53
|
+
file_ptr = FFIBindings.lldb_module_get_file(@ptr)
|
|
54
|
+
return nil if file_ptr.nil? || file_ptr.null?
|
|
55
|
+
|
|
56
|
+
FileSpec.from_ptr(file_ptr, context: context)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @rbs return: FileSpec?
|
|
60
|
+
def platform_file
|
|
61
|
+
return nil unless valid?
|
|
62
|
+
|
|
63
|
+
file_ptr = FFIBindings.lldb_module_get_platform_file(@ptr)
|
|
64
|
+
return nil if file_ptr.nil? || file_ptr.null?
|
|
65
|
+
|
|
66
|
+
FileSpec.from_ptr(file_ptr, context: context)
|
|
42
67
|
end
|
|
43
68
|
|
|
44
69
|
# @rbs return: Integer
|
|
@@ -48,6 +73,22 @@ module LLDB
|
|
|
48
73
|
FFIBindings.lldb_module_get_num_symbols(@ptr)
|
|
49
74
|
end
|
|
50
75
|
|
|
76
|
+
# @rbs index: Integer
|
|
77
|
+
# @rbs return: Symbol?
|
|
78
|
+
def symbol_at_index(index)
|
|
79
|
+
raise InvalidObjectError, 'Module is not valid' unless valid?
|
|
80
|
+
|
|
81
|
+
symbol_ptr = FFIBindings.lldb_module_get_symbol_at_index(@ptr, index)
|
|
82
|
+
return nil if symbol_ptr.nil? || symbol_ptr.null?
|
|
83
|
+
|
|
84
|
+
Symbol.new(symbol_ptr, target: @target, context: context)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @rbs return: Array[Symbol]
|
|
88
|
+
def symbols
|
|
89
|
+
(0...num_symbols).map { |index| symbol_at_index(index) }.compact
|
|
90
|
+
end
|
|
91
|
+
|
|
51
92
|
# @rbs return: String
|
|
52
93
|
def to_s
|
|
53
94
|
file_path || '(unknown module)'
|
data/lib/lldb/native.rb
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module LLDB
|
|
6
|
+
module Native
|
|
7
|
+
# @rbs status: Integer
|
|
8
|
+
# @rbs operation: String
|
|
9
|
+
# @rbs error: Error?
|
|
10
|
+
# @rbs return: bool
|
|
11
|
+
def self.check_status!(status, operation, error = nil)
|
|
12
|
+
return true if status == NativeStatus::OK
|
|
13
|
+
|
|
14
|
+
if status == NativeStatus::INTERNAL_ERROR
|
|
15
|
+
message = FFIBindings.lldb_wrapper_last_error_message || 'unknown native exception'
|
|
16
|
+
code = FFIBindings.lldb_wrapper_last_error_code
|
|
17
|
+
raise InternalBindingError.new(operation, message, code)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
native_error = error || Error.new
|
|
21
|
+
unless native_error.fail?
|
|
22
|
+
native_error.set_error("native operation failed with status #{status}")
|
|
23
|
+
end
|
|
24
|
+
raise OperationError.new(operation, native_error)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @rbs operation: String
|
|
28
|
+
# @rbs error: Error
|
|
29
|
+
# @rbs return: true
|
|
30
|
+
def self.check_error!(operation, error)
|
|
31
|
+
raise OperationError.new(operation, error) if error.fail?
|
|
32
|
+
|
|
33
|
+
true
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module LLDB
|
|
6
|
+
module NativeBuffer
|
|
7
|
+
# @rbs max_size: Integer?
|
|
8
|
+
# @rbs &reader: (FFI::Pointer?, Integer) -> Integer
|
|
9
|
+
# @rbs return: String
|
|
10
|
+
def self.read_c_string(max_size: nil, &reader)
|
|
11
|
+
raise ArgumentError, 'max_size must be non-negative' if max_size&.negative?
|
|
12
|
+
return '' if max_size == 0
|
|
13
|
+
|
|
14
|
+
required = reader.call(nil, 0)
|
|
15
|
+
capacity = if required.positive?
|
|
16
|
+
max_size ? [required + 1, max_size].min : required + 1
|
|
17
|
+
else
|
|
18
|
+
max_size || 256
|
|
19
|
+
end
|
|
20
|
+
capacity = 1 if capacity.zero?
|
|
21
|
+
loop do
|
|
22
|
+
buffer = FFI::MemoryPointer.new(:uint8, capacity)
|
|
23
|
+
written = reader.call(buffer, capacity)
|
|
24
|
+
bytes = buffer.get_bytes(0, [written, capacity].min).delete_suffix("\0")
|
|
25
|
+
return bytes if max_size && (capacity >= max_size || written < capacity - 1)
|
|
26
|
+
return bytes if written < capacity - 1
|
|
27
|
+
|
|
28
|
+
capacity = [capacity * 2, written + 2].max
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module LLDB
|
|
6
|
+
class NativeHandle
|
|
7
|
+
NULL_POINTER = FFI::Pointer.new(0)
|
|
8
|
+
|
|
9
|
+
# @rbs ptr: FFI::Pointer
|
|
10
|
+
# @rbs release: ^(FFI::Pointer) -> void
|
|
11
|
+
# @rbs return: void
|
|
12
|
+
def initialize(ptr, release:)
|
|
13
|
+
# The resource is detached with Array#shift, which is a single Ruby VM
|
|
14
|
+
# operation. Finalizers cannot safely acquire a Mutex on all supported
|
|
15
|
+
# Rubies, so the detach itself must not depend on one.
|
|
16
|
+
@state = [[ptr, release]]
|
|
17
|
+
ObjectSpace.define_finalizer(self, self.class.finalizer(@state))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @rbs return: FFI::Pointer
|
|
21
|
+
def to_ptr
|
|
22
|
+
resource = @state.first
|
|
23
|
+
resource ? resource.first : NULL_POINTER
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @rbs return: bool
|
|
27
|
+
def closed?
|
|
28
|
+
@state.empty?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @rbs return: bool
|
|
32
|
+
def close
|
|
33
|
+
resource = @state.shift
|
|
34
|
+
return false unless resource
|
|
35
|
+
|
|
36
|
+
pointer, release = resource
|
|
37
|
+
|
|
38
|
+
release.call(pointer) unless pointer.null?
|
|
39
|
+
true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @rbs state: Array[Array[untyped]]
|
|
43
|
+
# @rbs return: ^(Integer) -> void
|
|
44
|
+
def self.finalizer(state)
|
|
45
|
+
->(_object_id) do
|
|
46
|
+
resource = state.shift
|
|
47
|
+
next unless resource
|
|
48
|
+
|
|
49
|
+
pointer, release = resource
|
|
50
|
+
next unless pointer && !pointer.null?
|
|
51
|
+
|
|
52
|
+
begin
|
|
53
|
+
release.call(pointer)
|
|
54
|
+
rescue StandardError
|
|
55
|
+
# Finalizers must never raise into an unrelated Ruby thread.
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module LLDB
|
|
6
|
+
module NativeLifecycle
|
|
7
|
+
# @rbs return: bool
|
|
8
|
+
def closed?
|
|
9
|
+
@native_handle ? @native_handle.closed? : false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @rbs return: bool
|
|
13
|
+
def close
|
|
14
|
+
return false unless @native_handle
|
|
15
|
+
return false if @native_handle.closed?
|
|
16
|
+
|
|
17
|
+
send(:close_context) if respond_to?(:close_context, true)
|
|
18
|
+
@native_handle.close
|
|
19
|
+
@ptr = NativeHandle::NULL_POINTER
|
|
20
|
+
true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @rbs return: FFI::Pointer
|
|
24
|
+
def to_ptr
|
|
25
|
+
return NativeHandle::NULL_POINTER if closed?
|
|
26
|
+
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @rbs return: void
|
|
31
|
+
def ensure_open!
|
|
32
|
+
raise ClosedObjectError, "#{self.class} is closed" if closed?
|
|
33
|
+
@context&.ensure_open!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @rbs ptr: FFI::Pointer
|
|
37
|
+
# @rbs release: ^(FFI::Pointer) -> void
|
|
38
|
+
# @rbs context: Context?
|
|
39
|
+
# @rbs return: void
|
|
40
|
+
def initialize_native_object(ptr, release:, context: nil)
|
|
41
|
+
@ptr = ptr
|
|
42
|
+
@context = context
|
|
43
|
+
@native_handle = NativeHandle.new(ptr, release: release)
|
|
44
|
+
context&.register(@native_handle)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @rbs return: Context?
|
|
48
|
+
def context
|
|
49
|
+
@context
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @rbs return: Context
|
|
53
|
+
def context!
|
|
54
|
+
context || raise(LifecycleError, 'LLDB object has no context')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @rbs return: bool
|
|
58
|
+
def valid?
|
|
59
|
+
return false if closed? || @context&.closed?
|
|
60
|
+
|
|
61
|
+
super
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module LLDB
|
|
6
|
+
class NativeStringArray
|
|
7
|
+
# @rbs strings: Array[String]
|
|
8
|
+
# @rbs return: void
|
|
9
|
+
def initialize(strings)
|
|
10
|
+
@strings = strings.map { |string| NativeStringArray.validate!(string) }
|
|
11
|
+
@string_pointers = @strings.map { |string| FFI::MemoryPointer.from_string(string) }
|
|
12
|
+
@pointer_array = FFI::MemoryPointer.new(:pointer, @string_pointers.length + 1)
|
|
13
|
+
|
|
14
|
+
@string_pointers.each_with_index do |pointer, index|
|
|
15
|
+
@pointer_array[index].put_pointer(0, pointer)
|
|
16
|
+
end
|
|
17
|
+
@pointer_array[@string_pointers.length].put_pointer(0, nil)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @rbs value: String
|
|
21
|
+
# @rbs return: String
|
|
22
|
+
def self.validate!(value)
|
|
23
|
+
raise ArgumentError, 'native string values must be String' unless value.is_a?(String)
|
|
24
|
+
raise ArgumentError, 'native strings must not contain NUL bytes' if value.include?("\0")
|
|
25
|
+
|
|
26
|
+
value
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @rbs return: FFI::Pointer
|
|
30
|
+
def to_ptr
|
|
31
|
+
@pointer_array
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|