readapt 0.7.1 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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 +76 -53
  6. data/Gemfile +4 -4
  7. data/LICENSE.txt +21 -21
  8. data/README.md +37 -29
  9. data/Rakefile +14 -25
  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 -88
  14. data/ext/readapt/breakpoints.h +11 -12
  15. data/ext/readapt/extconf.rb +0 -0
  16. data/ext/readapt/frame.c +137 -0
  17. data/ext/readapt/frame.h +17 -0
  18. data/ext/readapt/hash_table.c +211 -212
  19. data/ext/readapt/hash_table.h +30 -32
  20. data/ext/readapt/inspector.c +51 -0
  21. data/ext/readapt/inspector.h +8 -0
  22. data/ext/readapt/monitor.c +40 -27
  23. data/ext/readapt/monitor.h +0 -0
  24. data/ext/readapt/normalize.c +59 -53
  25. data/ext/readapt/normalize.h +7 -7
  26. data/ext/readapt/readapt.c +18 -16
  27. data/ext/readapt/stack.c +86 -0
  28. data/ext/readapt/stack.h +20 -0
  29. data/ext/readapt/threads.c +111 -17
  30. data/ext/readapt/threads.h +11 -4
  31. data/lib/readapt.rb +21 -19
  32. data/lib/readapt/adapter.rb +98 -138
  33. data/lib/readapt/breakpoint.rb +20 -13
  34. data/lib/readapt/data_reader.rb +62 -0
  35. data/lib/readapt/debugger.rb +220 -204
  36. data/lib/readapt/error.rb +63 -0
  37. data/lib/readapt/finder.rb +20 -20
  38. data/lib/readapt/frame.rb +40 -42
  39. data/lib/readapt/input.rb +7 -0
  40. data/lib/readapt/message.rb +62 -59
  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 -25
  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 -26
  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 -57
  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 -39
  64. data/lib/readapt/snapshot.rb +1 -13
  65. data/lib/readapt/thread.rb +23 -39
  66. data/lib/readapt/variable.rb +1 -1
  67. data/lib/readapt/version.rb +3 -3
  68. data/readapt.gemspec +39 -39
  69. metadata +19 -8
  70. data/lib/readapt/location.rb +0 -25
@@ -0,0 +1,20 @@
1
+ #ifndef STACK_H_
2
+ #define STACK_H_
3
+
4
+ #include "stddef.h"
5
+
6
+ typedef struct readapt_stack_struct {
7
+ int size;
8
+ size_t elem_size;
9
+ void (*free_func)(void *);
10
+ int capacity;
11
+ void **elements;
12
+ } readapt_stack_t;
13
+
14
+ readapt_stack_t *stack_alloc(size_t elem_size, void(*free_func)(void*));
15
+ void stack_push(readapt_stack_t *stack, void *element);
16
+ void *stack_peek(readapt_stack_t *stack);
17
+ void stack_pop(readapt_stack_t *stack);
18
+ void stack_free(readapt_stack_t *stack);
19
+
20
+ #endif
@@ -1,15 +1,24 @@
1
1
  #include "ruby.h"
2
2
  #include "ruby/debug.h"
3
3
  #include "threads.h"
4
+ #include "frame.h"
5
+ #include "inspector.h"
4
6
 
7
+ static VALUE c_Thread;
5
8
  static VALUE threads;
9
+ static VALUE ids;
10
+ static int next_id;
6
11
 
7
- void thread_reference_free(void* data)
12
+ static void thread_reference_free(void* data)
8
13
  {
9
- free(data);
14
+ thread_reference_t* thr;
15
+
16
+ thr = data;
17
+ stack_free(thr->frames);
18
+ free(thr);
10
19
  }
11
20
 
12
- size_t thread_reference_size(const void* data)
21
+ static size_t thread_reference_size(const void* data)
13
22
  {
14
23
  return sizeof(thread_reference_t);
15
24
  }
@@ -25,20 +34,16 @@ static const rb_data_type_t thread_reference_type = {
25
34
  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
26
35
  };
27
36
 
28
- void initialize_threads()
29
- {
30
- threads = rb_hash_new();
31
- rb_global_variable(&threads);
32
- }
33
-
34
- VALUE thread_reference_new(VALUE thr)
37
+ static VALUE thread_reference_new(VALUE thr)
35
38
  {
36
39
  thread_reference_t *data = malloc(sizeof(thread_reference_t));
37
- VALUE obj = TypedData_Make_Struct(rb_cData, thread_reference_t, &thread_reference_type, data);
38
- data->id = NUM2LONG(rb_funcall(thr, rb_intern("object_id"), 0));
39
- data->depth = 0;
40
+ VALUE obj = TypedData_Make_Struct(c_Thread, thread_reference_t, &thread_reference_type, data);
41
+ data->id = next_id;
40
42
  data->cursor = 0;
43
+ data->depth = 0;
41
44
  data->control = rb_intern("continue");
45
+ data->frames = stack_alloc(sizeof(frame_t), frame_free);
46
+ next_id++;
42
47
  return obj;
43
48
  }
