ruby-debug-base19 0.11.15

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