class DEBUGGER__
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.
Constants
- CONTINUATIONS_SUPPORTED
Public Class Methods
Returns the list of break points where execution will be stopped.
See DEBUGGER__
for more usage
# File lib/debug.rb, line 928 def break_points @break_points end
# File lib/debug.rb, line 982 def context(thread=Thread.current) c = thread[:__debugger_data__] unless c thread[:__debugger_data__] = c = Context.new end c end
# File lib/debug.rb, line 1061 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
Returns the display expression list
See DEBUGGER__
for more usage
# File lib/debug.rb, line 921 def display @display end
# File lib/debug.rb, line 994 def get_thread(num) th = @thread_list.key(num) unless th @stdout.print "No thread ##{num}\n" throw :debug_error end th end
# File lib/debug.rb, line 990 def interrupt context(@last_thread).stop_next end
# File lib/debug.rb, line 1048 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
# File lib/debug.rb, line 966 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
# File lib/debug.rb, line 950 def set_last_thread(th) @last_thread = th end
# File lib/debug.rb, line 940 def set_trace( arg ) MUTEX.synchronize do make_thread_list for th, in @thread_list context(th).set_trace arg end end arg end
Returns the IO
used as stdout. Defaults to STDOUT
# File lib/debug.rb, line 909 def stdout @stdout end
Sets the IO
used as stdout. Defaults to STDOUT
# File lib/debug.rb, line 914 def stdout=(s) @stdout = s end
# File lib/debug.rb, line 954 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
# File lib/debug.rb, line 1003 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
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.
# File lib/debug.rb, line 1042 def thread_list_all for th in @thread_list.values.sort thread_list(th) end end
Returns the list of waiting threads.
When stepping through the traces of a function, thread gets suspended, to be resumed later.
# File lib/debug.rb, line 936 def waiting @waiting end