Module: Debugger

Defined in:
ext/ruby_debug.c

Constant Summary collapse

VERSION =
rb_str_new2(DEBUG_VERSION)

Class Method Summary collapse

Class Method Details

.add_breakpoint(source, pos, condition = nil) ⇒ Object

Adds a new breakpoint. source is a name of a file or a class. pos is a line number or a method name if source is a class name. condition is a string which is evaluated to true when this breakpoint is activated.



674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
# File 'ext/ruby_debug.c', line 674

static VALUE
debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
{
    VALUE source, pos, expr;
    VALUE result;
    debug_breakpoint_t *breakpoint;

    debug_check_started();
    
    if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2)
    {
        expr = Qnil;
    }

    breakpoint = ALLOC(debug_breakpoint_t);
    breakpoint->source = StringValue(source);
    breakpoint->pos = pos;
    breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
    result = Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
    rb_ary_push(breakpoints, result);
    return result;
}

.breakpointsArray

Returns an array of breakpoints.

Returns:

  • (Array)


703
704
705
706
707
708
709
# File 'ext/ruby_debug.c', line 703

static VALUE
debug_breakpoints(VALUE self)
{
    debug_check_started();

    return breakpoints;
}

.checkpointString

Returns a current checkpoint, which is a name of exception that will trigger a debugger when raised.

Returns:

  • (String)


718
719
720
721
722
723
724
# File 'ext/ruby_debug.c', line 718

static VALUE
debug_catchpoint(VALUE self)
{
    debug_check_started();

    return catchpoint;
}

.checkpoint=(string) ⇒ String

Sets checkpoint.

Returns:

  • (String)


732
733
734
735
736
737
738
739
740
741
742
743
744
745
# File 'ext/ruby_debug.c', line 732

static VALUE
debug_set_catchpoint(VALUE self, VALUE value)
{
    debug_check_started();

    if (!NIL_P(value) && TYPE(value) != T_STRING) {
        rb_raise(rb_eTypeError, "value of checkpoint must be String");
    }
    if(NIL_P(value))
    catchpoint = Qnil;
    else
    catchpoint = rb_str_dup(value);
    return value;
}

.contextsArray

Returns an array of all contexts.

Returns:

  • (Array)


803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
# File 'ext/ruby_debug.c', line 803

static VALUE
debug_contexts(VALUE self)
{
    volatile VALUE list;
    volatile VALUE new_list;
    VALUE thread, context;
    debug_context_t *debug_context;
    int i;

    debug_check_started();

    new_list = rb_ary_new();
    list = rb_funcall(rb_cThread, idList, 0);
    for(i = 0; i < RARRAY(list)->len; i++)
    {
        thread = rb_ary_entry(list, i);
        context = thread_context_lookup(thread);
        rb_ary_push(new_list, context);
    }
    /*
     * I wonder why rb_hash_clear is declared static?
     */
    rb_funcall(threads_tbl, idClear, 0);
    for(i = 0; i < RARRAY(new_list)->len; i++)
    {
        context = rb_ary_entry(new_list, i);
        Data_Get_Struct(context, debug_context_t, debug_context);
        rb_hash_aset(threads_tbl, debug_context->thread, context);
    }

    return new_list;
}

.current_contextObject

Returns current context. Note: Debugger.current_context.thread == Thread.current



784
785
786
787
788
789
790
791
792
793
794
795
# File 'ext/ruby_debug.c', line 784

static VALUE
debug_current_context(VALUE self)
{
    VALUE thread, context;

    debug_check_started();

    thread = rb_thread_current();
    context = thread_context_lookup(thread);

    return context;
}

.debug_at_exit { ... } ⇒ Proc

Register at_exit hook which is escaped from the debugger. FOR INTERNAL USE ONLY.

Yields:

Returns:

  • (Proc)


1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
# File 'ext/ruby_debug.c', line 1019

static VALUE
debug_at_exit(VALUE self)
{
    VALUE proc;
    if (!rb_block_given_p()) {
        rb_raise(rb_eArgError, "called without a block");
    }
    proc = rb_block_proc();
    rb_set_end_proc(debug_at_exit_i, proc);
    return proc;
}

.debug_load(file) ⇒ nil

Same as Kernel#load but resets current context’s frames. FOR INTERNAL USE ONLY.

Returns:

  • (nil)


950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
# File 'ext/ruby_debug.c', line 950

static VALUE
debug_debug_load(VALUE self, VALUE file)
{
    VALUE context;
    debug_context_t *debug_context;
    
    debug_start(self);
    
    context = debug_current_context(self);
    Data_Get_Struct(context, debug_context_t, debug_context);
    rb_ary_clear(debug_context->frames);
    rb_load(file, 0);
    
    debug_stop(self);
    return Qnil;
}

.last_interruptedObject

Returns last debugged context.



766
767
768
769
770
771
772
773
774
775
# File 'ext/ruby_debug.c', line 766

static VALUE
debug_last_interrupted(VALUE self)
{
    VALUE result = Qnil;

    debug_check_started();

    rb_hash_foreach(threads_tbl, find_last_context_func, (st_data_t)&result);
    return result;
}

