readapt 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d414f01a0f666c2b96e522ca8eaed42a796cbb929c46d13e813837cad1bafc0
4
- data.tar.gz: 18be9da48ce7f0ea2d2c1bcf038492fc73945617f9b650c51fedb69ae0aef8f5
3
+ metadata.gz: 660628a66dff5d1b46364c85d7ef3f115693463c1a94b18854ca79c7521a5b86
4
+ data.tar.gz: 4cbbffc522a4907d1819846262c473add5e76404f04bb3c654829301c704e821
5
5
  SHA512:
6
- metadata.gz: aa3fdb1fc8fc12a58dfec52c6f3cabe7876165efcbc56f88ee0c1f5ce1f734e79a2b53f4340be9f4ade0491c96ac0aec0683007022f93c598a70b25ef6b2606d
7
- data.tar.gz: 3087142261e3e42add244d763dd1555db7f0318839896e342d4cddada267a8538801cf66c1bb952e8f11e26166a50d6b8efcb216fbab7d1d7f1be381acd0e147
6
+ metadata.gz: 5f36dd16bf2e1a396eda01205e80fa5bf0d6ff3a12064297cbd6cba2f2f3643fb527a31c76c659bd4c49c32ae620d7dba72ede08ba677d0187cef0ba9b6b0ec5
7
+ data.tar.gz: 1e21ac739a23df49966a15a7b99477c5e0e795a8bc9600f779a9cd9c9ff58aa3c11b5a57fb4c9fb9732cf04287fa8614a99ecc561526fc6d20d9b73b4a305690
@@ -1,3 +1,10 @@
1
+ # 0.8.0 - November 9, 2019
2
+ - Multiple frames
3
+ - Flush output on disconnect
4
+ - Use Ruby debug inspector for stack frames
5
+ - Faster line processing
6
+ - Monitor disables GC
7
+
1
8
  # 0.7.1 - October 13, 2019
2
9
  - Debugger sets program name
3
10
 
data/Rakefile CHANGED
@@ -12,14 +12,3 @@ task :default => :spec
12
12
  Rake::ExtensionTask.new "readapt" do |ext|
13
13
  ext.lib_dir = "lib/readapt"
14
14
  end
15
-
16
- namespace :install do
17
- desc 'Install on Windows'
18
- task :win do
19
- Dir.mktmpdir do |tmp|
20
- gemfile = File.join(tmp, 'readapt.gem')
21
- system("gem build readapt.gemspec -o #{gemfile}") &&
22
- system("gem install #{gemfile}")
23
- end
24
- end
25
- end
@@ -54,11 +54,6 @@ int breakpoints_match(char *file, long line)
54
54
  return 0;
55
55
  }
56
56
 
57
- // int breakpoints_match(char *file, long line)
58
- // {
59
- // return breakpoints_match_id(rb_intern(file), line);
60
- // }
61
-
62
57
  static VALUE breakpoints_match_s(VALUE self, VALUE file, VALUE line)
