ruby-debug-base 0.10.4-java → 0.10.5.rc1-java

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