44
49
 
@@ -61,22 +66,25 @@ VALUE thread_reference(VALUE thr)
61
66
 
62
67
  VALUE thread_reference_id(VALUE id)
63
68
  {
64
- return rb_hash_aref(threads, id);
69
+ return rb_hash_aref(ids, id);
65
70
  }
66
71
 
67
72
  VALUE thread_add_reference(VALUE thr)
68
73
  {
69
74
  VALUE ref;
75
+ thread_reference_t *ptr;
70
76
 
71
77
  ref = thread_reference_new(thr);
78
+ ptr = thread_reference_pointer(ref);
72
79
  rb_hash_aset(threads, rb_obj_id(thr), ref);
80
+ rb_hash_aset(ids, INT2NUM(ptr->id), ref);
73
81
  return ref;
74
82
  }
75
83
 
76
84
  VALUE thread_delete_reference(VALUE thr)
77
85
  {
78
- rb_hash_delete(threads, thr);
79
- return Qnil;
86
+ // TODO: Do we need to delete from ids here?
87
+ return rb_hash_delete(threads, rb_obj_id(thr));
80
88
  }
81
89
 
82
90
  void thread_pause()
@@ -95,7 +103,93 @@ void thread_pause()
95
103
  }
96
104
  }
97
105
 
98
- void thread_reset()
106
+ void thread_clear()
99
107
  {
100
108
  rb_funcall(threads, rb_intern("clear"), 0);
109
+ rb_funcall(ids, rb_intern("clear"), 0);
110
+ }
111
+
112
+ static VALUE thread_allocate_s(VALUE self)
113
+ {
114
+ thread_reference_t *data = malloc(sizeof(thread_reference_t));
115
+ data->control = rb_intern("continue");
116
+ data->depth = 0;
117
+ data->cursor = 0;
118
+ data->frames = stack_alloc(sizeof(frame_t), frame_free);
119
+ data->id = 0;
120
+ return TypedData_Wrap_Struct(self, &thread_reference_type, data);
121
+ }
122
+
123
+ static VALUE thread_all_s(VALUE self)
124
+ {
125
+ return rb_funcall(threads, rb_intern("values"), 0);
126
+ }
127
+
128
+ static VALUE thread_find_s(VALUE self, VALUE id)
129
+ {
130
+ return thread_reference_id(id);
131
+ }
132
+
133
+ static VALUE thread_include_s(VALUE self, VALUE id)
134
+ {
135
+ return rb_funcall(ids, rb_intern("include?"), 1, id);
136
+ }
137
+
138
+ static VALUE thread_id_m(VALUE self)
139
+ {
140
+ thread_reference_t *data = thread_reference_pointer(self);
141
+ return LONG2NUM(data->id);
142
+ }
143
+
144
+ static VALUE frames_m(VALUE self)
145
+ {
146
+ thread_reference_t *data;
147
+ VALUE ary;
148
+ VALUE frm;
149
+ int i;
150
+ frame_t *fd;
151
+
152
+ ary = rb_ary_new();
153
+ data = thread_reference_pointer(self);
154
+ for (i = data->frames->size - 1; i >= 0; i--)
155
+ {
156
+ fd = data->frames->elements[i];
157
+ // TODO This condition should probably not be necessary.
158
+ if (fd->binding != Qnil)
159
+ {
160
+ frm = frame_new_from_data(fd);
161
+ rb_ary_push(ary, frm);
162
+ }
163
+ }
164
+
165
+ return ary;
166
+ }
167
+
168
+ void thread_reference_build_frames(thread_reference_t *ptr)
169
+ {
170
+ inspector_inspect(ptr);
171
+ }
172
+
173
+ void thread_reference_clear_frames(thread_reference_t *ptr)
174
+ {
175
+ stack_free(ptr->frames);
176
+ ptr->frames = stack_alloc(sizeof(frame_t), frame_free);
177
+ }
178
+
179
+ void initialize_threads(VALUE m_Readapt)
180
+ {
181
+ next_id = 1;
182
+
183
+ c_Thread = rb_define_class_under(m_Readapt, "Thread", rb_cData);
184
+ rb_define_alloc_func(c_Thread, thread_allocate_s);
185
+ rb_define_method(c_Thread, "id", thread_id_m, 0);
186
+ rb_define_method(c_Thread, "frames", frames_m, 0);
187
+ rb_define_singleton_method(c_Thread, "all", thread_all_s, 0);
188
+ rb_define_singleton_method(c_Thread, "find", thread_find_s, 1);
189
+ rb_define_singleton_method(c_Thread, "include?", thread_include_s, 1);
190
+
191
+ threads = rb_hash_new();
192
+ rb_global_variable(&threads);
193
+ ids = rb_hash_new();
194
+ rb_global_variable(&ids);
101
195
  }
@@ -1,21 +1,28 @@
1
1
  #ifndef THREADS_H_
2
2
  #define THREADS_H_
3
3
 
4
+ #include "ruby.h"
5
+ #include "frame.h"
6
+ #include "stack.h"
7
+
4
8
  typedef struct thread_reference_struct {
5
- long id;
6
- int depth;
9
+ int id;
7
10
  int cursor;
11
+ int depth;
8
12
  ID control;
13
+ readapt_stack_t *frames;
9
14
  } thread_reference_t;
10
15
 
11
- void initialize_threads();
16
+ void initialize_threads(VALUE);
12
17
  VALUE thread_current_reference();
13
18
  VALUE thread_reference(VALUE);
14
19
  VALUE thread_reference_id(VALUE);
15
20
  VALUE thread_add_reference(VALUE);
16
21
  VALUE thread_delete_reference(VALUE);
17
22
  thread_reference_t *thread_reference_pointer(VALUE);
23
+ void thread_reference_build_frames(thread_reference_t *);
24
+ void thread_reference_clear_frames(thread_reference_t *);
18
25
  void thread_pause();
19
- void thread_reset();
26
+ void thread_clear();
20
27
 
21
28
  #endif
@@ -1,19 +1,21 @@
1
- require 'backport'
2
-
3
- require 'readapt/version'
4
- require 'readapt/breakpoint'
5
- require 'readapt/location'
6
- require 'readapt/thread'
7
- require 'readapt/frame'
8
- require 'readapt/monitor'
9
- require 'readapt/snapshot'
10
- require 'readapt/finder'
11
- require 'readapt/debugger'
12
- require 'readapt/message'
13
- require 'readapt/variable'
14
- require 'readapt/adapter'
15
- require 'readapt/readapt'
16
- require 'readapt/shell'
17
-
18
- module Readapt
19
- end
1
+ require 'backport'
2
+
3
+ require 'readapt/version'
4
+ require 'readapt/readapt'
5
+ require 'readapt/references'
6
+ require 'readapt/breakpoint'
7
+ require 'readapt/thread'
8
+ require 'readapt/frame'
9
+ require 'readapt/monitor'
10
+ require 'readapt/snapshot'
11
+ require 'readapt/finder'
12
+ require 'readapt/debugger'
13
+ require 'readapt/message'
14
+ require 'readapt/variable'
15
+ require 'readapt/data_reader'
16
+ require 'readapt/server'
17
+ require 'readapt/adapter'
18
+ require 'readapt/input'
19
+ require 'readapt/output'
20
+ require 'readapt/error'
21
+ require 'readapt/shell'
@@ -1,138 +1,98 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
-
5
- module Readapt
6
- module Adapter
7
- # @!parse include Backport::Adapter
8
-
9
- @@debugger = nil
10
-
11
- def self.host debugger
12
- @@debugger = debugger
13
- end
14
-
15
- def format result
16
- write_line result.to_protocol.to_json
17
- end
18
-
19
- def opening
20
- @@debugger.add_observer self
21
- @data_reader = DataReader.new
22
- @data_reader.set_message_handler do |message|
23
- process message
24
- end
25
- end
26
-
27
- def closing
28
- @@debugger.delete_observer(self)
29
- end
30
-
31
- def receiving data
32
- @data_reader.receive data
33
- end
34
-
35
- def update event, data
36
- obj = {
37
- type: 'event',
38
- event: event
39
- }
40
- obj[:body] = data unless data.nil?
41
- json = obj.to_json
42
- envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
43
- write envelope
44
- end
45
-
46
- private
47
-
48
- # @param data [Hash]
49
- # @return [void]
50
- def process data
51
- # @todo Better solution than nil frames
52
- message = Message.process(data, @@debugger)
53
- if data['seq']
54
- json = {
55
- type: 'response',
56
- request_seq: data['seq'],
57
- success: true,
58
- command: data['command'],
59
- body: message.body
60
- }.to_json
61
- envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
62
- write envelope
63
- close if data['command'] == 'disconnect'
64
- return unless data['command'] == 'initialize'
65
- json = {
66
- type: 'event',
67
- event: 'initialized'
68
- }.to_json
69
- envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
70
- write envelope
71
- end
72
- rescue Exception => e
73
- STDERR.puts e.message
74
- STDERR.puts e.backtrace
75
- end
76
- end
77
-
78
- class DataReader
79
- def initialize
80
- @in_header = true
81
- @content_length = 0
82
- @buffer = String.new
83
- end
84
-
85
- # Declare a block to be executed for each message received from the
86
- # client.
87
- #
88
- # @yieldparam [Hash] The message received from the client
89
- def set_message_handler &block
90
- @message_handler = block
91
- end
92
-
93
- # Process raw data received from the client. The data will be parsed
94
- # into messages based on the JSON-RPC protocol. Each message will be
95
- # passed to the block declared via set_message_handler. Incomplete data
96
- # will be buffered and subsequent data will be appended to the buffer.
97
- #
98
- # @param data [String]
99
- def receive data
100
- data.each_char do |char|
101
- @buffer.concat char
102
- if @in_header
103
- prepare_to_parse_message if @buffer.end_with?("\r\n\r\n")
104
- else
105
- parse_message_from_buffer if @buffer.bytesize == @content_length
106
- end
107
- end
108
- end
109
-
110
- private
111
-
112
- def prepare_to_parse_message
113
- @in_header = false
114
- @buffer.each_line do |line|
115
- parts = line.split(':').map(&:strip)
116
- if parts[0] == 'Content-Length'
117
- @content_length = parts[1].to_i
118
- break
119
- end
120
- end
121
- @buffer.clear
122
- end
123
-
124
- def parse_message_from_buffer
125
- begin
126
- msg = JSON.parse(@buffer)
127
- @message_handler.call msg unless @message_handler.nil?
128
- rescue JSON::ParserError => e
129
- Solargraph::Logging.logger.warn "Failed to parse request: #{e.message}"
130
- Solargraph::Logging.logger.debug "Buffer: #{@buffer}"
131
- ensure
132
- @buffer.clear
133
- @in_header = true
134
- @content_length = 0
135
- end
136
- end
137
- end
138
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Readapt
6
+ module Adapter
7
+ # @!parse include Backport::Adapter
8
+
9
+ @@debugger = nil
10
+
11
+ def self.host debugger
12
+ @@debugger = debugger
13
+ end
14
+
15
+ def self.procid= pid
16
+ @@procid = pid
17
+ end
18
+
19
+ def procid
20
+ @@procid
21
+ end
22
+
23
+ def open_message
24
+ @@open_message ||= "<readapt-#{procid}>"
25
+ end
26
+
27
+ def close_message
28
+ @@close_message ||= "</readapt-#{procid}>"
29
+ end
30
+
31
+ def format result
32
+ write_line result.to_protocol.to_json
33
+ end
34
+
35
+ def opening
36
+ @@debugger.add_observer self
37
+ @data_reader = DataReader.new
38
+ @data_reader.set_message_handler do |message|
39
+ process message
40
+ end
41
+ end
42
+
43
+ def closing
44
+ @@debugger.delete_observer(self)
45
+ end
46
+
47
+ def receiving data
48
+ @data_reader.receive data
49
+ end
50
+
51
+ def update event, data
52
+ obj = {
53
+ type: 'event',
54
+ event: event
55
+ }
56
+ obj[:body] = data unless data.nil?
57
+ json = obj.to_json
58
+ envelope = "#{open_message}Content-Length: #{json.bytesize}\r\n\r\n#{json}#{close_message}"
59
+ write envelope
60
+ write "#{open_message}__TERMINATE__#{close_message}" if event == 'terminated'
61
+ end
62
+
63
+ private
64
+
65
+ # @param data [Hash]
66
+ # @return [void]
67
+ def process data
68
+ message = Message.process(data, @@debugger)
69
+ if data['seq']
70
+ json = {
71
+ type: 'response',
72
+ request_seq: data['seq'],
73
+ success: true,
74
+ command: data['command'],
75
+ body: message.body
76
+ }.to_json
77
+ envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
78
+ write "#{open_message}#{envelope}#{close_message}"
79
+ if data['command'] == 'disconnect'
80
+ @@debugger.disconnect
81
+ # @todo It does not appear necessary to close the adapter after
82
+ # disconnecting the debugger.
83
+ # close
84
+ end
85
+ return unless data['command'] == 'initialize'
86
+ json = {
87
+ type: 'event',
88
+ event: 'initialized'
89
+ }.to_json
90
+ envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
91
+ write "#{open_message}#{envelope}#{close_message}"
92
+ end
93
+ rescue RuntimeError => e
94
+ STDERR.puts "[#{e.class}] #{e.message}"
95
+ STDERR.puts e.backtrace.join
96
+ end
97
+ end
98
+ end