readapt 0.8.0 → 1.2.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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +16 -14
  3. data/.rspec +2 -2
  4. data/.travis.yml +18 -13
  5. data/CHANGELOG.md +80 -60
  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/inspector.c +51 -51
  19. data/ext/readapt/inspector.h +8 -8
  20. data/ext/readapt/{hash_table.c → lookup_table.c} +211 -211
  21. data/ext/readapt/lookup_table.h +30 -0
  22. data/ext/readapt/monitor.c +42 -5
  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 +2 -2
  31. data/lib/readapt.rb +21 -18
  32. data/lib/readapt/adapter.rb +98 -138
  33. data/lib/readapt/breakpoint.rb +21 -20
  34. data/lib/readapt/data_reader.rb +62 -0
  35. data/lib/readapt/debugger.rb +220 -224
  36. data/lib/readapt/error.rb +63 -0
  37. data/lib/readapt/finder.rb +34 -20
  38. data/lib/readapt/frame.rb +40 -40
  39. data/lib/readapt/input.rb +7 -0
  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 -14
  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 -0
  61. data/lib/readapt/references.rb +27 -0
  62. data/lib/readapt/server.rb +22 -0
  63. data/lib/readapt/shell.rb +104 -41
  64. data/lib/readapt/snapshot.rb +0 -0
  65. data/lib/readapt/thread.rb +25 -28
  66. data/lib/readapt/variable.rb +1 -1
  67. data/lib/readapt/version.rb +3 -3
  68. data/readapt.gemspec +39 -39
  69. metadata +15 -9
  70. data/ext/readapt/hash_table.h +0 -30
