ruby-debug 0.7.5 → 0.8
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.
- data/CHANGES +5 -0
- data/bin/rdebug +9 -12
- data/cli/ruby-debug.rb +117 -0
- data/{lib → cli}/ruby-debug/command.rb +2 -13
- data/{lib → cli}/ruby-debug/commands/breakpoints.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/catchpoint.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/control.rb +2 -0
- data/{lib → cli}/ruby-debug/commands/display.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/eval.rb +1 -0
- data/{lib → cli}/ruby-debug/commands/frame.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/help.rb +1 -1
- data/{lib → cli}/ruby-debug/commands/irb.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/list.rb +2 -2
- data/{lib → cli}/ruby-debug/commands/method.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/script.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/settings.rb +4 -0
- data/{lib → cli}/ruby-debug/commands/stepping.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/threads.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/tmate.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/trace.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/variables.rb +0 -0
- data/{lib → cli}/ruby-debug/interface.rb +0 -0
- data/{lib → cli}/ruby-debug/processor.rb +4 -2
- metadata +43 -39
- data/Rakefile +0 -120
- data/ext/extconf.rb +0 -18
- data/ext/ruby_debug.c +0 -2167
- data/lib/ruby-debug.rb +0 -330
data/ext/extconf.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require "mkmf"
|
2
|
-
|
3
|
-
if RUBY_VERSION >= "1.9"
|
4
|
-
if RUBY_RELEASE_DATE < "2005-03-17"
|
5
|
-
STDERR.print("Ruby version is too old\n")
|
6
|
-
exit(1)
|
7
|
-
end
|
8
|
-
elsif RUBY_VERSION >= "1.8"
|
9
|
-
if RUBY_RELEASE_DATE < "2005-03-22"
|
10
|
-
STDERR.print("Ruby version is too old\n")
|
11
|
-
exit(1)
|
12
|
-
end
|
13
|
-
else
|
14
|
-
STDERR.print("Ruby version is too old\n")
|
15
|
-
exit(1)
|
16
|
-
end
|
17
|
-
|
18
|
-
create_makefile("ruby_debug")
|
data/ext/ruby_debug.c
DELETED
@@ -1,2167 +0,0 @@
|
|
1
|
-
#include <stdio.h>
|
2
|
-
#include <ruby.h>
|
3
|
-
#include <node.h>
|
4
|
-
#include <rubysig.h>
|
5
|
-
#include <st.h>
|
6
|
-
|
7
|
-
#define DEBUG_VERSION "0.7.5"
|
8
|
-
|
9
|
-
#ifdef _WIN32
|
10
|
-
struct FRAME {
|
11
|
-
VALUE self;
|
12
|
-
int argc;
|
13
|
-
ID last_func;
|
14
|
-
ID orig_func;
|
15
|
-
VALUE last_class;
|
16
|
-
struct FRAME *prev;
|
17
|
-
struct FRAME *tmp;
|
18
|
-
struct RNode *node;
|
19
|
-
int iter;
|
20
|
-
int flags;
|
21
|
-
unsigned long uniq;
|
22
|
-
};
|
23
|
-
|
24
|
-
struct SCOPE {
|
25
|
-
struct RBasic super;
|
26
|
-
ID *local_tbl;
|
27
|
-
VALUE *local_vars;
|
28
|
-
int flags;
|
29
|
-
};
|
30
|
-
|
31
|
-
struct RVarmap {
|
32
|
-
struct RBasic super;
|
33
|
-
ID id;
|
34
|
-
VALUE val;
|
35
|
-
struct RVarmap *next;
|
36
|
-
};
|
37
|
-
|
38
|
-
RUBY_EXTERN struct SCOPE *ruby_scope;
|
39
|
-
RUBY_EXTERN struct FRAME *ruby_frame;
|
40
|
-
RUBY_EXTERN struct RVarmap *ruby_dyna_vars;
|
41
|
-
#else
|
42
|
-
#include <env.h>
|
43
|
-
#endif
|
44
|
-
|
45
|
-
#define CTX_FL_MOVED (1<<1)
|
46
|
-
#define CTX_FL_SUSPEND (1<<2)
|
47
|
-
#define CTX_FL_TRACING (1<<3)
|
48
|
-
#define CTX_FL_SKIPPED (1<<4)
|
49
|
-
#define CTX_FL_IGNORE (1<<5)
|
50
|
-
#define CTX_FL_DEAD (1<<6)
|
51
|
-
#define CTX_FL_WAS_RUNNING (1<<7)
|
52
|
-
|
53
|
-
#define CTX_FL_TEST(c,f) ((c)->flags & (f))
|
54
|
-
#define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
|
55
|
-
#define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0)
|
56
|
-
|
57
|
-
#define DID_MOVED (debug_context->last_line != line || \
|
58
|
-
debug_context->last_file == NULL || \
|
59
|
-
strcmp(debug_context->last_file, file) != 0)
|
60
|
-
|
61
|
-
#define IS_STARTED (threads_tbl != Qnil)
|
62
|
-
#define FRAME_N(n) (&debug_context->frames[debug_context->stack_size-(n)-1])
|
63
|
-
#define GET_FRAME (FRAME_N(check_frame_number(debug_context, frame)))
|
64
|
-
|
65
|
-
#ifndef min
|
66
|
-
#define min(x,y) ((x) < (y) ? (x) : (y))
|
67
|
-
#endif
|
68
|
-
|
69
|
-
#define STACK_SIZE_INCREMENT 128
|
70
|
-
|
71
|
-
typedef struct {
|
72
|
-
VALUE binding;
|
73
|
-
ID id;
|
74
|
-
ID orig_id;
|
75
|
-
int line;
|
76
|
-
const char * file;
|
77
|
-
short dead;
|
78
|
-
VALUE self;
|
79
|
-
union {
|
80
|
-
struct {
|
81
|
-
struct FRAME *frame;
|
82
|
-
struct SCOPE *scope;
|
83
|
-
struct RVarmap *dyna_vars;
|
84
|
-
} runtime;
|
85
|
-
struct {
|
86
|
-
VALUE locals;
|
87
|
-
} copy;
|
88
|
-
} info;
|
89
|
-
} debug_frame_t;
|
90
|
-
|
91
|
-
typedef struct {
|
92
|
-
VALUE thread_id;
|
93
|
-
int thnum;
|
94
|
-
int flags;
|
95
|
-
int stop_next;
|
96
|
-
int dest_frame;
|
97
|
-
int stop_line;
|
98
|
-
int stop_frame;
|
99
|
-
int stack_size;
|
100
|
-
int stack_len;
|
101
|
-
debug_frame_t *frames;
|
102
|
-
const char * last_file;
|
103
|
-
int last_line;
|
104
|
-
} debug_context_t;
|
105
|
-
|
106
|
-
enum bp_type {BP_POS_TYPE, BP_METHOD_TYPE};
|
107
|
-
|
108
|
-
typedef struct {
|
109
|
-
int id;
|
110
|
-
int type;
|
111
|
-
VALUE source;
|
112
|
-
union
|
113
|
-
{
|
114
|
-
int line;
|
115
|
-
ID mid;
|
116
|
-
} pos;
|
117
|
-
VALUE expr;
|
118
|
-
} debug_breakpoint_t;
|
119
|
-
|
120
|
-
typedef struct {
|
121
|
-
st_table *tbl;
|
122
|
-
} threads_table_t;
|
123
|
-
|
124
|
-
static VALUE threads_tbl = Qnil;
|
125
|
-
static VALUE breakpoints = Qnil;
|
126
|
-
static VALUE catchpoint = Qnil;
|
127
|
-
static VALUE tracing = Qfalse;
|
128
|
-
static VALUE locker = Qnil;
|
129
|
-
static VALUE post_mortem = Qfalse;
|
130
|
-
static VALUE keep_frame_binding = Qfalse;
|
131
|
-
static VALUE debug = Qfalse;
|
132
|
-
|
133
|
-
static VALUE last_context = Qnil;
|
134
|
-
static VALUE last_thread = Qnil;
|
135
|
-
static debug_context_t *last_debug_context = NULL;
|
136
|
-
|
137
|
-
static VALUE mDebugger;
|
138
|
-
static VALUE cThreadsTable;
|
139
|
-
static VALUE cContext;
|
140
|
-
static VALUE cBreakpoint;
|
141
|
-
static VALUE cDebugThread;
|
142
|
-
|
143
|
-
static VALUE rb_mObjectSpace;
|
144
|
-
|
145
|
-
static ID idAtLine;
|
146
|
-
static ID idAtBreakpoint;
|
147
|
-
static ID idAtCatchpoint;
|
148
|
-
static ID idAtTracing;
|
149
|
-
static ID idEval;
|
150
|
-
static ID idList;
|
151
|
-
|
152
|
-
static int start_count = 0;
|
153
|
-
static int thnum_max = 0;
|
154
|
-
static int bkp_count = 0;
|
155
|
-
static int last_debugged_thnum = -1;
|
156
|
-
static unsigned long last_check = 0;
|
157
|
-
static unsigned long hook_count = 0;
|
158
|
-
|
159
|
-
static VALUE create_binding(VALUE);
|
160
|
-
static VALUE debug_stop(VALUE);
|
161
|
-
static void save_current_position(debug_context_t *);
|
162
|
-
static VALUE context_copy_locals(debug_frame_t *);
|
163
|
-
static void context_suspend_0(debug_context_t *);
|
164
|
-
static void context_resume_0(debug_context_t *);
|
165
|
-
|
166
|
-
typedef struct locked_thread_t {
|
167
|
-
VALUE thread_id;
|
168
|
-
struct locked_thread_t *next;
|
169
|
-
} locked_thread_t;
|
170
|
-
|
171
|
-
static locked_thread_t *locked_head = NULL;
|
172
|
-
static locked_thread_t *locked_tail = NULL;
|
173
|
-
|
174
|
-
inline static void *
|
175
|
-
ruby_method_ptr(VALUE class, ID meth_id)
|
176
|
-
{
|
177
|
-
NODE *body, *method;
|
178
|
-
st_lookup(RCLASS(class)->m_tbl, meth_id, (st_data_t *)&body);
|
179
|
-
method = (NODE *)body->u2.value;
|
180
|
-
return (void *)method->u1.value;
|
181
|
-
}
|
182
|
-
|
183
|
-
inline static VALUE
|
184
|
-
ref2id(VALUE obj)
|
185
|
-
{
|
186
|
-
return rb_obj_id(obj);
|
187
|
-
}
|
188
|
-
|
189
|
-
static VALUE
|
190
|
-
id2ref_unprotected(VALUE id)
|
191
|
-
{
|
192
|
-
typedef VALUE (*id2ref_func_t)(VALUE, VALUE);
|
193
|
-
static id2ref_func_t f_id2ref = NULL;
|
194
|
-
if(f_id2ref == NULL)
|
195
|
-
{
|
196
|
-
f_id2ref = (id2ref_func_t)ruby_method_ptr(rb_mObjectSpace, rb_intern("_id2ref"));
|
197
|
-
}
|
198
|
-
return f_id2ref(rb_mObjectSpace, id);
|
199
|
-
}
|
200
|
-
|
201
|
-
static VALUE
|
202
|
-
id2ref_error()
|
203
|
-
{
|
204
|
-
rb_p(ruby_errinfo);
|
205
|
-
return Qnil;
|
206
|
-
}
|
207
|
-
|
208
|
-
static VALUE
|
209
|
-
id2ref(VALUE id)
|
210
|
-
{
|
211
|
-
return rb_rescue(id2ref_unprotected, id, id2ref_error, 0);
|
212
|
-
}
|
213
|
-
|
214
|
-
inline static VALUE
|
215
|
-
context_thread_0(debug_context_t *debug_context)
|
216
|
-
{
|
217
|
-
return id2ref(debug_context->thread_id);
|
218
|
-
}
|
219
|
-
|
220
|
-
static int
|
221
|
-
is_in_locked(VALUE thread_id)
|
222
|
-
{
|
223
|
-
locked_thread_t *node;
|
224
|
-
|
225
|
-
if(!locked_head)
|
226
|
-
return 0;
|
227
|
-
|
228
|
-
for(node = locked_head; node != locked_tail; node = node->next)
|
229
|
-
{
|
230
|
-
if(node->thread_id == thread_id) return 1;
|
231
|
-
}
|
232
|
-
return 0;
|
233
|
-
}
|
234
|
-
|
235
|
-
static void
|
236
|
-
add_to_locked(VALUE thread)
|
237
|
-
{
|
238
|
-
locked_thread_t *node;
|
239
|
-
VALUE thread_id = ref2id(thread);
|
240
|
-
|
241
|
-
if(is_in_locked(thread_id))
|
242
|
-
return;
|
243
|
-
|
244
|
-
node = ALLOC(locked_thread_t);
|
245
|
-
node->thread_id = thread_id;
|
246
|
-
node->next = NULL;
|
247
|
-
if(locked_tail)
|
248
|
-
locked_tail->next = node;
|
249
|
-
locked_tail = node;
|
250
|
-
if(!locked_head)
|
251
|
-
locked_head = node;
|
252
|
-
}
|
253
|
-
|
254
|
-
static VALUE
|
255
|
-
remove_from_locked()
|
256
|
-
{
|
257
|
-
VALUE thread;
|
258
|
-
locked_thread_t *node;
|
259
|
-
|
260
|
-
if(locked_head == NULL)
|
261
|
-
return Qnil;
|
262
|
-
node = locked_head;
|
263
|
-
locked_head = locked_head->next;
|
264
|
-
if(locked_tail == node)
|
265
|
-
locked_tail = NULL;
|
266
|
-
thread = id2ref(node->thread_id);
|
267
|
-
xfree(node);
|
268
|
-
return thread;
|
269
|
-
}
|
270
|
-
|
271
|
-
static int
|
272
|
-
threads_table_mark_keyvalue(VALUE key, VALUE value, int dummy)
|
273
|
-
{
|
274
|
-
rb_gc_mark(value);
|
275
|
-
return ST_CONTINUE;
|
276
|
-
}
|
277
|
-
|
278
|
-
static void
|
279
|
-
threads_table_mark(void* data)
|
280
|
-
{
|
281
|
-
threads_table_t *threads_table = (threads_table_t*)data;
|
282
|
-
st_foreach(threads_table->tbl, threads_table_mark_keyvalue, 0);
|
283
|
-
}
|
284
|
-
|
285
|
-
static void
|
286
|
-
threads_table_free(void* data)
|
287
|
-
{
|
288
|
-
threads_table_t *threads_table = (threads_table_t*)data;
|
289
|
-
st_free_table(threads_table->tbl);
|
290
|
-
xfree(threads_table);
|
291
|
-
}
|
292
|
-
|
293
|
-
static VALUE
|
294
|
-
threads_table_create()
|
295
|
-
{
|
296
|
-
threads_table_t *threads_table;
|
297
|
-
|
298
|
-
threads_table = ALLOC(threads_table_t);
|
299
|
-
threads_table->tbl = st_init_numtable();
|
300
|
-
return Data_Wrap_Struct(cThreadsTable, threads_table_mark, threads_table_free, threads_table);
|
301
|
-
}
|
302
|
-
|
303
|
-
static int
|
304
|
-
threads_table_clear_i(VALUE key, VALUE value, VALUE dummy)
|
305
|
-
{
|
306
|
-
return ST_DELETE;
|
307
|
-
}
|
308
|
-
|
309
|
-
static void
|
310
|
-
threads_table_clear(VALUE table)
|
311
|
-
{
|
312
|
-
threads_table_t *threads_table;
|
313
|
-
|
314
|
-
Data_Get_Struct(table, threads_table_t, threads_table);
|
315
|
-
st_foreach(threads_table->tbl, threads_table_clear_i, 0);
|
316
|
-
}
|
317
|
-
|
318
|
-
static VALUE
|
319
|
-
is_thread_alive(VALUE thread)
|
320
|
-
{
|
321
|
-
typedef VALUE (*thread_alive_func_t)(VALUE);
|
322
|
-
static thread_alive_func_t f_thread_alive = NULL;
|
323
|
-
if(!f_thread_alive)
|
324
|
-
{
|
325
|
-
f_thread_alive = (thread_alive_func_t)ruby_method_ptr(rb_cThread, rb_intern("alive?"));
|
326
|
-
}
|
327
|
-
return f_thread_alive(thread);
|
328
|
-
}
|
329
|
-
|
330
|
-
static int
|
331
|
-
threads_table_check_i(VALUE key, VALUE value, VALUE dummy)
|
332
|
-
{
|
333
|
-
VALUE thread;
|
334
|
-
|
335
|
-
thread = id2ref(key);
|
336
|
-
if(!rb_obj_is_kind_of(thread, rb_cThread))
|
337
|
-
{
|
338
|
-
return ST_DELETE;
|
339
|
-
}
|
340
|
-
if(rb_protect(is_thread_alive, thread, 0) != Qtrue)
|
341
|
-
{
|
342
|
-
return ST_DELETE;
|
343
|
-
}
|
344
|
-
return ST_CONTINUE;
|
345
|
-
}
|
346
|
-
|
347
|
-
static void
|
348
|
-
check_thread_contexts()
|
349
|
-
{
|
350
|
-
threads_table_t *threads_table;
|
351
|
-
|
352
|
-
Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
|
353
|
-
st_foreach(threads_table->tbl, threads_table_check_i, 0);
|
354
|
-
}
|
355
|
-
|
356
|
-
/*
|
357
|
-
* call-seq:
|
358
|
-
* Debugger.started? -> bool
|
359
|
-
*
|
360
|
-
* Returns +true+ the debugger is started.
|
361
|
-
*/
|
362
|
-
static VALUE
|
363
|
-
debug_is_started(VALUE self)
|
364
|
-
{
|
365
|
-
return IS_STARTED ? Qtrue : Qfalse;
|
366
|
-
}
|
367
|
-
|
368
|
-
static void
|
369
|
-
debug_check_started()
|
370
|
-
{
|
371
|
-
if(!IS_STARTED)
|
372
|
-
{
|
373
|
-
rb_raise(rb_eRuntimeError, "Debugger.start is not called yet.");
|
374
|
-
}
|
375
|
-
}
|
376
|
-
|
377
|
-
static void
|
378
|
-
debug_context_mark(void *data)
|
379
|
-
{
|
380
|
-
debug_frame_t *frame;
|
381
|
-
int i;
|
382
|
-
|
383
|
-
debug_context_t *debug_context = (debug_context_t *)data;
|
384
|
-
for(i = 0; i < debug_context->stack_size; i++)
|
385
|
-
{
|
386
|
-
frame = &(debug_context->frames[i]);
|
387
|
-
rb_gc_mark(frame->binding);
|
388
|
-
rb_gc_mark(frame->self);
|
389
|
-
if(frame->dead)
|
390
|
-
{
|
391
|
-
rb_gc_mark(frame->info.copy.locals);
|
392
|
-
}
|
393
|
-
}
|
394
|
-
}
|
395
|
-
|
396
|
-
static void
|
397
|
-
debug_context_free(void *data)
|
398
|
-
{
|
399
|
-
debug_context_t *debug_context = (debug_context_t *)data;
|
400
|
-
xfree(debug_context->frames);
|
401
|
-
}
|
402
|
-
|
403
|
-
static VALUE
|
404
|
-
debug_context_create(VALUE thread)
|
405
|
-
{
|
406
|
-
debug_context_t *debug_context;
|
407
|
-
|
408
|
-
debug_context = ALLOC(debug_context_t);
|
409
|
-
debug_context-> thnum = ++thnum_max;
|
410
|
-
|
411
|
-
debug_context->last_file = NULL;
|
412
|
-
debug_context->last_line = 0;
|
413
|
-
debug_context->flags = 0;
|
414
|
-
|
415
|
-
debug_context->stop_next = -1;
|
416
|
-
debug_context->dest_frame = -1;
|
417
|
-
debug_context->stop_line = -1;
|
418
|
-
debug_context->stop_frame = -1;
|
419
|
-
debug_context->stack_len = STACK_SIZE_INCREMENT;
|
420
|
-
debug_context->frames = ALLOC_N(debug_frame_t, STACK_SIZE_INCREMENT);
|
421
|
-
debug_context->stack_size = 0;
|
422
|
-
debug_context->thread_id = ref2id(thread);
|
423
|
-
if(rb_obj_class(thread) == cDebugThread)
|
424
|
-
CTX_FL_SET(debug_context, CTX_FL_IGNORE);
|
425
|
-
return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, debug_context);
|
426
|
-
}
|
427
|
-
|
428
|
-
static VALUE
|
429
|
-
debug_context_dup(debug_context_t *debug_context)
|
430
|
-
{
|
431
|
-
debug_context_t *new_debug_context;
|
432
|
-
debug_frame_t *new_frame, *old_frame;
|
433
|
-
int i;
|
434
|
-
|
435
|
-
new_debug_context = ALLOC(debug_context_t);
|
436
|
-
memcpy(new_debug_context, debug_context, sizeof(debug_context_t));
|
437
|
-
new_debug_context->stop_next = -1;
|
438
|
-
new_debug_context->dest_frame = -1;
|
439
|
-
new_debug_context->stop_line = -1;
|
440
|
-
new_debug_context->stop_frame = -1;
|
441
|
-
CTX_FL_SET(new_debug_context, CTX_FL_DEAD);
|
442
|
-
new_debug_context->frames = ALLOC_N(debug_frame_t, debug_context->stack_size);
|
443
|
-
new_debug_context->stack_len = debug_context->stack_size;
|
444
|
-
memcpy(new_debug_context->frames, debug_context->frames, sizeof(debug_frame_t) * debug_context->stack_size);
|
445
|
-
for(i = 0; i < debug_context->stack_size; i++)
|
446
|
-
{
|
447
|
-
new_frame = &(new_debug_context->frames[i]);
|
448
|
-
old_frame = &(debug_context->frames[i]);
|
449
|
-
new_frame->dead = 1;
|
450
|
-
new_frame->info.copy.locals = context_copy_locals(old_frame);
|
451
|
-
}
|
452
|
-
return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, new_debug_context);
|
453
|
-
}
|
454
|
-
|
455
|
-
static void
|
456
|
-
thread_context_lookup(VALUE thread, VALUE *context, debug_context_t **debug_context)
|
457
|
-
{
|
458
|
-
threads_table_t *threads_table;
|
459
|
-
VALUE thread_id;
|
460
|
-
debug_context_t *l_debug_context;
|
461
|
-
|
462
|
-
debug_check_started();
|
463
|
-
|
464
|
-
if(last_thread == thread && last_context != Qnil)
|
465
|
-
{
|
466
|
-
*context = last_context;
|
467
|
-
if(debug_context)
|
468
|
-
*debug_context = last_debug_context;
|
469
|
-
return;
|
470
|
-
}
|
471
|
-
thread_id = ref2id(thread);
|
472
|
-
Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
|
473
|
-
if(!st_lookup(threads_table->tbl, thread_id, context))
|
474
|
-
{
|
475
|
-
*context = debug_context_create(thread);
|
476
|
-
st_insert(threads_table->tbl, thread_id, *context);
|
477
|
-
}
|
478
|
-
|
479
|
-
Data_Get_Struct(*context, debug_context_t, l_debug_context);
|
480
|
-
if(debug_context)
|
481
|
-
*debug_context = l_debug_context;
|
482
|
-
|
483
|
-
last_thread = thread;
|
484
|
-
last_context = *context;
|
485
|
-
last_debug_context = l_debug_context;
|
486
|
-
}
|
487
|
-
|
488
|
-
static VALUE
|
489
|
-
call_at_line_unprotected(VALUE args)
|
490
|
-
{
|
491
|
-
VALUE context;
|
492
|
-
context = *RARRAY(args)->ptr;
|
493
|
-
return rb_funcall2(context, idAtLine, RARRAY(args)->len - 1, RARRAY(args)->ptr + 1);
|
494
|
-
}
|
495
|
-
|
496
|
-
static VALUE
|
497
|
-
call_at_line(VALUE context, debug_context_t *debug_context, VALUE file, VALUE line)
|
498
|
-
{
|
499
|
-
VALUE args;
|
500
|
-
|
501
|
-
last_debugged_thnum = debug_context->thnum;
|
502
|
-
save_current_position(debug_context);
|
503
|
-
|
504
|
-
args = rb_ary_new3(3, context, file, line);
|
505
|
-
return rb_protect(call_at_line_unprotected, args, 0);
|
506
|
-
}
|
507
|
-
|
508
|
-
static void
|
509
|
-
save_call_frame(rb_event_t event, VALUE self, char *file, int line, ID mid, debug_context_t *debug_context)
|
510
|
-
{
|
511
|
-
VALUE binding;
|
512
|
-
debug_frame_t *debug_frame;
|
513
|
-
int frame_n;
|
514
|
-
|
515
|
-
binding = self && RTEST(keep_frame_binding)? create_binding(self) : Qnil;
|
516
|
-
|
517
|
-
frame_n = debug_context->stack_size++;
|
518
|
-
if(frame_n >= debug_context->stack_len)
|
519
|
-
{
|
520
|
-
debug_context->stack_len += STACK_SIZE_INCREMENT;
|
521
|
-
debug_context->frames = REALLOC_N(debug_context->frames, debug_frame_t, debug_context->stack_len);
|
522
|
-
}
|
523
|
-
debug_frame = &debug_context->frames[frame_n];
|
524
|
-
debug_frame->file = file;
|
525
|
-
debug_frame->line = line;
|
526
|
-
debug_frame->binding = binding;
|
527
|
-
debug_frame->id = mid;
|
528
|
-
debug_frame->orig_id = mid;
|
529
|
-
debug_frame->dead = 0;
|
530
|
-
debug_frame->self = self;
|
531
|
-
debug_frame->info.runtime.frame = ruby_frame;
|
532
|
-
debug_frame->info.runtime.scope = ruby_scope;
|
533
|
-
debug_frame->info.runtime.dyna_vars = event == RUBY_EVENT_LINE ? ruby_dyna_vars : NULL;
|
534
|
-
}
|
535
|
-
|
536
|
-
#if defined DOSISH
|
537
|
-
#define isdirsep(x) ((x) == '/' || (x) == '\\')
|
538
|
-
#else
|
539
|
-
#define isdirsep(x) ((x) == '/')
|
540
|
-
#endif
|
541
|
-
|
542
|
-
static int
|
543
|
-
filename_cmp(VALUE source, char *file)
|
544
|
-
{
|
545
|
-
char *source_ptr, *file_ptr;
|
546
|
-
int s_len, f_len, min_len;
|
547
|
-
int s,f;
|
548
|
-
int dirsep_flag = 0;
|
549
|
-
|
550
|
-
s_len = RSTRING(source)->len;
|
551
|
-
f_len = strlen(file);
|
552
|
-
min_len = min(s_len, f_len);
|
553
|
-
|
554
|
-
source_ptr = RSTRING(source)->ptr;
|
555
|
-
file_ptr = file;
|
556
|
-
|
557
|
-
for( s = s_len - 1, f = f_len - 1; s >= s_len - min_len && f >= f_len - min_len; s--, f-- )
|
558
|
-
{
|
559
|
-
if((source_ptr[s] == '.' || file_ptr[f] == '.') && dirsep_flag)
|
560
|
-
return 1;
|
561
|
-
if(source_ptr[s] != file_ptr[f])
|
562
|
-
return 0;
|
563
|
-
if(isdirsep(source_ptr[s]))
|
564
|
-
dirsep_flag = 1;
|
565
|
-
}
|
566
|
-
return 1;
|
567
|
-
}
|
568
|
-
|
569
|
-
static int
|
570
|
-
check_breakpoints_by_pos(debug_context_t *debug_context, char *file, int line)
|
571
|
-
{
|
572
|
-
VALUE breakpoint;
|
573
|
-
debug_breakpoint_t *debug_breakpoint;
|
574
|
-
int i;
|
575
|
-
|
576
|
-
if(RARRAY(breakpoints)->len == 0)
|
577
|
-
return -1;
|
578
|
-
if(!CTX_FL_TEST(debug_context, CTX_FL_MOVED))
|
579
|
-
return -1;
|
580
|
-
|
581
|
-
for(i = 0; i < RARRAY(breakpoints)->len; i++)
|
582
|
-
{
|
583
|
-
breakpoint = rb_ary_entry(breakpoints, i);
|
584
|
-
Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
|
585
|
-
if(debug_breakpoint->type != BP_POS_TYPE)
|
586
|
-
continue;
|
587
|
-
if(debug_breakpoint->pos.line != line)
|
588
|
-
continue;
|
589
|
-
if(filename_cmp(debug_breakpoint->source, file))
|
590
|
-
return i;
|
591
|
-
}
|
592
|
-
return -1;
|
593
|
-
}
|
594
|
-
|
595
|
-
inline static int
|
596
|
-
classname_cmp(VALUE name, VALUE klass)
|
597
|
-
{
|
598
|
-
return (klass != Qnil && rb_str_cmp(name, rb_mod_name(klass)) == 0);
|
599
|
-
}
|
600
|
-
|
601
|
-
static int
|
602
|
-
check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid)
|
603
|
-
{
|
604
|
-
VALUE breakpoint;
|
605
|
-
debug_breakpoint_t *debug_breakpoint;
|
606
|
-
int i;
|
607
|
-
|
608
|
-
if(RARRAY(breakpoints)->len == 0)
|
609
|
-
return -1;
|
610
|
-
if(!CTX_FL_TEST(debug_context, CTX_FL_MOVED))
|
611
|
-
return -1;
|
612
|
-
for(i = 0; i < RARRAY(breakpoints)->len; i++)
|
613
|
-
{
|
614
|
-
breakpoint = rb_ary_entry(breakpoints, i);
|
615
|
-
Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
|
616
|
-
if(debug_breakpoint->type != BP_METHOD_TYPE)
|
617
|
-
continue;
|
618
|
-
if(debug_breakpoint->pos.mid != mid)
|
619
|
-
continue;
|
620
|
-
if(classname_cmp(debug_breakpoint->source, klass))
|
621
|
-
return i;
|
622
|
-
}
|
623
|
-
return -1;
|
624
|
-
}
|
625
|
-
|
626
|
-
/*
|
627
|
-
* This is a NASTY HACK. For some reasons rb_f_binding is decalred
|
628
|
-
* static in eval.c
|
629
|
-
*/
|
630
|
-
static VALUE
|
631
|
-
create_binding(VALUE self)
|
632
|
-
{
|
633
|
-
typedef VALUE (*bind_func_t)(VALUE);
|
634
|
-
static bind_func_t f_binding = NULL;
|
635
|
-
|
636
|
-
if(f_binding == NULL)
|
637
|
-
{
|
638
|
-
f_binding = (bind_func_t)ruby_method_ptr(rb_mKernel, rb_intern("binding"));
|
639
|
-
}
|
640
|
-
return f_binding(self);
|
641
|
-
}
|
642
|
-
|
643
|
-
static VALUE
|
644
|
-
get_breakpoint_at(int index)
|
645
|
-
{
|
646
|
-
return rb_ary_entry(breakpoints, index);
|
647
|
-
}
|
648
|
-
|
649
|
-
static VALUE
|
650
|
-
eval_expression(VALUE args)
|
651
|
-
{
|
652
|
-
return rb_funcall2(rb_mKernel, idEval, 2, RARRAY(args)->ptr);
|
653
|
-
}
|
654
|
-
|
655
|
-
inline static int
|
656
|
-
check_breakpoint_expression(VALUE breakpoint, VALUE binding)
|
657
|
-
{
|
658
|
-
debug_breakpoint_t *debug_breakpoint;
|
659
|
-
VALUE args, expr_result;
|
660
|
-
|
661
|
-
Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
|
662
|
-
if(NIL_P(debug_breakpoint->expr))
|
663
|
-
return 1;
|
664
|
-
|
665
|
-
args = rb_ary_new3(2, debug_breakpoint->expr, binding);
|
666
|
-
expr_result = rb_protect(eval_expression, args, 0);
|
667
|
-
return RTEST(expr_result);
|
668
|
-
}
|
669
|
-
|
670
|
-
inline static debug_frame_t *
|
671
|
-
get_top_frame(debug_context_t *debug_context)
|
672
|
-
{
|
673
|
-
if(debug_context->stack_size == 0)
|
674
|
-
return NULL;
|
675
|
-
else
|
676
|
-
return &(debug_context->frames[debug_context->stack_size-1]);
|
677
|
-
}
|
678
|
-
|
679
|
-
inline static void
|
680
|
-
save_top_binding(debug_context_t *debug_context, VALUE binding)
|
681
|
-
{
|
682
|
-
debug_frame_t *debug_frame;
|
683
|
-
debug_frame = get_top_frame(debug_context);
|
684
|
-
if(debug_frame)
|
685
|
-
debug_frame->binding = binding;
|
686
|
-
}
|
687
|
-
|
688
|
-
inline static void
|
689
|
-
set_frame_source(rb_event_t event, debug_context_t *debug_context, VALUE self, char *file, int line, ID mid)
|
690
|
-
{
|
691
|
-
debug_frame_t *top_frame;
|
692
|
-
top_frame = get_top_frame(debug_context);
|
693
|
-
if(top_frame)
|
694
|
-
{
|
695
|
-
top_frame->self = self;
|
696
|
-
top_frame->file = file;
|
697
|
-
top_frame->line = line;
|
698
|
-
top_frame->id = mid;
|
699
|
-
top_frame->info.runtime.dyna_vars = event == RUBY_EVENT_C_CALL ? NULL : ruby_dyna_vars;
|
700
|
-
}
|
701
|
-
}
|
702
|
-
|
703
|
-
static void
|
704
|
-
save_current_position(debug_context_t *debug_context)
|
705
|
-
{
|
706
|
-
debug_frame_t *debug_frame;
|
707
|
-
|
708
|
-
debug_frame = get_top_frame(debug_context);
|
709
|
-
if(!debug_frame) return;
|
710
|
-
debug_context->last_file = debug_frame->file;
|
711
|
-
debug_context->last_line = debug_frame->line;
|
712
|
-
CTX_FL_UNSET(debug_context, CTX_FL_MOVED);
|
713
|
-
}
|
714
|
-
|
715
|
-
static char *
|
716
|
-
get_event_name(rb_event_t event)
|
717
|
-
{
|
718
|
-
switch (event) {
|
719
|
-
case RUBY_EVENT_LINE:
|
720
|
-
return "line";
|
721
|
-
case RUBY_EVENT_CLASS:
|
722
|
-
return "class";
|
723
|
-
case RUBY_EVENT_END:
|
724
|
-
return "end";
|
725
|
-
case RUBY_EVENT_CALL:
|
726
|
-
return "call";
|
727
|
-
case RUBY_EVENT_RETURN:
|
728
|
-
return "return";
|
729
|
-
case RUBY_EVENT_C_CALL:
|
730
|
-
return "c-call";
|
731
|
-
case RUBY_EVENT_C_RETURN:
|
732
|
-
return "c-return";
|
733
|
-
case RUBY_EVENT_RAISE:
|
734
|
-
return "raise";
|
735
|
-
default:
|
736
|
-
return "unknown";
|
737
|
-
}
|
738
|
-
}
|
739
|
-
|
740
|
-
|
741
|
-
static void
|
742
|
-
debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
743
|
-
{
|
744
|
-
VALUE thread, context, breakpoint;
|
745
|
-
VALUE binding = Qnil;
|
746
|
-
debug_context_t *debug_context;
|
747
|
-
char *file;
|
748
|
-
int line;
|
749
|
-
int breakpoint_index = -1;
|
750
|
-
|
751
|
-
hook_count++;
|
752
|
-
|
753
|
-
if (mid == ID_ALLOCATOR) return;
|
754
|
-
|
755
|
-
thread = rb_thread_current();
|
756
|
-
thread_context_lookup(thread, &context, &debug_context);
|
757
|
-
|
758
|
-
/* return if thread is marked as 'ignored'.
|
759
|
-
debugger's threads are marked this way
|
760
|
-
*/
|
761
|
-
if(CTX_FL_TEST(debug_context, CTX_FL_IGNORE)) return;
|
762
|
-
|
763
|
-
while(1)
|
764
|
-
{
|
765
|
-
/* halt execution of the current thread if the debugger
|
766
|
-
is activated in another
|
767
|
-
*/
|
768
|
-
while(locker != Qnil && locker != thread)
|
769
|
-
{
|
770
|
-
add_to_locked(thread);
|
771
|
-
rb_thread_stop();
|
772
|
-
}
|
773
|
-
|
774
|
-
/* stop the current thread if it's marked as suspended */
|
775
|
-
if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
|
776
|
-
{
|
777
|
-
CTX_FL_SET(debug_context, CTX_FL_WAS_RUNNING);
|
778
|
-
rb_thread_stop();
|
779
|
-
}
|
780
|
-
else break;
|
781
|
-
}
|
782
|
-
|
783
|
-
/* return if the current thread is the locker */
|
784
|
-
if(locker != Qnil) return;
|
785
|
-
|
786
|
-
/* only the current thread can proceed */
|
787
|
-
locker = thread;
|
788
|
-
|
789
|
-
/* ignore a skipped section of code */
|
790
|
-
if(CTX_FL_TEST(debug_context, CTX_FL_SKIPPED)) goto cleanup;
|
791
|
-
|
792
|
-
if(node)
|
793
|
-
{
|
794
|
-
file = node->nd_file;
|
795
|
-
line = nd_line(node);
|
796
|
-
|
797
|
-
if(debug == Qtrue)
|
798
|
-
fprintf(stderr, "%s:%d [%s] %s\n", file, line, get_event_name(event), rb_id2name(mid));
|
799
|
-
|
800
|
-
if(DID_MOVED)
|
801
|
-
CTX_FL_SET(debug_context, CTX_FL_MOVED);
|
802
|
-
}
|
803
|
-
else if(event != RUBY_EVENT_RETURN && event != RUBY_EVENT_C_RETURN)
|
804
|
-
{
|
805
|
-
if(debug == Qtrue)
|
806
|
-
fprintf(stderr, "return [%s] %s\n", get_event_name(event), rb_id2name(mid));
|
807
|
-
goto cleanup;
|
808
|
-
}
|
809
|
-
|
810
|
-
switch(event)
|
811
|
-
{
|
812
|
-
case RUBY_EVENT_LINE:
|
813
|
-
{
|
814
|
-
set_frame_source(event, debug_context, self, file, line, mid);
|
815
|
-
|
816
|
-
if(RTEST(tracing) || CTX_FL_TEST(debug_context, CTX_FL_TRACING))
|
817
|
-
rb_funcall(context, idAtTracing, 2, rb_str_new2(file), INT2FIX(line));
|
818
|
-
|
819
|
-
if(debug_context->dest_frame == -1 ||
|
820
|
-
debug_context->stack_size == debug_context->dest_frame)
|
821
|
-
{
|
822
|
-
debug_context->stop_next--;
|
823
|
-
if(debug_context->stop_next < 0)
|
824
|
-
debug_context->stop_next = -1;
|
825
|
-
/* we check that we actualy moved to another line */
|
826
|
-
if(DID_MOVED)
|
827
|
-
debug_context->stop_line--;
|
828
|
-
}
|
829
|
-
else if(debug_context->stack_size < debug_context->dest_frame)
|
830
|
-
{
|
831
|
-
debug_context->stop_next = 0;
|
832
|
-
}
|
833
|
-
|
834
|
-
if(debug_context->stack_size == 0)
|
835
|
-
save_call_frame(event, self, file, line, mid, debug_context);
|
836
|
-
|
837
|
-
if(debug_context->stop_next == 0 || debug_context->stop_line == 0 ||
|
838
|
-
(breakpoint_index = check_breakpoints_by_pos(debug_context, file, line)) != -1)
|
839
|
-
{
|
840
|
-
binding = self? create_binding(self) : Qnil;
|
841
|
-
/* check breakpoint expression */
|
842
|
-
if(breakpoint_index != -1)
|
843
|
-
{
|
844
|
-
breakpoint = get_breakpoint_at(breakpoint_index);
|
845
|
-
if(check_breakpoint_expression(breakpoint, binding))
|
846
|
-
rb_funcall(context, idAtBreakpoint, 1, breakpoint);
|
847
|
-
else
|
848
|
-
break;
|
849
|
-
}
|
850
|
-
|
851
|
-
/* reset all pointers */
|
852
|
-
debug_context->dest_frame = -1;
|
853
|
-
debug_context->stop_line = -1;
|
854
|
-
debug_context->stop_next = -1;
|
855
|
-
|
856
|
-
save_top_binding(debug_context, binding);
|
857
|
-
call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line));
|
858
|
-
}
|
859
|
-
break;
|
860
|
-
}
|
861
|
-
case RUBY_EVENT_C_CALL:
|
862
|
-
{
|
863
|
-
set_frame_source(event, debug_context, self, file, line, mid);
|
864
|
-
break;
|
865
|
-
}
|
866
|
-
case RUBY_EVENT_CALL:
|
867
|
-
{
|
868
|
-
save_call_frame(event, self, file, line, mid, debug_context);
|
869
|
-
breakpoint_index = check_breakpoints_by_method(debug_context, klass, mid);
|
870
|
-
if(breakpoint_index != -1)
|
871
|
-
{
|
872
|
-
debug_frame_t *debug_frame;
|
873
|
-
debug_frame = get_top_frame(debug_context);
|
874
|
-
if(debug_frame)
|
875
|
-
binding = debug_frame->binding;
|
876
|
-
if(NIL_P(binding) && self)
|
877
|
-
binding = create_binding(self);
|
878
|
-
breakpoint = get_breakpoint_at(breakpoint_index);
|
879
|
-
if(check_breakpoint_expression(breakpoint, binding))
|
880
|
-
{
|
881
|
-
save_top_binding(debug_context, binding);
|
882
|
-
rb_funcall(context, idAtBreakpoint, 1, breakpoint);
|
883
|
-
call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line));
|
884
|
-
}
|
885
|
-
}
|
886
|
-
break;
|
887
|
-
}
|
888
|
-
case RUBY_EVENT_RETURN:
|
889
|
-
case RUBY_EVENT_END:
|
890
|
-
{
|
891
|
-
if(debug_context->stack_size == debug_context->stop_frame)
|
892
|
-
{
|
893
|
-
debug_context->stop_next = 1;
|
894
|
-
debug_context->stop_frame = 0;
|
895
|
-
}
|
896
|
-
while(debug_context->stack_size > 0)
|
897
|
-
{
|
898
|
-
debug_context->stack_size--;
|
899
|
-
if(debug_context->frames[debug_context->stack_size].orig_id == mid)
|
900
|
-
break;
|
901
|
-
}
|
902
|
-
break;
|
903
|
-
}
|
904
|
-
case RUBY_EVENT_CLASS:
|
905
|
-
{
|
906
|
-
save_call_frame(event, self, file, line, mid, debug_context);
|
907
|
-
break;
|
908
|
-
}
|
909
|
-
case RUBY_EVENT_RAISE:
|
910
|
-
{
|
911
|
-
VALUE ancestors;
|
912
|
-
VALUE expn_class, aclass;
|
913
|
-
int i;
|
914
|
-
|
915
|
-
set_frame_source(event, debug_context, self, file, line, mid);
|
916
|
-
|
917
|
-
if(post_mortem == Qtrue && self)
|
918
|
-
{
|
919
|
-
binding = create_binding(self);
|
920
|
-
rb_ivar_set(ruby_errinfo, rb_intern("@__debug_file"), rb_str_new2(file));
|
921
|
-
rb_ivar_set(ruby_errinfo, rb_intern("@__debug_line"), INT2FIX(line));
|
922
|
-
rb_ivar_set(ruby_errinfo, rb_intern("@__debug_binding"), binding);
|
923
|
-
rb_ivar_set(ruby_errinfo, rb_intern("@__debug_context"), debug_context_dup(debug_context));
|
924
|
-
}
|
925
|
-
|
926
|
-
expn_class = rb_obj_class(ruby_errinfo);
|
927
|
-
if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) )
|
928
|
-
{
|
929
|
-
debug_stop(mDebugger);
|
930
|
-
break;
|
931
|
-
}
|
932
|
-
|
933
|
-
if(catchpoint == Qnil)
|
934
|
-
break;
|
935
|
-
|
936
|
-
ancestors = rb_mod_ancestors(expn_class);
|
937
|
-
for(i = 0; i < RARRAY(ancestors)->len; i++)
|
938
|
-
{
|
939
|
-
aclass = rb_ary_entry(ancestors, i);
|
940
|
-
if(rb_str_cmp(rb_mod_name(aclass), catchpoint) == 0)
|
941
|
-
{
|
942
|
-
rb_funcall(context, idAtCatchpoint, 1, ruby_errinfo);
|
943
|
-
if(self && binding == Qnil)
|
944
|
-
binding = create_binding(self);
|
945
|
-
save_top_binding(debug_context, binding);
|
946
|
-
call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line));
|
947
|
-
break;
|
948
|
-
}
|
949
|
-
}
|
950
|
-
|
951
|
-
break;
|
952
|
-
}
|
953
|
-
case RUBY_EVENT_C_RETURN:
|
954
|
-
{
|
955
|
-
break;
|
956
|
-
}
|
957
|
-
}
|
958
|
-
|
959
|
-
cleanup:
|
960
|
-
|
961
|
-
/* check that all contexts point to alive threads */
|
962
|
-
if(hook_count - last_check > 3000)
|
963
|
-
{
|
964
|
-
check_thread_contexts();
|
965
|
-
last_check = hook_count;
|
966
|
-
}
|
967
|
-
|
968
|
-
/* release a lock */
|
969
|
-
locker = Qnil;
|
970
|
-
/* let the next thread to run */
|
971
|
-
thread = remove_from_locked();
|
972
|
-
if(thread != Qnil)
|
973
|
-
rb_thread_run(thread);
|
974
|
-
}
|
975
|
-
|
976
|
-
static VALUE
|
977
|
-
debug_stop_i(VALUE self)
|
978
|
-
{
|
979
|
-
if(IS_STARTED)
|
980
|
-
debug_stop(self);
|
981
|
-
return Qnil;
|
982
|
-
}
|
983
|
-
|
984
|
-
/*
|
985
|
-
* call-seq:
|
986
|
-
* Debugger.start -> bool
|
987
|
-
* Debugger.start { ... } -> obj
|
988
|
-
*
|
989
|
-
* This method activates the debugger.
|
990
|
-
* If it's called without a block it returns +true+, unless debugger was already started.
|
991
|
-
* If a block is given, it starts debugger and yields to block. When the block is finished
|
992
|
-
* executing it stops the debugger with Debugger.stop method.
|
993
|
-
*
|
994
|
-
* <i>Note that if you want to stop debugger, you must call Debugger.stop as many time as you
|
995
|
-
* called Debugger.start method.</i>
|
996
|
-
*/
|
997
|
-
static VALUE
|
998
|
-
debug_start(VALUE self)
|
999
|
-
{
|
1000
|
-
VALUE result;
|
1001
|
-
start_count++;
|
1002
|
-
|
1003
|
-
if(IS_STARTED)
|
1004
|
-
result = Qfalse;
|
1005
|
-
else
|
1006
|
-
{
|
1007
|
-
breakpoints = rb_ary_new();
|
1008
|
-
locker = Qnil;
|
1009
|
-
threads_tbl = threads_table_create();
|
1010
|
-
|
1011
|
-
rb_add_event_hook(debug_event_hook, RUBY_EVENT_ALL);
|
1012
|
-
result = Qtrue;
|
1013
|
-
}
|
1014
|
-
|
1015
|
-
if(rb_block_given_p())
|
1016
|
-
return rb_ensure(rb_yield, self, debug_stop_i, self);
|
1017
|
-
return result;
|
1018
|
-
}
|
1019
|
-
|
1020
|
-
/*
|
1021
|
-
* call-seq:
|
1022
|
-
* Debugger.stop -> bool
|
1023
|
-
*
|
1024
|
-
* This method disacivates the debugger. It returns +true+ if the debugger is disacivated,
|
1025
|
-
* otherwise it returns +false+.
|
1026
|
-
*
|
1027
|
-
* <i>Note that if you want to stop debugger, you must call Debugger.stop as many time as you
|
1028
|
-
* called Debugger.start method.</i>
|
1029
|
-
*/
|
1030
|
-
static VALUE
|
1031
|
-
debug_stop(VALUE self)
|
1032
|
-
{
|
1033
|
-
debug_check_started();
|
1034
|
-
|
1035
|
-
start_count--;
|
1036
|
-
if(start_count)
|
1037
|
-
return Qfalse;
|
1038
|
-
|
1039
|
-
rb_remove_event_hook(debug_event_hook);
|
1040
|
-
|
1041
|
-
locker = Qnil;
|
1042
|
-
breakpoints = Qnil;
|
1043
|
-
threads_tbl = Qnil;
|
1044
|
-
|
1045
|
-
return Qtrue;
|
1046
|
-
}
|
1047
|
-
|
1048
|
-
static void
|
1049
|
-
breakpoint_mark(void *data)
|
1050
|
-
{
|
1051
|
-
debug_breakpoint_t *breakpoint;
|
1052
|
-
breakpoint = (debug_breakpoint_t *)data;
|
1053
|
-
rb_gc_mark(breakpoint->source);
|
1054
|
-
rb_gc_mark(breakpoint->expr);
|
1055
|
-
}
|
1056
|
-
|
1057
|
-
/*
|
1058
|
-
* call-seq:
|
1059
|
-
* Debugger.add_breakpoint(source, pos, condition = nil) -> breakpoint
|
1060
|
-
*
|
1061
|
-
* Adds a new breakpoint.
|
1062
|
-
* <i>source</i> is a name of a file or a class.
|
1063
|
-
* <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
|
1064
|
-
* <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
|
1065
|
-
* is activated.
|
1066
|
-
*/
|
1067
|
-
static VALUE
|
1068
|
-
debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
|
1069
|
-
{
|
1070
|
-
VALUE source, pos, expr;
|
1071
|
-
VALUE result;
|
1072
|
-
debug_breakpoint_t *breakpoint;
|
1073
|
-
int type;
|
1074
|
-
|
1075
|
-
debug_check_started();
|
1076
|
-
|
1077
|
-
if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2)
|
1078
|
-
{
|
1079
|
-
expr = Qnil;
|
1080
|
-
}
|
1081
|
-
type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE;
|
1082
|
-
if(type == BP_POS_TYPE)
|
1083
|
-
source = StringValue(source);
|
1084
|
-
else
|
1085
|
-
pos = StringValue(pos);
|
1086
|
-
breakpoint = ALLOC(debug_breakpoint_t);
|
1087
|
-
breakpoint->id = ++bkp_count;
|
1088
|
-
breakpoint->source = source;
|
1089
|
-
breakpoint->type = type;
|
1090
|
-
if(type == BP_POS_TYPE)
|
1091
|
-
breakpoint->pos.line = FIX2INT(pos);
|
1092
|
-
else
|
1093
|
-
breakpoint->pos.mid = rb_intern(RSTRING(pos)->ptr);
|
1094
|
-
breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
|
1095
|
-
result = Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
|
1096
|
-
rb_ary_push(breakpoints, result);
|
1097
|
-
return result;
|
1098
|
-
}
|
1099
|
-
|
1100
|
-
/*
|
1101
|
-
* call-seq:
|
1102
|
-
* Debugger.remove_breakpoint(id) -> breakpoint
|
1103
|
-
*
|
1104
|
-
* Removes breakpoint by its id.
|
1105
|
-
* <i>id</i> is an identificator of a breakpoint.
|
1106
|
-
*/
|
1107
|
-
static VALUE
|
1108
|
-
debug_remove_breakpoint(VALUE self, VALUE id_value)
|
1109
|
-
{
|
1110
|
-
int i;
|
1111
|
-
int id;
|
1112
|
-
VALUE breakpoint;
|
1113
|
-
debug_breakpoint_t *debug_breakpoint;
|
1114
|
-
|
1115
|
-
id = FIX2INT(id_value);
|
1116
|
-
|
1117
|
-
for( i = 0; i < RARRAY(breakpoints)->len; i += 1 )
|
1118
|
-
{
|
1119
|
-
breakpoint = rb_ary_entry(breakpoints, i);
|
1120
|
-
Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
|
1121
|
-
if(debug_breakpoint->id == id)
|
1122
|
-
{
|
1123
|
-
rb_ary_delete_at(breakpoints, i);
|
1124
|
-
return breakpoint;
|
1125
|
-
}
|
1126
|
-
}
|
1127
|
-
return Qnil;
|
1128
|
-
}
|
1129
|
-
|
1130
|
-
/*
|
1131
|
-
* call-seq:
|
1132
|
-
* Debugger.breakpoints -> array
|
1133
|
-
*
|
1134
|
-
* Returns an array of breakpoints.
|
1135
|
-
*/
|
1136
|
-
static VALUE
|
1137
|
-
debug_breakpoints(VALUE self)
|
1138
|
-
{
|
1139
|
-
debug_check_started();
|
1140
|
-
|
1141
|
-
return breakpoints;
|
1142
|
-
}
|
1143
|
-
|
1144
|
-
/*
|
1145
|
-
* call-seq:
|
1146
|
-
* Debugger.checkpoint -> string
|
1147
|
-
*
|
1148
|
-
* Returns a current checkpoint, which is a name of exception that will
|
1149
|
-
* trigger a debugger when raised.
|
1150
|
-
*/
|
1151
|
-
static VALUE
|
1152
|
-
debug_catchpoint(VALUE self)
|
1153
|
-
{
|
1154
|
-
debug_check_started();
|
1155
|
-
|
1156
|
-
return catchpoint;
|
1157
|
-
}
|
1158
|
-
|
1159
|
-
/*
|
1160
|
-
* call-seq:
|
1161
|
-
* Debugger.checkpoint = string -> string
|
1162
|
-
*
|
1163
|
-
* Sets checkpoint.
|
1164
|
-
*/
|
1165
|
-
static VALUE
|
1166
|
-
debug_set_catchpoint(VALUE self, VALUE value)
|
1167
|
-
{
|
1168
|
-
debug_check_started();
|
1169
|
-
|
1170
|
-
if (!NIL_P(value) && TYPE(value) != T_STRING) {
|
1171
|
-
rb_raise(rb_eTypeError, "value of checkpoint must be String");
|
1172
|
-
}
|
1173
|
-
if(NIL_P(value))
|
1174
|
-
catchpoint = Qnil;
|
1175
|
-
else
|
1176
|
-
catchpoint = rb_str_dup(value);
|
1177
|
-
return value;
|
1178
|
-
}
|
1179
|
-
|
1180
|
-
static int
|
1181
|
-
find_last_context_func(VALUE key, VALUE value, VALUE *result)
|
1182
|
-
{
|
1183
|
-
debug_context_t *debug_context;
|
1184
|
-
Data_Get_Struct(value, debug_context_t, debug_context);
|
1185
|
-
if(debug_context->thnum == last_debugged_thnum)
|
1186
|
-
{
|
1187
|
-
*result = value;
|
1188
|
-
return ST_STOP;
|
1189
|
-
}
|
1190
|
-
return ST_CONTINUE;
|
1191
|
-
}
|
1192
|
-
|
1193
|
-
/*
|
1194
|
-
* call-seq:
|
1195
|
-
* Debugger.last_interrupted -> context
|
1196
|
-
*
|
1197
|
-
* Returns last debugged context.
|
1198
|
-
*/
|
1199
|
-
static VALUE
|
1200
|
-
debug_last_interrupted(VALUE self)
|
1201
|
-
{
|
1202
|
-
VALUE result = Qnil;
|
1203
|
-
threads_table_t *threads_table;
|
1204
|
-
|
1205
|
-
debug_check_started();
|
1206
|
-
|
1207
|
-
Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
|
1208
|
-
|
1209
|
-
st_foreach(threads_table->tbl, find_last_context_func, (st_data_t)&result);
|
1210
|
-
return result;
|
1211
|
-
}
|
1212
|
-
|
1213
|
-
/*
|
1214
|
-
* call-seq:
|
1215
|
-
* Debugger.current_context -> context
|
1216
|
-
*
|
1217
|
-
* Returns current context.
|
1218
|
-
* <i>Note:</i> Debugger.current_context.thread == Thread.current
|
1219
|
-
*/
|
1220
|
-
static VALUE
|
1221
|
-
debug_current_context(VALUE self)
|
1222
|
-
{
|
1223
|
-
VALUE thread, context;
|
1224
|
-
|
1225
|
-
debug_check_started();
|
1226
|
-
|
1227
|
-
thread = rb_thread_current();
|
1228
|
-
thread_context_lookup(thread, &context, NULL);
|
1229
|
-
|
1230
|
-
return context;
|
1231
|
-
}
|
1232
|
-
|
1233
|
-
/*
|
1234
|
-
* call-seq:
|
1235
|
-
* Debugger.thread_context(thread) -> context
|
1236
|
-
*
|
1237
|
-
* Returns context of the thread passed as an argument.
|
1238
|
-
*/
|
1239
|
-
static VALUE
|
1240
|
-
debug_thread_context(VALUE self, VALUE thread)
|
1241
|
-
{
|
1242
|
-
VALUE context;
|
1243
|
-
|
1244
|
-
debug_check_started();
|
1245
|
-
thread_context_lookup(thread, &context, NULL);
|
1246
|
-
return context;
|
1247
|
-
}
|
1248
|
-
|
1249
|
-
/*
|
1250
|
-
* call-seq:
|
1251
|
-
* Debugger.contexts -> array
|
1252
|
-
*
|
1253
|
-
* Returns an array of all contexts.
|
1254
|
-
*/
|
1255
|
-
static VALUE
|
1256
|
-
debug_contexts(VALUE self)
|
1257
|
-
{
|
1258
|
-
volatile VALUE list;
|
1259
|
-
volatile VALUE new_list;
|
1260
|
-
VALUE thread, context;
|
1261
|
-
threads_table_t *threads_table;
|
1262
|
-
debug_context_t *debug_context;
|
1263
|
-
int i;
|
1264
|
-
|
1265
|
-
debug_check_started();
|
1266
|
-
|
1267
|
-
new_list = rb_ary_new();
|
1268
|
-
list = rb_funcall(rb_cThread, idList, 0);
|
1269
|
-
for(i = 0; i < RARRAY(list)->len; i++)
|
1270
|
-
{
|
1271
|
-
thread = rb_ary_entry(list, i);
|
1272
|
-
thread_context_lookup(thread, &context, NULL);
|
1273
|
-
rb_ary_push(new_list, context);
|
1274
|
-
}
|
1275
|
-
threads_table_clear(threads_tbl);
|
1276
|
-
Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
|
1277
|
-
for(i = 0; i < RARRAY(new_list)->len; i++)
|
1278
|
-
{
|
1279
|
-
context = rb_ary_entry(new_list, i);
|
1280
|
-
Data_Get_Struct(context, debug_context_t, debug_context);
|
1281
|
-
st_insert(threads_table->tbl, debug_context->thread_id, context);
|
1282
|
-
}
|
1283
|
-
|
1284
|
-
return new_list;
|
1285
|
-
}
|
1286
|
-
|
1287
|
-
/*
|
1288
|
-
* call-seq:
|
1289
|
-
* Debugger.suspend -> Debugger
|
1290
|
-
*
|
1291
|
-
* Suspends all contexts.
|
1292
|
-
*/
|
1293
|
-
static VALUE
|
1294
|
-
debug_suspend(VALUE self)
|
1295
|
-
{
|
1296
|
-
VALUE current, context;
|
1297
|
-
VALUE saved_crit;
|
1298
|
-
VALUE context_list;
|
1299
|
-
debug_context_t *debug_context;
|
1300
|
-
int i;
|
1301
|
-
|
1302
|
-
debug_check_started();
|
1303
|
-
|
1304
|
-
saved_crit = rb_thread_critical;
|
1305
|
-
rb_thread_critical = Qtrue;
|
1306
|
-
context_list = debug_contexts(self);
|
1307
|
-
thread_context_lookup(rb_thread_current(), ¤t, NULL);
|
1308
|
-
|
1309
|
-
for(i = 0; i < RARRAY(context_list)->len; i++)
|
1310
|
-
{
|
1311
|
-
context = rb_ary_entry(context_list, i);
|
1312
|
-
if(current == context)
|
1313
|
-
continue;
|
1314
|
-
Data_Get_Struct(context, debug_context_t, debug_context);
|
1315
|
-
context_suspend_0(debug_context);
|
1316
|
-
}
|
1317
|
-
rb_thread_critical = saved_crit;
|
1318
|
-
|
1319
|
-
if(rb_thread_critical == Qfalse)
|
1320
|
-
rb_thread_schedule();
|
1321
|
-
|
1322
|
-
return self;
|
1323
|
-
}
|
1324
|
-
|
1325
|
-
/*
|
1326
|
-
* call-seq:
|
1327
|
-
* Debugger.resume -> Debugger
|
1328
|
-
*
|
1329
|
-
* Resumes all contexts.
|
1330
|
-
*/
|
1331
|
-
static VALUE
|
1332
|
-
debug_resume(VALUE self)
|
1333
|
-
{
|
1334
|
-
VALUE current, context;
|
1335
|
-
VALUE saved_crit;
|
1336
|
-
VALUE context_list;
|
1337
|
-
debug_context_t *debug_context;
|
1338
|
-
int i;
|
1339
|
-
|
1340
|
-
debug_check_started();
|
1341
|
-
|
1342
|
-
saved_crit = rb_thread_critical;
|
1343
|
-
rb_thread_critical = Qtrue;
|
1344
|
-
context_list = debug_contexts(self);
|
1345
|
-
|
1346
|
-
thread_context_lookup(rb_thread_current(), ¤t, NULL);
|
1347
|
-
for(i = 0; i < RARRAY(context_list)->len; i++)
|
1348
|
-
{
|
1349
|
-
context = rb_ary_entry(context_list, i);
|
1350
|
-
if(current == context)
|
1351
|
-
continue;
|
1352
|
-
Data_Get_Struct(context, debug_context_t, debug_context);
|
1353
|
-
context_resume_0(debug_context);
|
1354
|
-
}
|
1355
|
-
rb_thread_critical = saved_crit;
|
1356
|
-
|
1357
|
-
rb_thread_schedule();
|
1358
|
-
|
1359
|
-
return self;
|
1360
|
-
}
|
1361
|
-
|
1362
|
-
/*
|
1363
|
-
* call-seq:
|
1364
|
-
* Debugger.tracing -> bool
|
1365
|
-
*
|
1366
|
-
* Returns +true+ if the global tracing is activated.
|
1367
|
-
*/
|
1368
|
-
static VALUE
|
1369
|
-
debug_tracing(VALUE self)
|
1370
|
-
{
|
1371
|
-
return tracing;
|
1372
|
-
}
|
1373
|
-
|
1374
|
-
/*
|
1375
|
-
* call-seq:
|
1376
|
-
* Debugger.tracing = bool
|
1377
|
-
*
|
1378
|
-
* Sets the global tracing flag.
|
1379
|
-
*/
|
1380
|
-
static VALUE
|
1381
|
-
debug_set_tracing(VALUE self, VALUE value)
|
1382
|
-
{
|
1383
|
-
tracing = RTEST(value) ? Qtrue : Qfalse;
|
1384
|
-
return value;
|
1385
|
-
}
|
1386
|
-
|
1387
|
-
/*
|
1388
|
-
* call-seq:
|
1389
|
-
* Debugger.post_mortem? -> bool
|
1390
|
-
*
|
1391
|
-
* Returns +true+ if post-moterm debugging is enabled.
|
1392
|
-
*/
|
1393
|
-
static VALUE
|
1394
|
-
debug_post_mortem(VALUE self)
|
1395
|
-
{
|
1396
|
-
return post_mortem;
|
1397
|
-
}
|
1398
|
-
|
1399
|
-
/*
|
1400
|
-
* call-seq:
|
1401
|
-
* Debugger.post_mortem = bool
|
1402
|
-
*
|
1403
|
-
* Sets post-moterm flag.
|
1404
|
-
* FOR INTERNAL USE ONLY.
|
1405
|
-
*/
|
1406
|
-
static VALUE
|
1407
|
-
debug_set_post_mortem(VALUE self, VALUE value)
|
1408
|
-
{
|
1409
|
-
debug_check_started();
|
1410
|
-
|
1411
|
-
post_mortem = RTEST(value) ? Qtrue : Qfalse;
|
1412
|
-
return value;
|
1413
|
-
}
|
1414
|
-
|
1415
|
-
/*
|
1416
|
-
* call-seq:
|
1417
|
-
* Debugger.keep_frame_binding? -> bool
|
1418
|
-
*
|
1419
|
-
* Returns +true+ if the debugger will collect frame bindings.
|
1420
|
-
*/
|
1421
|
-
static VALUE
|
1422
|
-
debug_keep_frame_binding(VALUE self)
|
1423
|
-
{
|
1424
|
-
return keep_frame_binding;
|
1425
|
-
}
|
1426
|
-
|
1427
|
-
/*
|
1428
|
-
* call-seq:
|
1429
|
-
* Debugger.keep_frame_binding = bool
|
1430
|
-
*
|
1431
|
-
* Setting to +true+ will make the debugger create frame bindings.
|
1432
|
-
*/
|
1433
|
-
static VALUE
|
1434
|
-
debug_set_keep_frame_binding(VALUE self, VALUE value)
|
1435
|
-
{
|
1436
|
-
keep_frame_binding = RTEST(value) ? Qtrue : Qfalse;
|
1437
|
-
return value;
|
1438
|
-
}
|
1439
|
-
|
1440
|
-
static VALUE
|
1441
|
-
debug_debug(VALUE self)
|
1442
|
-
{
|
1443
|
-
return debug;
|
1444
|
-
}
|
1445
|
-
|
1446
|
-
static VALUE
|
1447
|
-
debug_set_debug(VALUE self, VALUE value)
|
1448
|
-
{
|
1449
|
-
debug = RTEST(value) ? Qtrue : Qfalse;
|
1450
|
-
return value;
|
1451
|
-
}
|
1452
|
-
|
1453
|
-
static VALUE
|
1454
|
-
debug_thread_inherited(VALUE klass)
|
1455
|
-
{
|
1456
|
-
rb_raise(rb_eRuntimeError, "Can't inherite Debugger::DebugThread class");
|
1457
|
-
}
|
1458
|
-
|
1459
|
-
/*
|
1460
|
-
* call-seq:
|
1461
|
-
* Debugger.debug_load(file) -> nil
|
1462
|
-
*
|
1463
|
-
* Same as Kernel#load but resets current context's frames.
|
1464
|
-
* FOR INTERNAL USE ONLY. Use Debugger.post_mortem method instead.
|
1465
|
-
*/
|
1466
|
-
static VALUE
|
1467
|
-
debug_debug_load(VALUE self, VALUE file)
|
1468
|
-
{
|
1469
|
-
VALUE context;
|
1470
|
-
debug_context_t *debug_context;
|
1471
|
-
|
1472
|
-
debug_start(self);
|
1473
|
-
|
1474
|
-
context = debug_current_context(self);
|
1475
|
-
Data_Get_Struct(context, debug_context_t, debug_context);
|
1476
|
-
debug_context->stack_size = 0;
|
1477
|
-
rb_load(file, 0);
|
1478
|
-
|
1479
|
-
debug_stop(self);
|
1480
|
-
return Qnil;
|
1481
|
-
}
|
1482
|
-
|
1483
|
-
static VALUE
|
1484
|
-
set_current_skipped_status(VALUE status)
|
1485
|
-
{
|
1486
|
-
VALUE context;
|
1487
|
-
debug_context_t *debug_context;
|
1488
|
-
|
1489
|
-
context = debug_current_context(Qnil);
|
1490
|
-
Data_Get_Struct(context, debug_context_t, debug_context);
|
1491
|
-
if(status)
|
1492
|
-
CTX_FL_SET(debug_context, CTX_FL_SKIPPED);
|
1493
|
-
else
|
1494
|
-
CTX_FL_UNSET(debug_context, CTX_FL_SKIPPED);
|
1495
|
-
return Qnil;
|
1496
|
-
}
|
1497
|
-
|
1498
|
-
/*
|
1499
|
-
* call-seq:
|
1500
|
-
* Debugger.skip { block } -> obj or nil
|
1501
|
-
*
|
1502
|
-
* The code inside of the block is escaped from the debugger.
|
1503
|
-
*/
|
1504
|
-
static VALUE
|
1505
|
-
debug_skip(VALUE self)
|
1506
|
-
{
|
1507
|
-
if (!rb_block_given_p()) {
|
1508
|
-
rb_raise(rb_eArgError, "called without a block");
|
1509
|
-
}
|
1510
|
-
if(!IS_STARTED)
|
1511
|
-
return rb_yield(Qnil);
|
1512
|
-
set_current_skipped_status(Qtrue);
|
1513
|
-
return rb_ensure(rb_yield, Qnil, set_current_skipped_status, Qfalse);
|
1514
|
-
}
|
1515
|
-
|
1516
|
-
static VALUE
|
1517
|
-
debug_at_exit_c(VALUE proc)
|
1518
|
-
{
|
1519
|
-
return rb_funcall(proc, rb_intern("call"), 0);
|
1520
|
-
}
|
1521
|
-
|
1522
|
-
static void
|
1523
|
-
debug_at_exit_i(VALUE proc)
|
1524
|
-
{
|
1525
|
-
if(!IS_STARTED)
|
1526
|
-
{
|
1527
|
-
debug_at_exit_c(proc);
|
1528
|
-
}
|
1529
|
-
else
|
1530
|
-
{
|
1531
|
-
set_current_skipped_status(Qtrue);
|
1532
|
-
rb_ensure(debug_at_exit_c, proc, set_current_skipped_status, Qfalse);
|
1533
|
-
}
|
1534
|
-
}
|
1535
|
-
|
1536
|
-
/*
|
1537
|
-
* call-seq:
|
1538
|
-
* Debugger.debug_at_exit { block } -> proc
|
1539
|
-
*
|
1540
|
-
* Register <tt>at_exit</tt> hook which is escaped from the debugger.
|
1541
|
-
* FOR INTERNAL USE ONLY.
|
1542
|
-
*/
|
1543
|
-
static VALUE
|
1544
|
-
debug_at_exit(VALUE self)
|
1545
|
-
{
|
1546
|
-
VALUE proc;
|
1547
|
-
if (!rb_block_given_p()) {
|
1548
|
-
rb_raise(rb_eArgError, "called without a block");
|
1549
|
-
}
|
1550
|
-
proc = rb_block_proc();
|
1551
|
-
rb_set_end_proc(debug_at_exit_i, proc);
|
1552
|
-
return proc;
|
1553
|
-
}
|
1554
|
-
|
1555
|
-
/*
|
1556
|
-
* call-seq:
|
1557
|
-
* context.stop_next = steps
|
1558
|
-
*
|
1559
|
-
* Stops the current context after a number +steps+ are made.
|
1560
|
-
*/
|
1561
|
-
static VALUE
|
1562
|
-
context_stop_next(VALUE self, VALUE steps)
|
1563
|
-
{
|
1564
|
-
debug_context_t *debug_context;
|
1565
|
-
|
1566
|
-
debug_check_started();
|
1567
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1568
|
-
if(FIX2INT(steps) < 0)
|
1569
|
-
rb_raise(rb_eRuntimeError, "Steps argument can't be negative.");
|
1570
|
-
debug_context->stop_next = FIX2INT(steps);
|
1571
|
-
|
1572
|
-
return steps;
|
1573
|
-
}
|
1574
|
-
|
1575
|
-
/*
|
1576
|
-
* call-seq:
|
1577
|
-
* context.step_over(steps)
|
1578
|
-
*
|
1579
|
-
* Steps over a +steps+ number of times.
|
1580
|
-
*/
|
1581
|
-
static VALUE
|
1582
|
-
context_step_over(int argc, VALUE *argv, VALUE self)
|
1583
|
-
{
|
1584
|
-
VALUE lines, frame;
|
1585
|
-
debug_context_t *debug_context;
|
1586
|
-
|
1587
|
-
debug_check_started();
|
1588
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1589
|
-
if(debug_context->stack_size == 0)
|
1590
|
-
rb_raise(rb_eRuntimeError, "No frames collected.");
|
1591
|
-
|
1592
|
-
rb_scan_args(argc, argv, "11", &lines, &frame);
|
1593
|
-
debug_context->stop_line = FIX2INT(lines);
|
1594
|
-
if(argc == 1)
|
1595
|
-
{
|
1596
|
-
debug_context->dest_frame = debug_context->stack_size;
|
1597
|
-
}
|
1598
|
-
else
|
1599
|
-
{
|
1600
|
-
if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size)
|
1601
|
-
rb_raise(rb_eRuntimeError, "Destination frame is out of range.");
|
1602
|
-
debug_context->dest_frame = debug_context->stack_size - FIX2INT(frame);
|
1603
|
-
}
|
1604
|
-
|
1605
|
-
return Qnil;
|
1606
|
-
}
|
1607
|
-
|
1608
|
-
/*
|
1609
|
-
* call-seq:
|
1610
|
-
* context.stop_frame(frame)
|
1611
|
-
*
|
1612
|
-
* Stops when a frame with number +frame+ is activated. Implements +up+ and +down+ commands.
|
1613
|
-
*/
|
1614
|
-
static VALUE
|
1615
|
-
context_stop_frame(VALUE self, VALUE frame)
|
1616
|
-
{
|
1617
|
-
debug_context_t *debug_context;
|
1618
|
-
|
1619
|
-
debug_check_started();
|
1620
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1621
|
-
if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size)
|
1622
|
-
rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
|
1623
|
-
debug_context->stop_frame = debug_context->stack_size - FIX2INT(frame);
|
1624
|
-
|
1625
|
-
return frame;
|
1626
|
-
}
|
1627
|
-
|
1628
|
-
inline static int
|
1629
|
-
check_frame_number(debug_context_t *debug_context, VALUE frame)
|
1630
|
-
{
|
1631
|
-
int frame_n;
|
1632
|
-
|
1633
|
-
frame_n = FIX2INT(frame);
|
1634
|
-
if(frame_n < 0 || frame_n >= debug_context->stack_size)
|
1635
|
-
rb_raise(rb_eArgError, "Invalid frame number %d, stack (0...%d)",
|
1636
|
-
frame_n, debug_context->stack_size);
|
1637
|
-
return frame_n;
|
1638
|
-
}
|
1639
|
-
|
1640
|
-
/*
|
1641
|
-
* call-seq:
|
1642
|
-
* context.frame_binding(frame) -> binding
|
1643
|
-
*
|
1644
|
-
* Returns frame's binding.
|
1645
|
-
*/
|
1646
|
-
static VALUE
|
1647
|
-
context_frame_binding(VALUE self, VALUE frame)
|
1648
|
-
{
|
1649
|
-
debug_context_t *debug_context;
|
1650
|
-
|
1651
|
-
debug_check_started();
|
1652
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1653
|
-
return GET_FRAME->binding;
|
1654
|
-
}
|
1655
|
-
|
1656
|
-
/*
|
1657
|
-
* call-seq:
|
1658
|
-
* context.frame_id(frame) -> sym
|
1659
|
-
*
|
1660
|
-
* Returns the sym of the called method.
|
1661
|
-
*/
|
1662
|
-
static VALUE
|
1663
|
-
context_frame_id(VALUE self, VALUE frame)
|
1664
|
-
{
|
1665
|
-
|
1666
|
-
debug_context_t *debug_context;
|
1667
|
-
ID id;
|
1668
|
-
|
1669
|
-
debug_check_started();
|
1670
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1671
|
-
|
1672
|
-
id = GET_FRAME->id;
|
1673
|
-
return id ? ID2SYM(id): Qnil;
|
1674
|
-
}
|
1675
|
-
|
1676
|
-
/*
|
1677
|
-
* call-seq:
|
1678
|
-
* context.frame_line(frame) -> int
|
1679
|
-
*
|
1680
|
-
* Returns the line number in the file.
|
1681
|
-
*/
|
1682
|
-
static VALUE
|
1683
|
-
context_frame_line(VALUE self, VALUE frame)
|
1684
|
-
{
|
1685
|
-
debug_context_t *debug_context;
|
1686
|
-
|
1687
|
-
debug_check_started();
|
1688
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1689
|
-
|
1690
|
-
return INT2FIX(GET_FRAME->line);
|
1691
|
-
}
|
1692
|
-
|
1693
|
-
/*
|
1694
|
-
* call-seq:
|
1695
|
-
* context.frame_file(frame) -> string
|
1696
|
-
*
|
1697
|
-
* Returns the name of the file.
|
1698
|
-
*/
|
1699
|
-
static VALUE
|
1700
|
-
context_frame_file(VALUE self, VALUE frame)
|
1701
|
-
{
|
1702
|
-
debug_context_t *debug_context;
|
1703
|
-
|
1704
|
-
debug_check_started();
|
1705
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1706
|
-
|
1707
|
-
return rb_str_new2(GET_FRAME->file);
|
1708
|
-
}
|
1709
|
-
|
1710
|
-
static VALUE
|
1711
|
-
context_copy_locals(debug_frame_t *debug_frame)
|
1712
|
-
{
|
1713
|
-
ID *tbl;
|
1714
|
-
int n, i;
|
1715
|
-
struct SCOPE *scope;
|
1716
|
-
struct RVarmap *vars;
|
1717
|
-
VALUE hash = rb_hash_new();
|
1718
|
-
|
1719
|
-
scope = debug_frame->info.runtime.scope;
|
1720
|
-
tbl = scope->local_tbl;
|
1721
|
-
|
1722
|
-
if (tbl && scope->local_vars)
|
1723
|
-
{
|
1724
|
-
n = *tbl++;
|
1725
|
-
for (i=2; i<n; i++)
|
1726
|
-
{ /* skip first 2 ($_ and $~) */
|
1727
|
-
if (!rb_is_local_id(tbl[i])) continue; /* skip flip states */
|
1728
|
-
rb_hash_aset(hash, rb_str_new2(rb_id2name(tbl[i])), scope->local_vars[i]);
|
1729
|
-
}
|
1730
|
-
}
|
1731
|
-
|
1732
|
-
vars = debug_frame->info.runtime.dyna_vars;
|
1733
|
-
while (vars)
|
1734
|
-
{
|
1735
|
-
if (vars->id && rb_is_local_id(vars->id))
|
1736
|
-
{ /* skip $_, $~ and flip states */
|
1737
|
-
rb_hash_aset(hash, rb_str_new2(rb_id2name(vars->id)), vars->val);
|
1738
|
-
}
|
1739
|
-
vars = vars->next;
|
1740
|
-
}
|
1741
|
-
return hash;
|
1742
|
-
}
|
1743
|
-
|
1744
|
-
/*
|
1745
|
-
* call-seq:
|
1746
|
-
* context.frame_locals(frame) -> hash
|
1747
|
-
*
|
1748
|
-
* Returns frame's local variables.
|
1749
|
-
*/
|
1750
|
-
static VALUE
|
1751
|
-
context_frame_locals(VALUE self, VALUE frame)
|
1752
|
-
{
|
1753
|
-
debug_context_t *debug_context;
|
1754
|
-
debug_frame_t *debug_frame;
|
1755
|
-
|
1756
|
-
debug_check_started();
|
1757
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1758
|
-
|
1759
|
-
debug_frame = GET_FRAME;
|
1760
|
-
if(debug_frame->dead)
|
1761
|
-
return debug_frame->info.copy.locals;
|
1762
|
-
else
|
1763
|
-
return context_copy_locals(debug_frame);
|
1764
|
-
}
|
1765
|
-
|
1766
|
-
/*
|
1767
|
-
* call-seq:
|
1768
|
-
* context.frame_self(frame) -> obj
|
1769
|
-
*
|
1770
|
-
* Returns self object of the frame.
|
1771
|
-
*/
|
1772
|
-
static VALUE
|
1773
|
-
context_frame_self(VALUE self, VALUE frame)
|
1774
|
-
{
|
1775
|
-
debug_context_t *debug_context;
|
1776
|
-
debug_frame_t *debug_frame;
|
1777
|
-
|
1778
|
-
debug_check_started();
|
1779
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1780
|
-
|
1781
|
-
debug_frame = GET_FRAME;
|
1782
|
-
return debug_frame->self;
|
1783
|
-
}
|
1784
|
-
|
1785
|
-
/*
|
1786
|
-
* call-seq:
|
1787
|
-
* context.stack_size-> int
|
1788
|
-
*
|
1789
|
-
* Returns the size of the context stack.
|
1790
|
-
*/
|
1791
|
-
static VALUE
|
1792
|
-
context_stack_size(VALUE self)
|
1793
|
-
{
|
1794
|
-
debug_context_t *debug_context;
|
1795
|
-
|
1796
|
-
debug_check_started();
|
1797
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1798
|
-
|
1799
|
-
return INT2FIX(debug_context->stack_size);
|
1800
|
-
}
|
1801
|
-
|
1802
|
-
/*
|
1803
|
-
* call-seq:
|
1804
|
-
* context.thread -> trhread
|
1805
|
-
*
|
1806
|
-
* Returns a thread this context is associated with.
|
1807
|
-
*/
|
1808
|
-
static VALUE
|
1809
|
-
context_thread(VALUE self)
|
1810
|
-
{
|
1811
|
-
debug_context_t *debug_context;
|
1812
|
-
|
1813
|
-
debug_check_started();
|
1814
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1815
|
-
return context_thread_0(debug_context);
|
1816
|
-
}
|
1817
|
-
|
1818
|
-
/*
|
1819
|
-
* call-seq:
|
1820
|
-
* context.thnum -> int
|
1821
|
-
*
|
1822
|
-
* Returns the context's number.
|
1823
|
-
*/
|
1824
|
-
static VALUE
|
1825
|
-
context_thnum(VALUE self)
|
1826
|
-
{
|
1827
|
-
debug_context_t *debug_context;
|
1828
|
-
|
1829
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1830
|
-
return INT2FIX(debug_context->thnum);
|
1831
|
-
}
|
1832
|
-
|
1833
|
-
static void
|
1834
|
-
context_suspend_0(debug_context_t *debug_context)
|
1835
|
-
{
|
1836
|
-
VALUE status;
|
1837
|
-
|
1838
|
-
status = rb_funcall(context_thread_0(debug_context), rb_intern("status"), 0);
|
1839
|
-
if(rb_str_cmp(status, rb_str_new2("run")) == 0)
|
1840
|
-
CTX_FL_SET(debug_context, CTX_FL_WAS_RUNNING);
|
1841
|
-
else if(rb_str_cmp(status, rb_str_new2("sleep")) == 0)
|
1842
|
-
CTX_FL_UNSET(debug_context, CTX_FL_WAS_RUNNING);
|
1843
|
-
else
|
1844
|
-
return;
|
1845
|
-
CTX_FL_SET(debug_context, CTX_FL_SUSPEND);
|
1846
|
-
}
|
1847
|
-
|
1848
|
-
static void
|
1849
|
-
context_resume_0(debug_context_t *debug_context)
|
1850
|
-
{
|
1851
|
-
if(!CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
|
1852
|
-
return;
|
1853
|
-
CTX_FL_UNSET(debug_context, CTX_FL_SUSPEND);
|
1854
|
-
if(CTX_FL_TEST(debug_context, CTX_FL_WAS_RUNNING))
|
1855
|
-
rb_thread_wakeup(context_thread_0(debug_context));
|
1856
|
-
}
|
1857
|
-
|
1858
|
-
/*
|
1859
|
-
* call-seq:
|
1860
|
-
* context.suspend -> nil
|
1861
|
-
*
|
1862
|
-
* Suspends the thread when it is running.
|
1863
|
-
*/
|
1864
|
-
static VALUE
|
1865
|
-
context_suspend(VALUE self)
|
1866
|
-
{
|
1867
|
-
debug_context_t *debug_context;
|
1868
|
-
|
1869
|
-
debug_check_started();
|
1870
|
-
|
1871
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1872
|
-
if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
|
1873
|
-
rb_raise(rb_eRuntimeError, "Already suspended.");
|
1874
|
-
context_suspend_0(debug_context);
|
1875
|
-
return Qnil;
|
1876
|
-
}
|
1877
|
-
|
1878
|
-
/*
|
1879
|
-
* call-seq:
|
1880
|
-
* context.suspended? -> bool
|
1881
|
-
*
|
1882
|
-
* Returns +true+ if the thread is suspended by debugger.
|
1883
|
-
*/
|
1884
|
-
static VALUE
|
1885
|
-
context_is_suspended(VALUE self)
|
1886
|
-
{
|
1887
|
-
debug_context_t *debug_context;
|
1888
|
-
|
1889
|
-
debug_check_started();
|
1890
|
-
|
1891
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1892
|
-
return CTX_FL_TEST(debug_context, CTX_FL_SUSPEND) ? Qtrue : Qfalse;
|
1893
|
-
}
|
1894
|
-
|
1895
|
-
/*
|
1896
|
-
* call-seq:
|
1897
|
-
* context.resume -> nil
|
1898
|
-
*
|
1899
|
-
* Resumes the thread from the suspended mode.
|
1900
|
-
*/
|
1901
|
-
static VALUE
|
1902
|
-
context_resume(VALUE self)
|
1903
|
-
{
|
1904
|
-
debug_context_t *debug_context;
|
1905
|
-
|
1906
|
-
debug_check_started();
|
1907
|
-
|
1908
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1909
|
-
if(!CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
|
1910
|
-
rb_raise(rb_eRuntimeError, "Thread is not suspended.");
|
1911
|
-
context_resume_0(debug_context);
|
1912
|
-
return Qnil;
|
1913
|
-
}
|
1914
|
-
|
1915
|
-
/*
|
1916
|
-
* call-seq:
|
1917
|
-
* context.tracing -> bool
|
1918
|
-
*
|
1919
|
-
* Returns the tracing flag for the current context.
|
1920
|
-
*/
|
1921
|
-
static VALUE
|
1922
|
-
context_tracing(VALUE self)
|
1923
|
-
{
|
1924
|
-
debug_context_t *debug_context;
|
1925
|
-
|
1926
|
-
debug_check_started();
|
1927
|
-
|
1928
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1929
|
-
return CTX_FL_TEST(debug_context, CTX_FL_TRACING) ? Qtrue : Qfalse;
|
1930
|
-
}
|
1931
|
-
|
1932
|
-
/*
|
1933
|
-
* call-seq:
|
1934
|
-
* context.tracking = bool
|
1935
|
-
*
|
1936
|
-
* Controls the tracing for this context.
|
1937
|
-
*/
|
1938
|
-
static VALUE
|
1939
|
-
context_set_tracing(VALUE self, VALUE value)
|
1940
|
-
{
|
1941
|
-
debug_context_t *debug_context;
|
1942
|
-
|
1943
|
-
debug_check_started();
|
1944
|
-
|
1945
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1946
|
-
if(RTEST(value))
|
1947
|
-
CTX_FL_SET(debug_context, CTX_FL_TRACING);
|
1948
|
-
else
|
1949
|
-
CTX_FL_UNSET(debug_context, CTX_FL_TRACING);
|
1950
|
-
return value;
|
1951
|
-
}
|
1952
|
-
|
1953
|
-
/*
|
1954
|
-
* call-seq:
|
1955
|
-
* context.ignored? -> bool
|
1956
|
-
*
|
1957
|
-
* Returns the ignore flag for the current context.
|
1958
|
-
*/
|
1959
|
-
static VALUE
|
1960
|
-
context_ignored(VALUE self)
|
1961
|
-
{
|
1962
|
-
debug_context_t *debug_context;
|
1963
|
-
|
1964
|
-
debug_check_started();
|
1965
|
-
|
1966
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1967
|
-
return CTX_FL_TEST(debug_context, CTX_FL_IGNORE) ? Qtrue : Qfalse;
|
1968
|
-
}
|
1969
|
-
|
1970
|
-
/*
|
1971
|
-
* call-seq:
|
1972
|
-
* context.dead? = bool
|
1973
|
-
*
|
1974
|
-
* Returns +true+ if context doesn't represent a live context and is created
|
1975
|
-
* during post-mortem exception handling.
|
1976
|
-
*/
|
1977
|
-
static VALUE
|
1978
|
-
context_dead(VALUE self)
|
1979
|
-
{
|
1980
|
-
debug_context_t *debug_context;
|
1981
|
-
|
1982
|
-
debug_check_started();
|
1983
|
-
|
1984
|
-
Data_Get_Struct(self, debug_context_t, debug_context);
|
1985
|
-
return CTX_FL_TEST(debug_context, CTX_FL_DEAD) ? Qtrue : Qfalse;
|
1986
|
-
}
|
1987
|
-
|
1988
|
-
/*
|
1989
|
-
* call-seq:
|
1990
|
-
* breakpoint.source -> string
|
1991
|
-
*
|
1992
|
-
* Returns a source of the breakpoint.
|
1993
|
-
*/
|
1994
|
-
static VALUE
|
1995
|
-
breakpoint_source(VALUE self)
|
1996
|
-
{
|
1997
|
-
debug_breakpoint_t *breakpoint;
|
1998
|
-
|
1999
|
-
Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
|
2000
|
-
return breakpoint->source;
|
2001
|
-
}
|
2002
|
-
|
2003
|
-
/*
|
2004
|
-
* call-seq:
|
2005
|
-
* breakpoint.pos -> string or int
|
2006
|
-
*
|
2007
|
-
* Returns a position of this breakpoint.
|
2008
|
-
*/
|
2009
|
-
static VALUE
|
2010
|
-
breakpoint_pos(VALUE self)
|
2011
|
-
{
|
2012
|
-
debug_breakpoint_t *breakpoint;
|
2013
|
-
|
2014
|
-
Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
|
2015
|
-
if(breakpoint->type == BP_METHOD_TYPE)
|
2016
|
-
return rb_str_new2(rb_id2name(breakpoint->pos.mid));
|
2017
|
-
else
|
2018
|
-
return INT2FIX(breakpoint->pos.line);
|
2019
|
-
}
|
2020
|
-
|
2021
|
-
/*
|
2022
|
-
* call-seq:
|
2023
|
-
* breakpoint.expr -> string
|
2024
|
-
*
|
2025
|
-
* Returns a codition expression when this breakpoint should be activated.
|
2026
|
-
*/
|
2027
|
-
static VALUE
|
2028
|
-
breakpoint_expr(VALUE self)
|
2029
|
-
{
|
2030
|
-
debug_breakpoint_t *breakpoint;
|
2031
|
-
|
2032
|
-
Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
|
2033
|
-
return breakpoint->expr;
|
2034
|
-
}
|
2035
|
-
|
2036
|
-
/*
|
2037
|
-
* call-seq:
|
2038
|
-
* breakpoint.id -> int
|
2039
|
-
*
|
2040
|
-
* Returns id of the breakpoint.
|
2041
|
-
*/
|
2042
|
-
static VALUE
|
2043
|
-
breakpoint_id(VALUE self)
|
2044
|
-
{
|
2045
|
-
debug_breakpoint_t *breakpoint;
|
2046
|
-
|
2047
|
-
Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
|
2048
|
-
return INT2FIX(breakpoint->id);
|
2049
|
-
}
|
2050
|
-
|
2051
|
-
/*
|
2052
|
-
* Document-class: Context
|
2053
|
-
*
|
2054
|
-
* == Summary
|
2055
|
-
*
|
2056
|
-
* Debugger keeps a single instance of this class for each Ruby thread.
|
2057
|
-
*/
|
2058
|
-
static void
|
2059
|
-
Init_context()
|
2060
|
-
{
|
2061
|
-
cContext = rb_define_class_under(mDebugger, "Context", rb_cObject);
|
2062
|
-
rb_define_method(cContext, "stop_next=", context_stop_next, 1);
|
2063
|
-
rb_define_method(cContext, "step_over", context_step_over, -1);
|
2064
|
-
rb_define_method(cContext, "stop_frame=", context_stop_frame, 1);
|
2065
|
-
rb_define_method(cContext, "thread", context_thread, 0);
|
2066
|
-
rb_define_method(cContext, "thnum", context_thnum, 0);
|
2067
|
-
rb_define_method(cContext, "suspend", context_suspend, 0);
|
2068
|
-
rb_define_method(cContext, "suspended?", context_is_suspended, 0);
|
2069
|
-
rb_define_method(cContext, "resume", context_resume, 0);
|
2070
|
-
rb_define_method(cContext, "tracing", context_tracing, 0);
|
2071
|
-
rb_define_method(cContext, "tracing=", context_set_tracing, 1);
|
2072
|
-
rb_define_method(cContext, "ignored?", context_ignored, 0);
|
2073
|
-
rb_define_method(cContext, "frame_binding", context_frame_binding, 1);
|
2074
|
-
rb_define_method(cContext, "frame_id", context_frame_id, 1);
|
2075
|
-
rb_define_method(cContext, "frame_line", context_frame_line, 1);
|
2076
|
-
rb_define_method(cContext, "frame_file", context_frame_file, 1);
|
2077
|
-
rb_define_method(cContext, "frame_locals", context_frame_locals, 1);
|
2078
|
-
rb_define_method(cContext, "frame_self", context_frame_self, 1);
|
2079
|
-
rb_define_method(cContext, "stack_size", context_stack_size, 0);
|
2080
|
-
rb_define_method(cContext, "dead?", context_dead, 0);
|
2081
|
-
}
|
2082
|
-
|
2083
|
-
/*
|
2084
|
-
* Document-class: Breakpoint
|
2085
|
-
*
|
2086
|
-
* == Summary
|
2087
|
-
*
|
2088
|
-
* This class represents a breakpoint. It defines position of the breakpoint and
|
2089
|
-
* condition when this breakpoint should be triggered.
|
2090
|
-
*/
|
2091
|
-
static void
|
2092
|
-
Init_breakpoint()
|
2093
|
-
{
|
2094
|
-
cBreakpoint = rb_define_class_under(mDebugger, "Breakpoint", rb_cObject);
|
2095
|
-
rb_define_method(cBreakpoint, "source", breakpoint_source, 0);
|
2096
|
-
rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0);
|
2097
|
-
rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0);
|
2098
|
-
rb_define_method(cBreakpoint, "id", breakpoint_id, 0);
|
2099
|
-
}
|
2100
|
-
|
2101
|
-
|
2102
|
-
/*
|
2103
|
-
* Document-class: Debugger
|
2104
|
-
*
|
2105
|
-
* == Summary
|
2106
|
-
*
|
2107
|
-
* This is a singleton class allows controlling the debugger. Use it to start/stop debugger,
|
2108
|
-
* set/remove breakpoints, etc.
|
2109
|
-
*/
|
2110
|
-
#if defined(_WIN32)
|
2111
|
-
__declspec(dllexport)
|
2112
|
-
#endif
|
2113
|
-
void
|
2114
|
-
Init_ruby_debug()
|
2115
|
-
{
|
2116
|
-
mDebugger = rb_define_module("Debugger");
|
2117
|
-
rb_define_const(mDebugger, "VERSION", rb_str_new2(DEBUG_VERSION));
|
2118
|
-
rb_define_module_function(mDebugger, "start", debug_start, 0);
|
2119
|
-
rb_define_module_function(mDebugger, "stop", debug_stop, 0);
|
2120
|
-
rb_define_module_function(mDebugger, "started?", debug_is_started, 0);
|
2121
|
-
rb_define_module_function(mDebugger, "breakpoints", debug_breakpoints, 0);
|
2122
|
-
rb_define_module_function(mDebugger, "add_breakpoint", debug_add_breakpoint, -1);
|
2123
|
-
rb_define_module_function(mDebugger, "remove_breakpoint", debug_remove_breakpoint, 1);
|
2124
|
-
rb_define_module_function(mDebugger, "catchpoint", debug_catchpoint, 0);
|
2125
|
-
rb_define_module_function(mDebugger, "catchpoint=", debug_set_catchpoint, 1);
|
2126
|
-
rb_define_module_function(mDebugger, "last_context", debug_last_interrupted, 0);
|
2127
|
-
rb_define_module_function(mDebugger, "contexts", debug_contexts, 0);
|
2128
|
-
rb_define_module_function(mDebugger, "current_context", debug_current_context, 0);
|
2129
|
-
rb_define_module_function(mDebugger, "thread_context", debug_thread_context, 1);
|
2130
|
-
rb_define_module_function(mDebugger, "suspend", debug_suspend, 0);
|
2131
|
-
rb_define_module_function(mDebugger, "resume", debug_resume, 0);
|
2132
|
-
rb_define_module_function(mDebugger, "tracing", debug_tracing, 0);
|
2133
|
-
rb_define_module_function(mDebugger, "tracing=", debug_set_tracing, 1);
|
2134
|
-
rb_define_module_function(mDebugger, "debug_load", debug_debug_load, 1);
|
2135
|
-
rb_define_module_function(mDebugger, "skip", debug_skip, 0);
|
2136
|
-
rb_define_module_function(mDebugger, "debug_at_exit", debug_at_exit, 0);
|
2137
|
-
rb_define_module_function(mDebugger, "post_mortem?", debug_post_mortem, 0);
|
2138
|
-
rb_define_module_function(mDebugger, "post_mortem=", debug_set_post_mortem, 1);
|
2139
|
-
rb_define_module_function(mDebugger, "keep_frame_binding?", debug_keep_frame_binding, 0);
|
2140
|
-
rb_define_module_function(mDebugger, "keep_frame_binding=", debug_set_keep_frame_binding, 1);
|
2141
|
-
rb_define_module_function(mDebugger, "debug", debug_debug, 0);
|
2142
|
-
rb_define_module_function(mDebugger, "debug=", debug_set_debug, 1);
|
2143
|
-
|
2144
|
-
cThreadsTable = rb_define_class_under(mDebugger, "ThreadsTable", rb_cObject);
|
2145
|
-
|
2146
|
-
cDebugThread = rb_define_class_under(mDebugger, "DebugThread", rb_cThread);
|
2147
|
-
rb_define_singleton_method(cDebugThread, "inherited", debug_thread_inherited, 1);
|
2148
|
-
|
2149
|
-
Init_context();
|
2150
|
-
Init_breakpoint();
|
2151
|
-
|
2152
|
-
idAtLine = rb_intern("at_line");
|
2153
|
-
idAtBreakpoint = rb_intern("at_breakpoint");
|
2154
|
-
idAtCatchpoint = rb_intern("at_catchpoint");
|
2155
|
-
idAtTracing = rb_intern("at_tracing");
|
2156
|
-
idEval = rb_intern("eval");
|
2157
|
-
idList = rb_intern("list");
|
2158
|
-
|
2159
|
-
rb_mObjectSpace = rb_const_get(rb_mKernel, rb_intern("ObjectSpace"));
|
2160
|
-
|
2161
|
-
rb_global_variable(&threads_tbl);
|
2162
|
-
rb_global_variable(&breakpoints);
|
2163
|
-
rb_global_variable(&catchpoint);
|
2164
|
-
rb_global_variable(&locker);
|
2165
|
-
rb_global_variable(&last_context);
|
2166
|
-
rb_global_variable(&last_thread);
|
2167
|
-
}
|