readapt 1.2.0 → 1.4.3

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