debugger 1.3.3 → 1.4.0

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