@@ -1,18 +1,18 @@
1
- # frozen_string_literal: true
2
-
3
- module Readapt
4
- module Message
5
- class Threads < Base
6
- def run
7
- set_body({
8
- threads: debugger.threads.map do |thr|
9
- {
10
- id: thr.id,
11
- name: thr.name
12
- }
13
- end
14
- })
15
- end
16
- end
17
- end
18
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Readapt
4
+ module Message
5
+ class Threads < Base
6
+ def run
7
+ set_body({
8
+ threads: debugger.threads.map do |thr|
9
+ {
10
+ id: thr.id,
11
+ name: thr.name
12
+ }
13
+ end
14
+ })
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,61 +1,61 @@
1
- # frozen_string_literal: true
2
-
3
- module Readapt
4
- module Message
5
- class Variables < Base
6
- def run
7
- ref = arguments['variablesReference']
8
- frame = debugger.frame(ref)
9
- # @todo 1 is a magic number representing the toplevel binding (see
10
- # Message::Scopes)
11
- vars = if ref == 1
12
- global_variables.map do |gv|
13
- Variable.new(gv, eval(gv.to_s))
14
- end
15
- else
16
- if frame != Frame::NULL_FRAME && !frame.nil?
17
- frame.locals
18
- else
19
- obj = object_reference
20
- result = []
21
- if obj.is_a?(Array)
22
- obj.each_with_index do |itm, idx|
23
- result.push Variable.new("[#{idx}]", itm)
24
- end
25
- elsif obj.is_a?(Hash)
26
- obj.each_pair do |idx, itm|
27
- result.push Variable.new("[#{idx}]", itm)
28
- end
29
- else
30
- obj.instance_variables.each do |iv|
31
- result.push Variable.new(iv, obj.instance_variable_get(iv))
32
- end
33
- obj.class.class_variables.each do |cv|
34
- result.push Variable.new(cv, obj.class.class_variable_get(cv))
35
- end
36
- end
37
- result
38
- end
39
- end
40
- set_body({
41
- variables: vars.map do |var|
42
- {
43
- name: var.name,
44
- value: var.value,
45
- type: var.type,
46
- variablesReference: var.reference
47
- }
48
- end
49
- })
50
- end
51
-
52
- private
53
-
54
- def object_reference
55
- ObjectSpace._id2ref(arguments['variablesReference'])
56
- rescue RangeError
57
- nil
58
- end
59
- end
60
- end
61
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Readapt
4
+ module Message
5
+ class Variables < Base
6
+ def run
7
+ ref = arguments['variablesReference']
8
+ frame = debugger.frame(ref)
9
+ # @todo 1 is a magic number representing the toplevel binding (see
10
+ # Message::Scopes)
11
+ vars = if ref == 1
12
+ global_variables.map do |gv|
13
+ Variable.new(gv, eval(gv.to_s))
14
+ end
15
+ else
16
+ if frame != Frame::NULL_FRAME && !frame.nil?
17
+ frame.locals
18
+ else
19
+ obj = object_reference
20
+ result = []
21
+ if obj.is_a?(Array)
22
+ obj.each_with_index do |itm, idx|
23
+ result.push Variable.new("[#{idx}]", itm)
24
+ end
25
+ elsif obj.is_a?(Hash)
26
+ obj.each_pair do |idx, itm|
27
+ result.push Variable.new("[#{idx}]", itm)
28
+ end
29
+ else
30
+ obj.instance_variables.sort.each do |iv|
31
+ result.push Variable.new(iv, obj.instance_variable_get(iv))
32
+ end
33
+ obj.class.class_variables.sort.each do |cv|
34
+ result.push Variable.new(cv, obj.class.class_variable_get(cv))
35
+ end
36
+ end
37
+ result
38
+ end
39
+ end
40
+ set_body({
41
+ variables: vars.map do |var|
42
+ {
43
+ name: var.name,
44
+ value: var.value,
45
+ type: var.type,
46
+ variablesReference: var.reference
47
+ }
48
+ end
49
+ })
50
+ end
51
+
52
+ private
53
+
54
+ def object_reference
55
+ ObjectSpace._id2ref(arguments['variablesReference'])
56
+ rescue RangeError
57
+ nil
58
+ end
59
+ end
60
+ end
61
+ end
File without changes
@@ -0,0 +1,25 @@
1
+ module Readapt
2
+ module Output
3
+ class << self
4
+ attr_accessor :adapter
5
+ end
6
+
7
+ def receiving data
8
+ send_event('output', {
9
+ output: data.force_encoding('utf-8'),
10
+ category: 'stdout'
11
+ })
12
+ end
13
+
14
+ def send_event event, data
15
+ obj = {
16
+ type: 'event',
17
+ event: event
18
+ }
19
+ obj[:body] = data unless data.nil?
20
+ json = obj.to_json
21
+ envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
22
+ Output.adapter.write envelope
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ module Readapt
2
+ module References
3
+ module_function
4
+
5
+ @variable_reference_map = {}
6
+ @reference_variable_map = {}
7
+ @reference_id = 1000
8
+
9
+ def clear
10
+ @variable_reference_map.clear
11
+ @reference_variable_map.clear
12
+ @reference_id = 1000
13
+ end
14
+
15
+ def identify object
16
+ return @variable_reference_map[object] if @variable_reference_map.has_key?(object)
17
+ @reference_id += 1
18
+ @variable_reference_map[object] = @reference_id
19
+ @reference_variable_map[@reference_id] = object
20
+ @reference_id
21
+ end
22
+
23
+ def get id
24
+ @reference_variable_map[id]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ require 'securerandom'
2
+ require 'stringio'
3
+
4
+ module Readapt
5
+ module Server
6
+ class << self
7
+ attr_accessor :target_in
8
+ attr_accessor :target_pid
9
+ end
10
+
11
+ def opening
12
+ Error.adapter = self
13
+ Output.adapter = self
14
+ end
15
+
16
+ def receiving data
17
+ Server.target_in.syswrite data
18
+ rescue Errno::EPIPE, IOError
19
+ close
20
+ end
21
+ end
22
+ end
data/lib/readapt/shell.rb CHANGED
@@ -1,41 +1,104 @@
1
- require 'thor'
2
- require 'backport'
3
-
4
- module Readapt
5
- class Shell < Thor
6
- map %w[--version -v] => :version
7
-
8
- desc "--version, -v", "Print the version"
9
- def version
10
- puts Readapt::VERSION
11
- end
12
-
13
- desc 'serve', 'Run a DAP server'
14
- option :host, type: :string, aliases: :h, description: 'The server host', default: '127.0.0.1'
15
- option :port, type: :numeric, aliases: :p, description: 'The server port', default: 1234
16
- def serve
17
- STDOUT.sync = true
18
- STDERR.sync = true
19
- machine = Backport::Machine.new
20
- machine.run do
21
- Signal.trap("INT") do
22
- graceful_shutdown
23
- end
24
- Signal.trap("TERM") do
25
- graceful_shutdown
26
- end
27
- debugger = Readapt::Debugger.new(machine)
28
- Readapt::Adapter.host debugger
29
- machine.prepare Backport::Server::Tcpip.new(host: options[:host], port: options[:port], adapter: Readapt::Adapter)
30
- STDERR.puts "Readapt Debugger #{Readapt::VERSION} is listening HOST=#{options[:host]} PORT=#{options[:port]} PID=#{Process.pid}"
31
- end
32
- end
33
-
34
- private
35
-
36
- def graceful_shutdown
37
- Backport.stop
38
- exit
39
- end
40
- end
41
- end
1
+ require 'thor'
2
+ require 'backport'
3
+ require 'open3'
4
+ require 'securerandom'
5
+ require 'socket'
6
+
7
+ module Readapt
8
+ class Shell < Thor
9
+ map %w[--version -v] => :version
10
+
11
+ desc "--version, -v", "Print the version"
12
+ def version
13
+ puts Readapt::VERSION
14
+ end
15
+
16
+ desc 'socket', 'Run a DAP server over TCP'
17
+ option :host, type: :string, aliases: :h, description: 'The server host', default: '127.0.0.1'
18
+ option :port, type: :numeric, aliases: :p, description: 'The server port', default: 1234
19
+ def socket
20
+ machine = Backport::Machine.new
21
+ machine.run do
22
+ prepare_machine machine
23
+ server = Backport::Server::Tcpip.new(host: options[:host], port: options[:port], adapter: Readapt::Server)
24
+ machine.prepare server
25
+ STDERR.puts "Readapt Debugger #{Readapt::VERSION} is listening HOST=#{options[:host]} PORT=#{options[:port]} PID=#{Process.pid}"
26
+ end
27
+ end
28
+ map serve: :socket
29
+
30
+ desc 'stdio', 'Run a DAP server over STDIO'
31
+ def stdio
32
+ machine = Backport::Machine.new
33
+ machine.run do
34
+ prepare_machine machine
35
+ server = Backport::Server::Stdio.new(adapter: Readapt::Server)
36
+ machine.prepare server
37
+ end
38
+ end
39
+
40
+ desc 'target [PROCID]', 'Run a target process'
41
+ def target procid = nil
42
+ STDIN.binmode
43
+ STDOUT.binmode
44
+ STDERR.binmode
45
+ STDOUT.sync = true
46
+ STDERR.sync = true
47
+ Readapt::Adapter.procid = procid
48
+ machine = Backport::Machine.new
49
+ Signal.trap("INT") do
50
+ graceful_shutdown machine
51
+ end
52
+ Signal.trap("TERM") do
53
+ graceful_shutdown machine
54
+ end
55
+ machine.run do
56
+ debugger = Readapt::Debugger.new
57
+ Readapt::Adapter.host debugger
58
+ machine.prepare Backport::Server::Stdio.new(input: STDIN, output: STDERR, adapter: Readapt::Adapter)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ # @param machine [Backport::Machine]
65
+ # @return [void]
66
+ def prepare_machine machine
67
+ STDOUT.sync = true
68
+ STDERR.sync = true
69
+ Signal.trap("INT") do
70
+ graceful_shutdown machine
71
+ end
72
+ Signal.trap("TERM") do
73
+ graceful_shutdown machine
74
+ end
75
+ procid = SecureRandom.hex(8)
76
+ Readapt::Error.procid = procid
77
+ stdin, stdout, stderr, thr = Open3.popen3('ruby', $0, 'target', procid)
78
+ stdin.sync = true
79
+ stdout.sync = true
80
+ stderr.sync = true
81
+ stdin.binmode
82
+ Readapt::Server.target_in = stdin
83
+ Readapt::Server.target_pid = thr[:pid]
84
+ output = Backport::Server::Stdio.new(input: stdout, output: stdin, adapter: Readapt::Output)
85
+ error = Backport::Server::Stdio.new(input: stderr, output: stdin, adapter: Readapt::Error)
86
+ machine.prepare output
87
+ machine.prepare error
88
+ at_exit do
89
+ begin
90
+ Process.kill 'KILL', thr[:pid]
91
+ rescue Errno::ESRCH
92
+ # Ignore
93
+ end
94
+ end
95
+ end
96
+
97
+ # @param machine [Backport::Machine]
98
+ # @return [void]
99
+ def graceful_shutdown machine
100
+ machine.stop
101
+ exit
102
+ end
103
+ end
104
+ end
File without changes
@@ -1,28 +1,25 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ostruct'
4
-
5
- module Readapt
6
- class Thread
7
- @@next_id = 0
8
-
9
- # @return [Symbol]
10
- attr_accessor :control
11
-
12
- def name
13
- @name ||= begin
14
- @@next_id += 1
15
- "Thread #{@@next_id}"
16
- end
17
- end
18
-
19
- def object
20
- STDERR.puts "Getting #{id}"
21
- ObjectSpace._id2ref(id)
22
- end
23
-
24
- # def frames
25
- # @frames ||= []
26
- # end
27
- end
28
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+
5
+ module Readapt
6
+ class Thread
7
+ @@next_id = 0
8
+
9
+ # @return [Symbol]
10
+ attr_accessor :control
11
+
12
+ # @return [String]
13
+ def name
14
+ @name ||= begin
15
+ @@next_id += 1
16
+ "Thread #{@@next_id}"
17
+ end
18
+ end
19
+
20
+ # @return [Object]
21
+ def object
22
+ ObjectSpace._id2ref(id)
23
+ end
24
+ end
25
+ end
@@ -16,7 +16,7 @@ module Readapt
16
16
 
17
17
  # @return [Integer]
18
18
  def reference
19
- @reference ||= unstructured || object.object_id
19
+ @reference ||= unstructured || References.identify(object)
20
20
  end
21
21
 
22
22
  # @return [String]