.resumeDebugger

Resumes all contexts.

Returns:



880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
# File 'ext/ruby_debug.c', line 880

static VALUE
debug_resume(VALUE self)
{
    VALUE current, context;
    VALUE saved_crit;
    VALUE thread;
    VALUE context_list;
    debug_context_t *debug_context;
    int i;

    debug_check_started();

    saved_crit = rb_thread_critical;
    rb_thread_critical = Qtrue;
    context_list = debug_contexts(self);

    current = thread_context_lookup(rb_thread_current());
    for(i = 0; i < RARRAY(context_list)->len; i++)
    {
        context = rb_ary_entry(context_list, i);
        if(current == context)
            continue;
        Data_Get_Struct(context, debug_context_t, debug_context);
        debug_context->suspend = 0;
    }
    for(i = 0; i < RARRAY(waiting)->len; i++)
    {
        thread = rb_ary_entry(waiting, i);
        rb_thread_run(thread);
    }
    rb_ary_clear(waiting);
    rb_thread_critical = saved_crit;

    rb_thread_schedule();

    return self;
}

.skip { ... } ⇒ Object?

The code inside of the block is escaped from the debugger.

Yields:

Returns:

  • (Object, nil)


980
981
982
983
984
985
986
987
988
989
990
# File 'ext/ruby_debug.c', line 980

static VALUE
debug_skip(VALUE self)
{
    if (!rb_block_given_p()) {
        rb_raise(rb_eArgError, "called without a block");
    }
    if(!IS_STARTED)
        return rb_yield(Qnil);
    rb_remove_event_hook(debug_event_hook);
    return rb_ensure(rb_yield, Qnil, debug_skip_i, Qnil);
}

.startBoolean .start { ... } ⇒ Object

This method activates the debugger. If it’s called without a block it returns true, unless debugger was already started. If a block is given, it starts debugger and yields to block. At the end of stops the debugger with Debugger.stop method.

Note that if you want to stop debugger, you must call Debugger.stop as many time as you called Debugger.start method.

Overloads:

  • .startBoolean

    Returns:

    • (Boolean)
  • .start { ... } ⇒ Object

    Yields:

    Returns:

    • (Object)


604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
# File 'ext/ruby_debug.c', line 604

static VALUE
debug_start(VALUE self)
{
    start_count++;
    
    if(IS_STARTED)
        return Qfalse;
        
    threads_tbl = rb_hash_new();
    breakpoints = rb_ary_new();
    waiting     = rb_ary_new();
    locker      = Qnil;

    rb_add_event_hook(debug_event_hook, RUBY_EVENT_ALL);
    
    if(rb_block_given_p())
        return rb_ensure(rb_yield, Qnil, debug_stop_i, self);
    
    return Qtrue;
}

.started?Boolean

Returns true the debugger is started.

Returns:

  • (Boolean)


137
138
139
140
141
# File 'ext/ruby_debug.c', line 137

static VALUE
debug_is_started(VALUE self)
{
    return IS_STARTED ? Qtrue : Qfalse;
}

.stopBoolean

This method disacivates the debugger. It returns true if the debugger is disacivated, otherwise it returns false.

Note that if you want to stop debugger, you must call Debugger.stop as many time as you called Debugger.start method.

Returns:

  • (Boolean)


635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
# File 'ext/ruby_debug.c', line 635

static VALUE
debug_stop(VALUE self)
{
    debug_check_started();
    
    start_count--;
    if(start_count)
        return Qfalse;
    
    rb_remove_event_hook(debug_event_hook);

    waiting     = Qnil;
    locker      = Qnil;
    breakpoints = Qnil;
    threads_tbl = Qnil;

    return Qtrue;
}

.suspendDebugger

Suspends all contexts.

Returns:



842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
# File 'ext/ruby_debug.c', line 842

static VALUE
debug_suspend(VALUE self)
{
    VALUE current, context;
    VALUE saved_crit;
    VALUE context_list;
    debug_context_t *debug_context;
    int i;

    debug_check_started();

    saved_crit = rb_thread_critical;
    rb_thread_critical = Qtrue;
    context_list = debug_contexts(self);
    current = thread_context_lookup(rb_thread_current());

    for(i = 0; i < RARRAY(context_list)->len; i++)
    {
        context = rb_ary_entry(context_list, i);
        if(current == context)
            continue;
        Data_Get_Struct(context, debug_context_t, debug_context);
        debug_context->suspend = 1;
    }
    rb_thread_critical = saved_crit;

    if(rb_thread_critical == Qfalse)
        rb_thread_schedule();

    return self;
}

.tracingBoolean

Returns true is a global tracing is activated.

Returns:

  • (Boolean)


924
925
926
927
928
# File 'ext/ruby_debug.c', line 924

static VALUE
debug_tracing(VALUE self)
{
    return tracing;
}

.tracing=(bool) ⇒ Object

Sets a global tracing flag.



936
937
938
939
940
941
# File 'ext/ruby_debug.c', line 936

static VALUE
debug_set_tracing(VALUE self, VALUE value)
{
    tracing = RTEST(value) ? Qtrue : Qfalse;
    return value;
}