Class: DEBUGGER__
- Inherits:
-
Object
- Object
- DEBUGGER__
- Defined in:
- lib/debug.rb
Overview
This library provides debugging functionality to Ruby.
To add a debugger to your code, start by requiring debug
in your program:
def say(word)
require 'debug'
puts word
end
This will cause Ruby to interrupt execution and show a prompt when the say
method is run.
Once you’re inside the prompt, you can start debugging your program.
(rdb:1) p word
"hello"
Getting help
You can get help at any time by pressing h
.
(rdb:1) h
Debugger help v.-0.002b
Commands
b[reak] [file:|class:]<line|method>
b[reak] [class.]<line|method>
set breakpoint to some position
wat[ch] <expression> set watchpoint to some expression
cat[ch] (<exception>|off) set catchpoint to an exception
b[reak] list breakpoints
cat[ch] show catchpoint
del[ete][ nnn] delete some or all breakpoints
disp[lay] <expression> add expression into display expression list
undisp[lay][ nnn] delete one particular or all display expressions
c[ont] run until program ends or hit breakpoint
s[tep][ nnn] step (into methods) one line or till line nnn
n[ext][ nnn] go over one line or till line nnn
w[here] display frames
f[rame] alias for where
l[ist][ (-|nn-mm)] list program, - lists backwards
nn-mm lists given lines
up[ nn] move to higher frame
down[ nn] move to lower frame
fin[ish] return to outer frame
tr[ace] (on|off) set trace mode of current thread
tr[ace] (on|off) all set trace mode of all threads
q[uit] exit from debugger
v[ar] g[lobal] show global variables
v[ar] l[ocal] show local variables
v[ar] i[nstance] <object> show instance variables of object
v[ar] c[onst] <object> show constants of object
m[ethod] i[nstance] <obj> show methods of object
m[ethod] <class|module> show instance methods of class or module
th[read] l[ist] list all threads
th[read] c[ur[rent]] show current thread
th[read] [sw[itch]] <nnn> switch thread context to nnn
th[read] stop <nnn> stop thread nnn
th[read] resume <nnn> resume thread nnn
p expression evaluate expression and print its value
h[elp] print this help
<everything else> evaluate
Usage
The following is a list of common functionalities that the debugger provides.
Navigating through your code
In general, a debugger is used to find bugs in your program, which often means pausing execution and inspecting variables at some point in time.
Let’s look at an example:
def my_method(foo)
require 'debug'
foo = get_foo if foo.nil?
raise if foo.nil?
end
When you run this program, the debugger will kick in just before the foo
assignment.
(rdb:1) p foo
nil
In this example, it’d be interesting to move to the next line and inspect the value of foo
again. You can do that by pressing n
:
(rdb:1) n # goes to next line
(rdb:1) p foo
nil
You now know that the original value of foo
was nil, and that it still was nil after calling get_foo
.
Other useful commands for navigating through your code are:
c
-
Runs the program until it either exists or encounters another breakpoint. You usually press
c
when you are finished debugging your program and want to resume its execution. s
-
Steps into method definition. In the previous example,
s
would take you inside the method definition ofget_foo
. r
-
Restart the program.
q
-
Quit the program.
Inspecting variables
You can use the debugger to easily inspect both local and global variables. We’ve seen how to inspect local variables before:
(rdb:1) p my_arg
42
You can also pretty print the result of variables or expressions:
(rdb:1) pp %w{a very long long array containing many words}
["a",
"very",
"long",
...
]
You can list all local variables with v l:
(rdb:1) v l
foo => "hello"
Similarly, you can show all global variables with v g:
(rdb:1) v g
all global variables
Finally, you can omit p
if you simply want to evaluate a variable or expression
(rdb:1) 5**2
25
Going beyond basics
Ruby Debug provides more advanced functionalities like switching between threads, setting breakpoints and watch expressions, and more. The full list of commands is available at any time by pressing h
.
Staying out of trouble
Make sure you remove every instance of require ‘debug’ before shipping your code. Failing to do so may result in your program hanging unpredictably.
Debug is not available in safe mode.
Defined Under Namespace
Classes: Context
Constant Summary collapse
- MUTEX =
:nodoc:
Thread::Mutex.new
Class Method Summary collapse
-
.break_points ⇒ Object
Returns the list of break points where execution will be stopped.
- .context(thread = Thread.current) ⇒ Object
- .debug_thread_info(input, binding) ⇒ Object
-
.display ⇒ Object
Returns the display expression list.
- .get_thread(num) ⇒ Object
- .interrupt ⇒ Object
- .make_thread_list ⇒ Object
- .resume ⇒ Object
- .set_last_thread(th) ⇒ Object
- .set_trace(arg) ⇒ Object
-
.stdout ⇒ Object
Returns the IO used as stdout.
-
.stdout=(s) ⇒ Object
Sets the IO used as stdout.
- .suspend ⇒ Object
- .thread_list(num) ⇒ Object
-
.thread_list_all ⇒ Object
Prints all threads in @thread_list to @stdout.
-
.waiting ⇒ Object
Returns the list of waiting threads.
Class Method Details
.break_points ⇒ Object
Returns the list of break points where execution will be stopped.
See DEBUGGER__ for more usage
916 917 918 |
# File 'lib/debug.rb', line 916 def break_points @break_points end |
.context(thread = Thread.current) ⇒ Object
970 971 972 973 974 975 976 |
# File 'lib/debug.rb', line 970 def context(thread=Thread.current) c = thread[:__debugger_data__] unless c thread[:__debugger_data__] = c = Context.new end c end |
.debug_thread_info(input, binding) ⇒ Object
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 |
# File 'lib/debug.rb', line 1049 def debug_thread_info(input, binding) case input when /^l(?:ist)?/ make_thread_list thread_list_all when /^c(?:ur(?:rent)?)?$/ make_thread_list thread_list(@thread_list[Thread.current]) when /^(?:sw(?:itch)?\s+)?(\d+)/ make_thread_list th = get_thread($1.to_i) if th == Thread.current @stdout.print "It's the current thread.\n" else thread_list(@thread_list[th]) context(th).stop_next th.run return :cont end when /^stop\s+(\d+)/ make_thread_list th = get_thread($1.to_i) if th == Thread.current @stdout.print "It's the current thread.\n" elsif th.stop? @stdout.print "Already stopped.\n" else thread_list(@thread_list[th]) context(th).suspend end when /^resume\s+(\d+)/ make_thread_list th = get_thread($1.to_i) if th == Thread.current @stdout.print "It's the current thread.\n" elsif !th.stop? @stdout.print "Already running." else thread_list(@thread_list[th]) th.run end end end |
.display ⇒ Object
Returns the display expression list
See DEBUGGER__ for more usage
909 910 911 |
# File 'lib/debug.rb', line 909 def display @display end |
.get_thread(num) ⇒ Object
982 983 984 985 986 987 988 989 |
# File 'lib/debug.rb', line 982 def get_thread(num) th = @thread_list.key(num) unless th @stdout.print "No thread ##{num}\n" throw :debug_error end th end |
.interrupt ⇒ Object
978 979 980 |
# File 'lib/debug.rb', line 978 def interrupt context(@last_thread).stop_next end |
.make_thread_list ⇒ Object
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
# File 'lib/debug.rb', line 1036 def make_thread_list hash = {} for th in Thread::list if @thread_list.key? th hash[th] = @thread_list[th] else @max_thread += 1 hash[th] = @max_thread end end @thread_list = hash end |
.resume ⇒ Object
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 |
# File 'lib/debug.rb', line 954 def resume MUTEX.synchronize do make_thread_list @thread_list.each do |th,| next if th == Thread.current context(th).clear_suspend end waiting.each do |th| th.run end waiting.clear end # Schedule other threads to restart as soon as possible. Thread.pass end |
.set_last_thread(th) ⇒ Object
938 939 940 |
# File 'lib/debug.rb', line 938 def set_last_thread(th) @last_thread = th end |
.set_trace(arg) ⇒ Object
928 929 930 931 932 933 934 935 936 |
# File 'lib/debug.rb', line 928 def set_trace( arg ) MUTEX.synchronize do make_thread_list for th, in @thread_list context(th).set_trace arg end end arg end |
.stdout ⇒ Object
Returns the IO used as stdout. Defaults to STDOUT
897 898 899 |
# File 'lib/debug.rb', line 897 def stdout @stdout end |
.stdout=(s) ⇒ Object
Sets the IO used as stdout. Defaults to STDOUT
902 903 904 |
# File 'lib/debug.rb', line 902 def stdout=(s) @stdout = s end |
.suspend ⇒ Object
942 943 944 945 946 947 948 949 950 951 952 |
# File 'lib/debug.rb', line 942 def suspend MUTEX.synchronize do make_thread_list for th, in @thread_list next if th == Thread.current context(th).set_suspend end end # Schedule other threads to suspend as soon as possible. Thread.pass end |
.thread_list(num) ⇒ Object
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 |
# File 'lib/debug.rb', line 991 def thread_list(num) th = get_thread(num) if th == Thread.current @stdout.print "+" else @stdout.print " " end @stdout.printf "%d ", num @stdout.print th.inspect, "\t" file = context(th).instance_eval{@file} if file @stdout.print file,":",context(th).instance_eval{@line} end @stdout.print "\n" end |
.thread_list_all ⇒ Object
Prints all threads in @thread_list to @stdout. Returns a sorted array of values from the @thread_list hash.
While in the debugger you can list all of the threads with: DEBUGGER__.thread_list_all
(rdb:1) DEBUGGER__.thread_list_all
+1 #<Thread:0x007fb2320c03f0 run> debug_me.rb.rb:3
2 #<Thread:0x007fb23218a538 debug_me.rb.rb:3 sleep>
3 #<Thread:0x007fb23218b0f0 debug_me.rb.rb:3 sleep>
[1, 2, 3]
Your current thread is indicated by a +
Additionally you can list all threads with th l
(rdb:1) th l
+1 #<Thread:0x007f99328c0410 run> debug_me.rb:3
2 #<Thread:0x007f9932938230 debug_me.rb:3 sleep> debug_me.rb:3
3 #<Thread:0x007f9932938e10 debug_me.rb:3 sleep> debug_me.rb:3
See DEBUGGER__ for more usage.
1030 1031 1032 1033 1034 |
# File 'lib/debug.rb', line 1030 def thread_list_all for th in @thread_list.values.sort thread_list(th) end end |
.waiting ⇒ Object
Returns the list of waiting threads.
When stepping through the traces of a function, thread gets suspended, to be resumed later.
924 925 926 |
# File 'lib/debug.rb', line 924 def waiting @waiting end |