readapt 0.7.1 → 1.1.1

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 +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
@@ -1,32 +1,30 @@
1
- #ifndef HASH_TABLE_H_
2
- #define HASH_TABLE_H_
3
-
4
- #include "ruby.h"
5
-
6
- typedef struct ht_long_array
7
- {
8
- long *items;
9
- long size;
10
- } ht_long_array;
11
-
12
- // ht_item is an item in the hash table
13
- typedef struct ht_item
14
- {
15
- char *key;
16
- ht_long_array *value;
17
- } ht_item;
18
-
19
- typedef struct ht_hash_table
20
- {
21
- long size;
22
- ht_item **items;
23
- } ht_hash_table;
24
-
25
- ht_hash_table *ht_new();
26
- void ht_del_hash_table(ht_hash_table *ht);
27
-
28
- void ht_insert(ht_hash_table *ht, char *key, const long *value, const long size);
29
- ht_long_array *ht_search(ht_hash_table *ht, char *key);
30
- void ht_delete(ht_hash_table *h, char *key);
31
-
32
- #endif // HASH_TABLE_H_
1
+ #ifndef HASH_TABLE_H_
2
+ #define HASH_TABLE_H_
3
+
4
+ typedef struct ht_long_array
5
+ {
6
+ long *items;
7
+ long size;
8
+ } ht_long_array;
9
+
10
+ // ht_item is an item in the hash table
11
+ typedef struct ht_item
12
+ {
13
+ char *key;
14
+ ht_long_array *value;
15
+ } ht_item;
16
+
17
+ typedef struct ht_hash_table
18
+ {
19
+ long size;
20
+ ht_item **items;
21
+ } ht_hash_table;
22
+
23
+ ht_hash_table *ht_new();
24
+ void ht_del_hash_table(ht_hash_table *ht);
25
+
26
+ void ht_insert(ht_hash_table *ht, char *key, const long *value, const long size);
27
+ ht_long_array *ht_search(ht_hash_table *ht, char *key);
28
+ void ht_delete(ht_hash_table *h, char *key);
29
+
30
+ #endif // HASH_TABLE_H_
@@ -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,
54
- LONG2NUM(ptr->id),
55
- bid,
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,
55
+ INT2NUM(ptr->id),
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;
File without changes
@@ -1,53 +1,59 @@
1
- #include "ruby.h"
2
- #include "ruby/debug.h"
3
- #include <ctype.h>
4
-
5
- static int isWindows;
6
-
7
- static int
8
- checkIfWindows()
9
- {
10
- VALUE regexp, result;
11
-
12
- regexp = rb_reg_new("/cygwin|mswin|mingw|bccwin|wince|emx/", 37, 0);
13
- result = rb_reg_match(regexp, rb_str_new_cstr(RUBY_PLATFORM));
14
- return result == Qnil ? 0 : 1;
15
- }
16
-
17
- char *normalize_path_new_cstr(char *str)
18
- {
19
- char *buffer;
20
- long i, len;
21
-
22
- buffer = malloc((strlen(str) + 1) * sizeof(char));
23
- strcpy(buffer, str);
24
- if (isWindows)
25
- {
26
- buffer[0] = toupper(buffer[0]);
27
- len = strlen(buffer);
28
- for (i = 2; i < len; i++)
29
- {
30
- if (buffer[i] == '\\')
31
- {
32
- buffer[i] = '/';
33
- }
34
- }
35
- }
36
- return buffer;
37
- }
38
-
39
- static VALUE
40
- normalize_path_s(VALUE self, VALUE str)
41
- {
42
- char *path = normalize_path_new_cstr(StringValueCStr(str));
43
- VALUE result = rb_str_new_cstr(path);
44
- free(path);
45
- return result;
46
- }
47
-
48
- void initialize_normalize(VALUE m_Readapt)
49
- {
50
- isWindows = checkIfWindows();
51
-
52
- rb_define_singleton_method(m_Readapt, "normalize_path", normalize_path_s, 1);
53
- }
1
+ #include "ruby.h"
2
+ #include "ruby/debug.h"
3
+ #include <ctype.h>
4
+
5
+ static int isWindows;
6
+
7
+ static int
8
+ checkIfWindows()
9
+ {
10
+ VALUE regexp, result;
11
+
12
+ regexp = rb_reg_new("/cygwin|mswin|mingw|bccwin|wince|emx/", 37, 0);
13
+ result = rb_reg_match(regexp, rb_str_new_cstr(RUBY_PLATFORM));
14
+ return result == Qnil ? 0 : 1;
15
+ }
16
+
17
+ void normalize_path(char *str)
18
+ {
19
+ long i, len;
20
+
21
+ if (isWindows)
22
+ {
23
+ str[0] = toupper(str[0]);
24
+ len = strlen(str);
25
+ for (i = 2; i < len; i++)
26
+ {
27
+ if (str[i] == '\\')
28
+ {
29
+ str[i] = '/';
30
+ }
31
+ }
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);
42
+ return buffer;
43
+ }
44
+
45
+ static VALUE
46
+ normalize_path_s(VALUE self, VALUE str)
47
+ {
48
+ char *path = normalize_path_new_cstr(StringValueCStr(str));
49
+ VALUE result = rb_str_new_cstr(path);
50
+ free(path);
51
+ return result;
52
+ }
53
+
54
+ void initialize_normalize(VALUE m_Readapt)
55
+ {
56
+ isWindows = checkIfWindows();
57
+
58
+ rb_define_singleton_method(m_Readapt, "normalize_path", normalize_path_s, 1);
59
+ }
@@ -1,7 +1,7 @@
1
- #ifndef NORMALIZE_H_
2
- #define NORMALIZE_H_
3
-
4
- void initialize_normalize(VALUE);
5
- char *normalize_path_new_cstr(char *str);
6
-
7
- #endif
1
+ #ifndef NORMALIZE_H_
2
+ #define NORMALIZE_H_
3
+
4
+ void initialize_normalize(VALUE);
5
+ char *normalize_path_new_cstr(char *str);
6
+ void normalize_path(char *str);
7
+ #endif
@@ -1,16 +1,18 @@
1
- #include "ruby.h"
2
- #include "ruby/debug.h"
3
- #include "monitor.h"
4
- #include "normalize.h"
5
- #include "breakpoints.h"
6
-
7
- static VALUE m_Readapt;
8
-
9
- void Init_readapt()
10
- {
11
- m_Readapt = rb_define_module("Readapt");
12
-
13
- initialize_normalize(m_Readapt);
14
- initialize_breakpoints(m_Readapt);
15
- initialize_monitor(m_Readapt);
16
- }
1
+ #include "ruby.h"
2
+ #include "ruby/debug.h"
3
+ #include "monitor.h"
4
+ #include "normalize.h"
5
+ #include "breakpoints.h"
6
+ #include "frame.h"
7
+
8
+ static VALUE m_Readapt;
9
+
10
+ void Init_readapt()
11
+ {
12
+ m_Readapt = rb_define_module("Readapt");
13
+
14
+ initialize_normalize(m_Readapt);
15
+ initialize_breakpoints(m_Readapt);
16
+ initialize_frame(m_Readapt);
17
+ initialize_monitor(m_Readapt);
18
+ }
@@ -0,0 +1,86 @@
1
+ #include <stdlib.h>
2
+ #include "stack.h"
3
+
4
+ #define STACK_CAPACITY 20
5
+
6
+ /**
7
+ * Allocate a stack. The `elem_size` is the expected size of each element,
8
+ * e.g., `sizeof(some_struct)`. The optional `free_func` argument is a pointer
9
+ * to a function that will be called when an element is popped off the stack.
10
+ */
11
+ readapt_stack_t *stack_alloc(size_t elem_size, void (*free_func)(void *))
12
+ {
13
+ readapt_stack_t *s = malloc(sizeof(readapt_stack_t));
14
+ s->elem_size = elem_size;
15
+ s->free_func = free_func;
16
+ s->size = 0;
17
+ s->capacity = 0;
18
+ return s;
19
+ }
20
+
21
+ /**
22
+ * Add an element to the end of the stack
23
+ */
24
+ void stack_push(readapt_stack_t *stack, void *element)
25
+ {
26
+ if (stack->size == stack->capacity)
27
+ {
28
+ if (stack->capacity == 0)
29
+ {
30
+ stack->capacity = STACK_CAPACITY;
31
+ stack->elements = malloc(stack->elem_size * stack->capacity);
32
+ }
33
+ else
34
+ {
35
+ stack->capacity += STACK_CAPACITY;
36
+ stack->elements = realloc(stack->elements, stack->elem_size * stack->capacity);
37
+ }
38
+ }
39
+ stack->elements[stack->size] = element;
40
+ stack->size++;
41
+ }
42
+
43
+ /**
44
+ * Get a pointer to the last element in the stack.
45
+ */
46
+ void *stack_peek(readapt_stack_t *stack)
47
+ {
48
+ return stack->size == 0 ? NULL : stack->elements[stack->size - 1];
49
+ }
50
+
51
+ /**
52
+ * Pop the last element off the stack and pass it to free_func.
53
+ */
54
+ void stack_pop(readapt_stack_t *stack)
55
+ {
56
+ void *e;
57
+
58
+ if (stack->size > 0)
59
+ {
60
+ e = stack->elements[stack->size - 1];
61
+ if (stack->free_func)
62
+ {
63
+ stack->free_func(e);
64
+ }
65
+ // stack->elements[stack->size - 1] = NULL;
66
+ stack->size--;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Free the stack from memory. If it still contains any elements, pass them to
72
+ * free_func.
73
+ */
74
+ void stack_free(readapt_stack_t *stack)
75
+ {
76
+ int i;
77
+
78
+ if (stack->free_func)
79
+ {
80
+ for (i = 0; i < stack->size; i++)
81
+ {
82
+ stack->free_func(stack->elements[i]);
83
+ }
84
+ }
85
+ free(stack);
86
+ }