readapt 1.4.0 → 1.4.1

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 -19
  5. data/CHANGELOG.md +91 -87
  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 +0 -0
  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 +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 -228
  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 -21
  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 -11
  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 -53
  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 +3 -3
@@ -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
- sleep 0.001 # @todo Trying to let thread data sync
129
- References.clear
130
- if snapshot.event == :thread_begin || snapshot.event == :entry
131
- thr = Thread.find(snapshot.thread_id)
132
- thr.control = :continue
133
- send_event('thread', {
134
- reason: 'started',
135
- threadId: snapshot.thread_id
136
- }, true)
137
- snapshot.control = :continue
138
- elsif snapshot.event == :thread_end
139
- thr = thread(snapshot.thread_id)
140
- thr.control = :continue
141
- send_event('thread', {
142
- reason: 'exited',
143
- threadId: snapshot.thread_id
144
- })
145
- snapshot.control = :continue
146
- else
147
- confirmed_pause = true
148
- thread = self.thread(snapshot.thread_id)
149
- if snapshot.event == :breakpoint
150
- bp = get_breakpoint(snapshot.file, snapshot.line)
151
- unless bp.condition.nil? || bp.condition.empty?
152
- # @type [Binding]
153
- bnd = thread.frames.first.frame_binding
154
- begin
155
- unless bnd.eval(bp.condition)
156
- confirmed_pause = false
157
- end
158
- rescue Exception => e
159
- STDERR.puts "Breakpoint condition raised an error"
160
- STDERR.puts "#{snapshot.file}:#{snapshot.line} - `#{bp.condition}`"
161
- STDERR.puts "[#{e.class}] #{e.message}"
162
- confirmed_pause = false
163
- end
164
- end
165
- unless !confirmed_pause || bp.hit_condition.nil? || bp.hit_condition.empty?
166
- bp.hit_cursor += 1
167
- bnd = thread.frames.first.frame_binding
168
- begin
169
- hit_count = bnd.eval(bp.hit_condition)
170
- if bp.hit_cursor == hit_count
171
- bp.hit_cursor = 0
172
- else
173
- confirmed_pause = false
174
- end
175
- rescue Exception => e
176
- STDERR.puts "Breakpoint condition raised an error"
177
- STDERR.puts "#{snapshot.file}:#{snapshot.line} - `#{bp.condition}`"
178
- STDERR.puts "[#{e.class}] #{e.message}"
179
- confirmed_pause = false
180
- end
181
- end
182
- elsif snapshot.event == :raise && !pause_on_raise?
183
- confirmed_pause = false
184
- end
185
- if confirmed_pause
186
- changed
187
- thread.control = :pause
188
- thread.frames.each do |frm|
189
- @frames[frm.local_id] = frm
190
- end
191
- send_event('stopped', {
192
- reason: snapshot.event,
193
- threadId: thread.id
194
- })
195
- sleep 0.01 until thread.control != :pause || !Thread.include?(thread.id)
196
- thread.frames.each do |frm|
197
- @frames.delete frm.local_id
198
- end
199
- else
200
- thread.control = :continue
201
- end
202
- snapshot.control = thread.control
203
- end
204
- end
205
-
206
- def set_program_args
207
- $0 = file
208
- ARGV.clear
209
- ARGV.replace(@config['programArgs'] || [])
210
- end
211
-
212
- def set_original_args
213
- $0 = @original_prog
214
- ARGV.clear
215
- ARGV.replace @original_argv
216
- end
217
-
218
- def shutdown
219
- exit
220
- end
221
-
222
- def send_event event, data, wait = false
223
- changed
224
- notify_observers event, data
225
- sleep 0.01 if wait
226
- end
227
- end
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