63
58
  {
64
59
  return breakpoints_match(StringValueCStr(file), NUM2LONG(line)) == 0 ? Qfalse : Qtrue;
@@ -6,7 +6,6 @@ void initialize_breakpoints(VALUE m_Readapt);
6
6
  void breakpoints_set(char *file, long *lines);
7
7
  void breakpoints_delete(char *file);
8
8
  int breakpoints_match(char *file, long line);
9
- // int breakpoints_match_id(ht_key file, long line);
10
9
  long breakpoints_files();
11
10
 
12
11
  #endif
@@ -0,0 +1,137 @@
1
+ #include "ruby.h"
2
+ #include "ruby/debug.h"
3
+ #include "frame.h"
4
+ #include "normalize.h"
5
+
6
+ static VALUE c_Frame;
7
+
8
+ void frame_free(void *data)
9
+ {
10
+ frame_t *frm = data;
11
+
12
+ free(frm->file);
13
+ free(frm);
14
+ }
15
+
16
+ static size_t
17
+ frame_size(const void *data)
18
+ {
19
+ return sizeof(frame_t);
20
+ }
21
+
22
+ static const rb_data_type_t frame_type = {
23
+ .wrap_struct_name = "frame_data",
24
+ .function = {
25
+ .dmark = NULL,
26
+ .dfree = frame_free,
27
+ .dsize = frame_size,
28
+ },
29
+ .data = NULL,
30
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
31
+ };
32
+
33
+ VALUE frame_allocate_s(VALUE self)
34
+ {
35
+ VALUE obj;
36
+ frame_t *data = malloc(sizeof(frame_t));
37
+ obj = TypedData_Wrap_Struct(self, &frame_type, data);
38
+ data->file = NULL;
39
+ data->line = 0;
40
+ data->binding = Qnil;
41
+ return obj;
42
+ }
43
+
44
+ VALUE frame_allocate()
45
+ {
46
+ return frame_allocate_s(c_Frame);
47
+ }
48
+
49
+ frame_t *frame_data_from_tracepoint(VALUE tracepoint)
50
+ {
51
+ frame_t *data;
52
+ VALUE tmp;
53
+ rb_trace_arg_t *tracearg;
54
+ char *file;
55
+ int line;
56
+
57
+ data = malloc(sizeof(frame_t));
58
+ tracearg = rb_tracearg_from_tracepoint(tracepoint);
59
+ tmp = rb_tracearg_path(tracearg);
60
+ file = (tmp == Qnil ? NULL : normalize_path_new_cstr(StringValueCStr(tmp)));
61
+ line = NUM2INT(rb_tracearg_lineno(tracearg));
62
+
63
+ data->file = file;
64
+ data->line = line;
65
+ data->binding = Qnil;
66
+
67
+ return data;
68
+ }
69
+
70
+ VALUE frame_initialize_m(VALUE self, VALUE file, VALUE line, VALUE binding)
71
+ {
72
+ frame_t *data;
73
+ TypedData_Get_Struct(self, frame_t, &frame_type, data);
74
+ if (file == Qnil)
75
+ {
76
+ data->file = NULL;
77
+ }
78
+ else
79
+ {
80
+ data->file = normalize_path_new_cstr(StringValueCStr(file));
81
+ }
82
+ data->line = NUM2INT(line);
83
+ data->binding = binding;
84
+ return self;
85
+ }
86
+
87
+ VALUE frame_new_from_data(frame_t *data)
88
+ {
89
+ VALUE obj;
90
+
91
+ obj = frame_allocate();
92
+ frame_initialize_m(
93
+ obj,
94
+ rb_str_new_cstr(data->file),
95
+ INT2NUM(data->line),
96
+ data->binding);
97
+
98
+ return obj;
99
+ }
100
+
101
+ VALUE frame_file_m(VALUE self)
102
+ {
103
+ frame_t *data;
104
+ VALUE str = Qnil;
105
+
106
+ TypedData_Get_Struct(self, frame_t, &frame_type, data);
107
+ if (data->file)
108
+ {
109
+ str = rb_str_new_cstr(data->file);
110
+ rb_obj_freeze(str);
111
+ }
112
+ return str;
113
+ }
114
+
115
+ VALUE frame_line_m(VALUE self)
116
+ {
117
+ frame_t *data;
118
+ TypedData_Get_Struct(self, frame_t, &frame_type, data);
119
+ return INT2NUM(data->line);
120
+ }
121
+
122
+ VALUE frame_binding_m(VALUE self)
123
+ {
124
+ frame_t *data;
125
+ TypedData_Get_Struct(self, frame_t, &frame_type, data);
126
+ return data->binding;
127
+ }
128
+
129
+ void initialize_frame(VALUE m_Readapt)
130
+ {
131
+ c_Frame = rb_define_class_under(m_Readapt, "Frame", rb_cData);
132
+ rb_define_alloc_func(c_Frame, frame_allocate_s);
133
+ rb_define_method(c_Frame, "initialize", frame_initialize_m, 3);
134
+ rb_define_method(c_Frame, "file", frame_file_m, 0);
135
+ rb_define_method(c_Frame, "line", frame_line_m, 0);
136
+ rb_define_method(c_Frame, "frame_binding", frame_binding_m, 0);
137
+ }
@@ -0,0 +1,17 @@
1
+ #ifndef FRAME_H_
2
+ #define FRAME_H_
3
+
4
+ #include "ruby.h"
5
+
6
+ typedef struct frame_struct {
7
+ char *file;
8
+ int line;
9
+ VALUE binding;
10
+ } frame_t;
11
+
12
+ void initialize_frame(VALUE);
13
+ frame_t *frame_data_from_tracepoint(VALUE);
14
+ VALUE frame_new_from_data(frame_t *);
15
+ void frame_free(void *);
16
+
17
+ #endif
@@ -3,7 +3,6 @@
3
3
  #include <string.h>
4
4
 
5
5
  #include "hash_table.h"
6
- #include "ruby.h"
7
6
 
8
7
  static ht_long_array *copy_array(const long *value, const long size)
9
8
  {
@@ -1,8 +1,6 @@
1
1
  #ifndef HASH_TABLE_H_
2
2
  #define HASH_TABLE_H_
3
3
 
4
- #include "ruby.h"
5
-
6
4
  typedef struct ht_long_array
7
5
  {
8
6
  long *items;
@@ -0,0 +1,51 @@
1
+ #include "ruby.h"
2
+ #include "ruby/debug.h"
3
+ #include "frame.h"
4
+ #include "threads.h"
5
+ #include "normalize.h"
6
+
7
+ static VALUE process_inspection(const rb_debug_inspector_t *inspector, void *ptr)
8
+ {
9
+ VALUE locations;
10
+ long i_size;
11
+ long i;
12
+ VALUE loc;
13
+ VALUE path;
14
+ int line;
15
+ VALUE bnd;
16
+ thread_reference_t *data;
17
+ frame_t *frm;
18
+ VALUE iseq;
19
+
20
+ data = ptr;
21
+
22
+ locations = rb_debug_inspector_backtrace_locations(inspector);
23
+ i_size = locations == Qnil ? 0 : RARRAY_LENINT(locations);
24
+ for (i = i_size - 1; i >= 0; i--)
25
+ {
26
+ iseq = rb_debug_inspector_frame_iseq_get(inspector, i);
27
+ if (iseq != Qnil)
28
+ {
29
+ loc = rb_ary_entry(locations, i);
30
+ path = rb_funcall(loc, rb_intern("absolute_path"), 0);
31
+ line = NUM2INT(rb_funcall(loc, rb_intern("lineno"), 0));
32
+ bnd = rb_debug_inspector_frame_binding_get(inspector, i);
33
+
34
+ frm = malloc(sizeof(frame_t));
35
+ frm->file = normalize_path_new_cstr(StringValueCStr(path));
36
+ frm->line = line;
37
+ frm->binding = bnd;
38
+ stack_push(data->frames, frm);
39
+ }
40
+ }
41
+
42
+ return Qnil;
43
+ }
44
+
45
+ /**
46
+ * Get an array of frames from the Ruby debug inspector.
47
+ */
48
+ void inspector_inspect(thread_reference_t *data)
49
+ {
50
+ rb_debug_inspector_open(process_inspection, (void *)data);
51
+ }
@@ -0,0 +1,8 @@
1
+ #ifndef INSPECTOR_H_
2
+ #define INSPECTOR_H_
3
+
4
+ #include "ruby.h"
5
+
6
+ void inspector_inspect(thread_reference_t *);
7
+
8
+ #endif
@@ -46,18 +46,16 @@ static int match_step(thread_reference_t *ptr)
46
46
  static ID
47
47
  monitor_debug(const char *file, const long line, VALUE tracepoint, thread_reference_t *ptr, ID event)
48
48
  {
49
- VALUE bind, bid, snapshot, result;
49
+ VALUE snapshot, result, gc_disabled;
50
50
 
51
- bind = rb_funcall(tracepoint, rb_intern("binding"), 0);
52
- bid = rb_funcall(bind, rb_intern("object_id"), 0);
53
- snapshot = rb_funcall(c_Snapshot, rb_intern("new"), 7,
51
+ // Disable garbage collection to avoid segfaults in Frame#frame_binding
52
+ gc_disabled = rb_gc_disable();
53
+ thread_reference_build_frames(ptr);
54
+ snapshot = rb_funcall(c_Snapshot, rb_intern("new"), 4,
54
55
  LONG2NUM(ptr->id),
55
- bid,
56
56
  rb_str_new_cstr(file),
57
57
  INT2NUM(line),
58
- Qnil,
59
- ID2SYM(event),
60
- INT2NUM(ptr->depth)
58
+ ID2SYM(event)
61
59
  );
62
60
  rb_io_flush(rb_stdout);
63
61
  rb_io_flush(rb_stderr);
@@ -68,33 +66,44 @@ monitor_debug(const char *file, const long line, VALUE tracepoint, thread_refere
68
66
  ptr->cursor = ptr->depth;
69
67
  ptr->control = result;
70
68
  }
69
+ thread_reference_clear_frames(ptr);
70
+ if (!RTEST(gc_disabled))
71
+ {
72
+ rb_gc_enable();
73
+ }
71
74
  return result;
72
75
  }
73
76
 
74
77
  static void
75
78
  process_line_event(VALUE tracepoint, void *data)
76
79
  {
77
- VALUE ref, tmp;
78
- char *tp_file;
79
- long tp_line;
80
+ VALUE ref;
80
81
  thread_reference_t *ptr;
81
- rb_trace_arg_t *tp;
82
+ rb_trace_arg_t *arg;
82
83
  int threadPaused;
83
84
  ID dapEvent;
85
+ VALUE tmp;
86
+ char *tp_file;
87
+ long tp_line;
84
88
 
85
89
  ref = thread_current_reference();
86
90
  if (ref != Qnil)
87
91
  {
88
92
  ptr = thread_reference_pointer(ref);
89
93
  threadPaused = (ptr->control == id_pause);
94
+
90
95
  if (firstLineEvent && ptr->control == id_continue && breakpoints_files() == 0)
91
96
  {
92
97
  return;
93
98
  }
94
- tp = rb_tracearg_from_tracepoint(tracepoint);
95
- tmp = rb_tracearg_path(tp);
96
- tp_file = normalize_path_new_cstr(StringValueCStr(tmp));
97
- tp_line = NUM2LONG(rb_tracearg_lineno(tp));
99
+
100
+ arg = rb_tracearg_from_tracepoint(tracepoint);
101
+ tmp = rb_tracearg_path(arg);
102
+ // tp_file = normalize_path_new_cstr(StringValueCStr(tmp));
103
+ tp_file = StringValueCStr(tmp);
104
+ normalize_path(tp_file);
105
+ tmp = rb_tracearg_lineno(arg);
106
+ tp_line = NUM2INT(tmp);
98
107
 
99
108
  dapEvent = id_continue;
100
109
  if (!firstLineEvent)
@@ -128,7 +137,7 @@ process_line_event(VALUE tracepoint, void *data)
128
137
  monitor_debug(tp_file, tp_line, tracepoint, ptr, dapEvent);
129
138
  }
130
139
 
131
- free(tp_file);
140
+ // free(tp_file);
132
141
  }
133
142
  }
134
143
 
@@ -163,7 +172,7 @@ process_return_event(VALUE tracepoint, void *data)
163
172
  static void
164
173
  process_thread_begin_event(VALUE tracepoint, void *data)
165
174
  {
166
- VALUE list, here, prev, ref;
175
+ VALUE list, here, ref;
167
176
  thread_reference_t *ptr;
168
177
 
169
178
  list = rb_funcall(rb_cThread, rb_intern("list"), 0);
@@ -189,12 +198,15 @@ process_thread_end_event(VALUE tracepoint, void *data)
189
198
  thread_reference_t *ptr;
190
199
 
191
200
  thr = rb_thread_current();
192
- ref = thread_reference(thr);
193
- if (ref != Qnil)
201
+ if (thr != Qnil)
194
202
  {
195
- ptr = thread_reference_pointer(ref);
196
- monitor_debug("", 0, tracepoint, ptr, rb_intern("thread_end"));
197
- thread_delete_reference(thr);
203
+ ref = thread_reference(thr);
204
+ if (ref != Qnil)
205
+ {
206
+ ptr = thread_reference_pointer(ref);
207
+ monitor_debug("", 0, tracepoint, ptr, rb_intern("thread_end"));
208
+ thread_delete_reference(thr);
209
+ }
198
210
  }
199
211
  }
200
212
 
@@ -255,6 +267,7 @@ monitor_disable_s(VALUE self)
255
267
 
256
268
  free(entryFile);
257
269
  entryFile = NULL;
270
+ thread_clear();
258
271
 
259
272
  return previous;
260
273
  }
@@ -280,15 +293,15 @@ void initialize_monitor(VALUE m_Readapt)
280
293
  m_Monitor = rb_define_module_under(m_Readapt, "Monitor");
281
294
  c_Snapshot = rb_define_class_under(m_Readapt, "Snapshot", rb_cObject);
282
295
 
283
- initialize_threads();
296
+ initialize_threads(m_Readapt);
284
297
 
285
298
  rb_define_singleton_method(m_Monitor, "start", monitor_enable_s, 1);
286
299
  rb_define_singleton_method(m_Monitor, "stop", monitor_disable_s, 0);
287
300
  rb_define_singleton_method(m_Monitor, "pause", monitor_pause_s, 1);
288
301
 
289
302
  tpLine = rb_tracepoint_new(Qnil, RUBY_EVENT_LINE, process_line_event, NULL);
290
- tpCall = rb_tracepoint_new(Qnil, RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS, process_call_event, NULL);
291
- tpReturn = rb_tracepoint_new(Qnil, RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END, process_return_event, NULL);
303
+ tpCall = rb_tracepoint_new(Qnil, RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS | RUBY_EVENT_C_CALL, process_call_event, NULL);
304
+ tpReturn = rb_tracepoint_new(Qnil, RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END | RUBY_EVENT_C_RETURN, process_return_event, NULL);
292
305
  tpThreadBegin = rb_tracepoint_new(Qnil, RUBY_EVENT_THREAD_BEGIN, process_thread_begin_event, NULL);
293
306
  tpThreadEnd = rb_tracepoint_new(Qnil, RUBY_EVENT_THREAD_END, process_thread_end_event, NULL);
294
307
  debugProc = Qnil;
@@ -14,25 +14,31 @@ checkIfWindows()
14
14
  return result == Qnil ? 0 : 1;
15
15
  }
16
16
 
17
- char *normalize_path_new_cstr(char *str)
17
+ void normalize_path(char *str)
18
18
  {
19
- char *buffer;
20
19
  long i, len;
21
20
 
22
- buffer = malloc((strlen(str) + 1) * sizeof(char));
23
- strcpy(buffer, str);
24
21
  if (isWindows)
25
22
  {
26
- buffer[0] = toupper(buffer[0]);
27
- len = strlen(buffer);
23
+ str[0] = toupper(str[0]);
24
+ len = strlen(str);
28
25
  for (i = 2; i < len; i++)
29
26
  {
30
- if (buffer[i] == '\\')
27
+ if (str[i] == '\\')
31
28
  {
32
- buffer[i] = '/';
29
+ str[i] = '/';
33
30
  }
34
31
  }
35
32
  }
33
+ }
34
+
35
+ char *normalize_path_new_cstr(char *str)
36
+ {
37
+ char *buffer;
38
+
39
+ buffer = malloc((strlen(str) + 1) * sizeof(char));
40
+ strcpy(buffer, str);
41
+ normalize_path(buffer);
36
42
  return buffer;
37
43
  }
38
44