readapt 1.4.0 → 1.4.1
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/.gitignore +16 -16
- data/.rspec +2 -2
- data/.travis.yml +19 -19
- data/CHANGELOG.md +91 -87
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +37 -37
- data/Rakefile +14 -14
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/exe/readapt +5 -5
- data/ext/readapt/breakpoints.c +83 -83
- data/ext/readapt/breakpoints.h +11 -11
- data/ext/readapt/extconf.rb +0 -0
- data/ext/readapt/frame.c +137 -137
- data/ext/readapt/frame.h +17 -17
- data/ext/readapt/inspector.c +51 -51
- data/ext/readapt/inspector.h +8 -8
- data/ext/readapt/lookup_table.c +211 -211
- data/ext/readapt/lookup_table.h +30 -30
- data/ext/readapt/monitor.c +0 -0
- data/ext/readapt/monitor.h +0 -0
- data/ext/readapt/normalize.c +59 -59
- data/ext/readapt/normalize.h +7 -7
- data/ext/readapt/readapt.c +18 -18
- data/ext/readapt/stack.c +86 -86
- data/ext/readapt/stack.h +20 -20
- data/ext/readapt/threads.c +13 -2
- data/ext/readapt/threads.h +2 -1
- data/lib/readapt.rb +21 -21
- data/lib/readapt/adapter.rb +98 -98
- data/lib/readapt/breakpoint.rb +21 -21
- data/lib/readapt/data_reader.rb +62 -62
- data/lib/readapt/debugger.rb +227 -228
- data/lib/readapt/error.rb +63 -63
- data/lib/readapt/finder.rb +34 -34
- data/lib/readapt/frame.rb +40 -40
- data/lib/readapt/input.rb +7 -7
- data/lib/readapt/message.rb +62 -62
- data/lib/readapt/message/attach.rb +11 -11
- data/lib/readapt/message/base.rb +32 -32
- data/lib/readapt/message/configuration_done.rb +11 -11
- data/lib/readapt/message/continue.rb +15 -15
- data/lib/readapt/message/disconnect.rb +13 -13
- data/lib/readapt/message/evaluate.rb +18 -18
- data/lib/readapt/message/initialize.rb +21 -21
- data/lib/readapt/message/launch.rb +11 -11
- data/lib/readapt/message/next.rb +12 -12
- data/lib/readapt/message/pause.rb +11 -11
- data/lib/readapt/message/scopes.rb +26 -26
- data/lib/readapt/message/set_breakpoints.rb +25 -25
- data/lib/readapt/message/set_exception_breakpoints.rb +11 -11
- data/lib/readapt/message/stack_trace.rb +38 -38
- data/lib/readapt/message/step_in.rb +11 -11
- data/lib/readapt/message/step_out.rb +11 -11
- data/lib/readapt/message/threads.rb +18 -18
- data/lib/readapt/message/variables.rb +53 -53
- data/lib/readapt/monitor.rb +0 -0
- data/lib/readapt/output.rb +25 -25
- data/lib/readapt/references.rb +27 -27
- data/lib/readapt/server.rb +22 -22
- data/lib/readapt/shell.rb +104 -104
- data/lib/readapt/snapshot.rb +0 -0
- data/lib/readapt/thread.rb +20 -25
- data/lib/readapt/variable.rb +0 -0
- data/lib/readapt/version.rb +3 -3
- data/readapt.gemspec +39 -39
- metadata +3 -3
data/lib/readapt/debugger.rb
CHANGED
@@ -1,228 +1,227 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'backport'
|
4
|
-
require 'observer'
|
5
|
-
require 'set'
|
6
|
-
|
7
|
-
module Readapt
|
8
|
-
class Debugger
|
9
|
-
include Observable
|
10
|
-
include Finder
|
11
|
-
|
12
|
-
attr_reader :monitor
|
13
|
-
|
14
|
-
attr_reader :file
|
15
|
-
|
16
|
-
attr_writer :pause_on_raise
|
17
|
-
|
18
|
-
def initialize
|
19
|
-
@stack = []
|
20
|
-
@frames = {}
|
21
|
-
@running = false
|
22
|
-
@attached = false
|
23
|
-
@request = nil
|
24
|
-
@config = {}
|
25
|
-
@original_argv = ARGV.clone
|
26
|
-
@original_prog = $0
|
27
|
-
@breakpoints = {}
|
28
|
-
end
|
29
|
-
|
30
|
-
def config arguments, request
|
31
|
-
@file = Readapt.normalize_path(find(arguments['program']))
|
32
|
-
@config = arguments
|
33
|
-
@request = request
|
34
|
-
rescue LoadError => e
|
35
|
-
STDERR.puts e.message
|
36
|
-
end
|
37
|
-
|
38
|
-
def pause_on_raise?
|
39
|
-
@pause_on_raise ||= false
|
40
|
-
end
|
41
|
-
|
42
|
-
# @return [Readapt::Thread]
|
43
|
-
def thread id
|
44
|
-
Thread.find(id)
|
45
|
-
end
|
46
|
-
|
47
|
-
def threads
|
48
|
-
Thread.all
|
49
|
-
end
|
50
|
-
|
51
|
-
def frame id
|
52
|
-
@frames[id] || Frame::NULL_FRAME
|
53
|
-
end
|
54
|
-
|
55
|
-
def launched?
|
56
|
-
@request == :launch
|
57
|
-
end
|
58
|
-
|
59
|
-
def attached?
|
60
|
-
@request == :attach
|
61
|
-
end
|
62
|
-
|
63
|
-
def start
|
64
|
-
::Thread.new do
|
65
|
-
set_program_args
|
66
|
-
run { load @file }
|
67
|
-
set_original_args
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def run
|
72
|
-
# raise RuntimeError, 'Debugger is already running' if @running
|
73
|
-
@running = true
|
74
|
-
send_event('process', {
|
75
|
-
name: @file
|
76
|
-
})
|
77
|
-
Monitor.start @file do |snapshot|
|
78
|
-
debug snapshot
|
79
|
-
end
|
80
|
-
yield if block_given?
|
81
|
-
rescue StandardError => e
|
82
|
-
STDERR.puts "[#{e.class}] #{e.message}"
|
83
|
-
STDERR.puts e.backtrace.join("\n")
|
84
|
-
ensure
|
85
|
-
Monitor.stop
|
86
|
-
@running = false
|
87
|
-
STDOUT.flush #unless STDOUT.closed?
|
88
|
-
STDERR.flush #unless STDERR.closed?
|
89
|
-
changed
|
90
|
-
send_event 'terminated', nil
|
91
|
-
end
|
92
|
-
|
93
|
-
def output data, category = :console
|
94
|
-
send_event('output', {
|
95
|
-
output: data,
|
96
|
-
category: category
|
97
|
-
})
|
98
|
-
end
|
99
|
-
|
100
|
-
def get_breakpoint source, line
|
101
|
-
@breakpoints["#{source}:#{line}"] || Breakpoint.new(source, line, nil, 0)
|
102
|
-
end
|
103
|
-
|
104
|
-
def set_breakpoint source, line, condition, hitcount
|
105
|
-
@breakpoints["#{source}:#{line}"] = Breakpoint.new(source, line, condition, hitcount)
|
106
|
-
end
|
107
|
-
|
108
|
-
def clear_breakpoints source
|
109
|
-
@breakpoints.delete_if { |_key, value|
|
110
|
-
value.source == source
|
111
|
-
}
|
112
|
-
end
|
113
|
-
|
114
|
-
def disconnect
|
115
|
-
shutdown if launched?
|
116
|
-
@request = nil
|
117
|
-
end
|
118
|
-
|
119
|
-
def self.run &block
|
120
|
-
new.run &block
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
# @param [Snapshot]
|
126
|
-
# return [void]
|
127
|
-
def debug snapshot
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
thr =
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
thr =
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
bp
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
STDERR.puts "
|
160
|
-
STDERR.puts "#{
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
STDERR.puts "
|
177
|
-
STDERR.puts "#{
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
thread.
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
ARGV.
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
ARGV.
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'backport'
|
4
|
+
require 'observer'
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
module Readapt
|
8
|
+
class Debugger
|
9
|
+
include Observable
|
10
|
+
include Finder
|
11
|
+
|
12
|
+
attr_reader :monitor
|
13
|
+
|
14
|
+
attr_reader :file
|
15
|
+
|
16
|
+
attr_writer :pause_on_raise
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@stack = []
|
20
|
+
@frames = {}
|
21
|
+
@running = false
|
22
|
+
@attached = false
|
23
|
+
@request = nil
|
24
|
+
@config = {}
|
25
|
+
@original_argv = ARGV.clone
|
26
|
+
@original_prog = $0
|
27
|
+
@breakpoints = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def config arguments, request
|
31
|
+
@file = Readapt.normalize_path(find(arguments['program']))
|
32
|
+
@config = arguments
|
33
|
+
@request = request
|
34
|
+
rescue LoadError => e
|
35
|
+
STDERR.puts e.message
|
36
|
+
end
|
37
|
+
|
38
|
+
def pause_on_raise?
|
39
|
+
@pause_on_raise ||= false
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Readapt::Thread]
|
43
|
+
def thread id
|
44
|
+
Thread.find(id)
|
45
|
+
end
|
46
|
+
|
47
|
+
def threads
|
48
|
+
Thread.all
|
49
|
+
end
|
50
|
+
|
51
|
+
def frame id
|
52
|
+
@frames[id] || Frame::NULL_FRAME
|
53
|
+
end
|
54
|
+
|
55
|
+
def launched?
|
56
|
+
@request == :launch
|
57
|
+
end
|
58
|
+
|
59
|
+
def attached?
|
60
|
+
@request == :attach
|
61
|
+
end
|
62
|
+
|
63
|
+
def start
|
64
|
+
::Thread.new do
|
65
|
+
set_program_args
|
66
|
+
run { load @file }
|
67
|
+
set_original_args
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def run
|
72
|
+
# raise RuntimeError, 'Debugger is already running' if @running
|
73
|
+
@running = true
|
74
|
+
send_event('process', {
|
75
|
+
name: @file
|
76
|
+
})
|
77
|
+
Monitor.start @file do |snapshot|
|
78
|
+
debug snapshot
|
79
|
+
end
|
80
|
+
yield if block_given?
|
81
|
+
rescue StandardError => e
|
82
|
+
STDERR.puts "[#{e.class}] #{e.message}"
|
83
|
+
STDERR.puts e.backtrace.join("\n")
|
84
|
+
ensure
|
85
|
+
Monitor.stop
|
86
|
+
@running = false
|
87
|
+
STDOUT.flush #unless STDOUT.closed?
|
88
|
+
STDERR.flush #unless STDERR.closed?
|
89
|
+
changed
|
90
|
+
send_event 'terminated', nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def output data, category = :console
|
94
|
+
send_event('output', {
|
95
|
+
output: data,
|
96
|
+
category: category
|
97
|
+
})
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_breakpoint source, line
|
101
|
+
@breakpoints["#{source}:#{line}"] || Breakpoint.new(source, line, nil, 0)
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_breakpoint source, line, condition, hitcount
|
105
|
+
@breakpoints["#{source}:#{line}"] = Breakpoint.new(source, line, condition, hitcount)
|
106
|
+
end
|
107
|
+
|
108
|
+
def clear_breakpoints source
|
109
|
+
@breakpoints.delete_if { |_key, value|
|
110
|
+
value.source == source
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
def disconnect
|
115
|
+
shutdown if launched?
|
116
|
+
@request = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.run &block
|
120
|
+
new.run &block
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# @param [Snapshot]
|
126
|
+
# return [void]
|
127
|
+
def debug snapshot
|
128
|
+
References.clear
|
129
|
+
if snapshot.event == :thread_begin || snapshot.event == :entry
|
130
|
+
thr = Thread.find(snapshot.thread_id)
|
131
|
+
thr.control = :continue
|
132
|
+
send_event('thread', {
|
133
|
+
reason: 'started',
|
134
|
+
threadId: snapshot.thread_id
|
135
|
+
}, true)
|
136
|
+
snapshot.control = :continue
|
137
|
+
elsif snapshot.event == :thread_end
|
138
|
+
thr = thread(snapshot.thread_id)
|
139
|
+
thr.control = :continue
|
140
|
+
send_event('thread', {
|
141
|
+
reason: 'exited',
|
142
|
+
threadId: snapshot.thread_id
|
143
|
+
})
|
144
|
+
snapshot.control = :continue
|
145
|
+
else
|
146
|
+
confirmed_pause = true
|
147
|
+
thread = self.thread(snapshot.thread_id)
|
148
|
+
if snapshot.event == :breakpoint
|
149
|
+
bp = get_breakpoint(snapshot.file, snapshot.line)
|
150
|
+
unless bp.condition.nil? || bp.condition.empty?
|
151
|
+
# @type [Binding]
|
152
|
+
bnd = thread.frames.first.frame_binding
|
153
|
+
begin
|
154
|
+
unless bnd.eval(bp.condition)
|
155
|
+
confirmed_pause = false
|
156
|
+
end
|
157
|
+
rescue StandardError => e
|
158
|
+
STDERR.puts "Breakpoint condition raised an error"
|
159
|
+
STDERR.puts "#{snapshot.file}:#{snapshot.line} - `#{bp.condition}`"
|
160
|
+
STDERR.puts "[#{e.class}] #{e.message}"
|
161
|
+
confirmed_pause = false
|
162
|
+
end
|
163
|
+
end
|
164
|
+
unless !confirmed_pause || bp.hit_condition.nil? || bp.hit_condition.empty?
|
165
|
+
bp.hit_cursor += 1
|
166
|
+
bnd = thread.frames.first.frame_binding
|
167
|
+
begin
|
168
|
+
hit_count = bnd.eval(bp.hit_condition)
|
169
|
+
if bp.hit_cursor == hit_count
|
170
|
+
bp.hit_cursor = 0
|
171
|
+
else
|
172
|
+
confirmed_pause = false
|
173
|
+
end
|
174
|
+
rescue StandardError => e
|
175
|
+
STDERR.puts "Breakpoint condition raised an error"
|
176
|
+
STDERR.puts "#{snapshot.file}:#{snapshot.line} - `#{bp.condition}`"
|
177
|
+
STDERR.puts "[#{e.class}] #{e.message}"
|
178
|
+
confirmed_pause = false
|
179
|
+
end
|
180
|
+
end
|
181
|
+
elsif snapshot.event == :raise && !pause_on_raise?
|
182
|
+
confirmed_pause = false
|
183
|
+
end
|
184
|
+
if confirmed_pause
|
185
|
+
changed
|
186
|
+
thread.control = :pause
|
187
|
+
thread.frames.each do |frm|
|
188
|
+
@frames[frm.local_id] = frm
|
189
|
+
end
|
190
|
+
send_event('stopped', {
|
191
|
+
reason: snapshot.event,
|
192
|
+
threadId: thread.id
|
193
|
+
})
|
194
|
+
sleep 0.01 until thread.control != :pause || !Thread.include?(thread.id)
|
195
|
+
thread.frames.each do |frm|
|
196
|
+
@frames.delete frm.local_id
|
197
|
+
end
|
198
|
+
else
|
199
|
+
thread.control = :continue
|
200
|
+
end
|
201
|
+
snapshot.control = thread.control
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def set_program_args
|
206
|
+
$0 = file
|
207
|
+
ARGV.clear
|
208
|
+
ARGV.replace(@config['programArgs'] || [])
|
209
|
+
end
|
210
|
+
|
211
|
+
def set_original_args
|
212
|
+
$0 = @original_prog
|
213
|
+
ARGV.clear
|
214
|
+
ARGV.replace @original_argv
|
215
|
+
end
|
216
|
+
|
217
|
+
def shutdown
|
218
|
+
exit
|
219
|
+
end
|
220
|
+
|
221
|
+
def send_event event, data, wait = false
|
222
|
+
changed
|
223
|
+
notify_observers event, data
|
224
|
+
sleep 0.01 if wait
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|