ruby-debug-base19 0.11.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }