readapt 1.0.0 → 1.1.0

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 -15
  3. data/.rspec +2 -2
  4. data/.travis.yml +18 -18
  5. data/CHANGELOG.md +72 -69
  6. data/Gemfile +4 -4
  7. data/LICENSE.txt +21 -21
  8. data/README.md +37 -29
  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/hash_table.c +211 -211
  19. data/ext/readapt/hash_table.h +30 -30
  20. data/ext/readapt/inspector.c +51 -51
  21. data/ext/readapt/inspector.h +8 -8
  22. data/ext/readapt/monitor.c +1 -1
  23. data/ext/readapt/monitor.h +0 -0
  24. data/ext/readapt/normalize.c +59 -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 +15 -11
  30. data/ext/readapt/threads.h +1 -1
  31. data/lib/readapt.rb +21 -20
  32. data/lib/readapt/adapter.rb +98 -98
  33. data/lib/readapt/breakpoint.rb +20 -20
  34. data/lib/readapt/data_reader.rb +62 -62
  35. data/lib/readapt/debugger.rb +220 -220
  36. data/lib/readapt/error.rb +63 -63
  37. data/lib/readapt/finder.rb +20 -20
  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 +13 -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 +8 -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 +61 -61
  59. data/lib/readapt/monitor.rb +0 -0
  60. data/lib/readapt/output.rb +25 -25
  61. data/lib/readapt/references.rb +27 -0
  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 +23 -23
  66. data/lib/readapt/variable.rb +1 -1
  67. data/lib/readapt/version.rb +3 -3
  68. data/readapt.gemspec +39 -39
  69. metadata +4 -3
@@ -1,220 +1,220 @@
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
- if snapshot.event == :thread_begin || snapshot.event == :entry
124
- thr = Thread.find(snapshot.thread_id)
125
- thr.control = :continue
126
- send_event('thread', {
127
- reason: 'started',
128
- threadId: snapshot.thread_id
129
- }, true)
130
- snapshot.control = :continue
131
- elsif snapshot.event == :thread_end
132
- thr = thread(snapshot.thread_id)
133
- thr.control = :continue
134
- # @threads.delete snapshot.thread_id
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
+ 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,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