Installation
The installation procedure requires rubygems package and C compiler available.
Two notes worth to mention:
- For Debian users, you must have ruby-dev package installed.
- For Windows users, I don't have a precompiled version for Windows available yet.
The installation procedure is very simple:
$ sudo gem install ruby-debug
Basic usages
There are two way you can use this library.
rdebug script.
When you start your application with rdebug script, the debugger is activated by default and the execution of your script is halted at the first line of code:
$ cat test.rb
puts 'ok'
$ rdebug test.rb
./test.rb:1:puts 'ok'
(rdb:1) list
[-4, 5] in ./test.rb
=> 1 puts 'ok'
(rdb:1)
From this point you can invoke any commands available, such as you can create breakpoints and step through your code.
On demand invocation
You can require ruby-debug library from inside of your application and use a very simple API in order to summon up the debugger. Let's see how it can be done with a Rails application. I'm going to demonstrate it on my BugTrack application.
Open
<bugtrack>/config/environments/development.rbfile and append the following line to the end of the file:require 'ruby-debug'Open
<bugtrack>/app/controllers/user_cotroller.rbfile and findloginaction. What we want is to stop our application at this point and explore what is going on in there:def login debugger # add this line user = User.auth(@params['login'], @params['pwd']) if user @session[USER_PARAM] = user set_filter(user) ... endNote that I've added Kernel#debugger method call in the beginning of this method. When the execution gets to this point, we should see our debugger's command prompt.
Now start the application using webrick. Note you can't use lighttpd, because it forks fastcgi processes in the background and they don't have access to the current terminal.
$ ./script/server webrick => Booting WEBrick... => Rails application started on http://0.0.0.0:3000 => Ctrl-C to shutdown server; call with --help for options [2006-07-11 12:42:56] INFO WEBrick 1.3.1 [2006-07-11 12:42:56] INFO ruby 1.8.5 (2006-07-11) [i686-darwin8.7.1] [2006-07-11 12:42:56] INFO WEBrick::HTTPServer#start: pid=27917 port=3000Now let's try to login. As soon as I send a login request to the server, on the console I see the debugger prompt:
./script/.../controllers/user_controller.rb:59: \ user = User.auth(@params['login'], @params['pwd']) (rdb:2) _It displays the name of the file
.../user_controller.rbwhere we hit the breakpoint, the line number (59, in that case) and the line of code which will be executed next. At this point you can start playing with the debugger by entering debugger commands and executing them. For the list of all available commands use help command.
Several most-used commands.
Note that most commands have one-two character abbreviations. Again check the output of help command.
Show me the code. Use list command to browse code in the current context:
(rdb:2) list [54, 63] in ./script/../config/../app/controllers/user_controller.rb 54 end 55 end 56 57 def login 58 debugger => 59 user = User.auth(@params['login'], @params['pwd']) 60 if user 61 @session[USER_PARAM] = user 62 set_filter(user) 63 elseYou can continue browsing by entering more list commands. In order to move in the opposite direction, use
-argument. Also you can specify a line number you want to start your listing from or a range of lines separated by a dash character.Evaluate an expression in the current context. Just type any expression you want and the debugger will show you a result of this expression evaluation or an exception:
(rdb:2) params {"action"=>"login", "controller"=>"user", "pwd"=>"letmein", \ "login"=>"admin"}You can also use library by using *pp* command.
Find where we are at this point. Use where command to see the full stack trace.
(rdb:2) where --> #1 ./script/../config/../app/controllers/user_controller.rb:59:in `login' #2 /usr/.../action_controller/base.rb:910:in `perform_action_without_filters' #3 /usr/.../action_controller/filters.rb:368:in `perform_action_without_benchmark' #4 /usr/.../action_controller/benchmarking.rb:69:in `measure' #5 /usr/.../action_controller/benchmarking.rb:69:in `perform_action_without_rescue' #6 /usr/.../action_controller/rescue.rb:82:in `perform_action' ... (rdb:2)The
-->arrow indicates the current stack frame selected. It also shows the current evaluation context (see the next command).Move up and down the stack frame. You can use up and down commands in order to change the context to the upper or to the lower frame respectively. Eventually, you can evaluate an expression in the new context. Again, you can use where command to see which frame is currently activate.
(rdb:2) up 2 #3 /usr/.../action_controller/filters.rb:368:in `perform_action_without_benchmark' (rdb:2) l [363, 372] in /usr/.../action_controller/filters.rb 363 364 def perform_action_with_filters 365 before_action_result = before_action 366 367 unless before_action_result == false || performed? => 368 perform_action_without_filters 369 after_action 370 end 371 372 @before_filter_chain_aborted = (before_action_result == false) (rdb:2) before_action_result [:verify_login, :verify_access] (rdb:2) performed? false (rdb:2) down 2Stepping the program. Use step command to make a single step, use next command to move to the next line without descending inside methods. Both commands accept an optional numeric argument which specifies how many steps to make:
(rdb:2) s script/../config/../app/models/user.rb:27: find :first, (rdb:2) l [22, 31] in script/../config/../app/models/user.rb 22 def status_name 23 STATUS_NAMES[self.status] 24 end 25 26 def self.auth(login, pwd) => 27 find :first, 28 :conditions => ["login = ? AND pwd = ? AND status = ?", 29 login, pwd, ACTIVE] 30 end 31 32 def is_admin?Note that you can move up along the frame stack with *up* command and then use next command to continue execution at the new stack level.
Threads listing. Use thread list to display all threads and their statuses. The plus
+character and the number indicates the current thread of execution:(rdb:2) thread list 1 #<Thread:0x1f17c4 sleep> /usr/local/lib/ruby/1.8/webrick/server.rb:91 +2 #<Thread:0x4b3b2b8 run> script/../config/../app/models/user.rb:27 31 #<Thread:0x4b61238 sleep> /usr/local/lib/ruby/1.8/drb/drb.rb:944 (rdb:2)By the way, the debugger prompt also shows the current thread number
(rdb:2).Display variables from the current context. Use var local and var global to display local and global variables respectively.
(rdb:2) var local login => "admin" pwd => "letmein" (rdb:2) var global $! => nil $" => ["rubygems.rb", "rbconfig.rb", "rubygems/rubygems_version.rb", ...Setting breakpoints. Use break [[file:]line] command to add a breakpoint at the given point in the file:
(rdb:2) b 69 Set breakpoint 1 at ./script/.../controllers/user_controller.rb:69or at the method execution:
(rdb:2) b User.auth Set breakpoint 1 at User.authOptionally, you can set an expression which defines whether the debugger should stop when it reaches the breakpoint. This expression is evaluated each time at the context of the breakpoint position:
(rdb:2) b 72 if params['user'] == 'admin' Set breakpoint 1 at ./script/.../controllers/user_controller.rb:69To list all breakpoints use break command without parameters:
(rdb:2) break Breakpoints: 1 ./script/.../user_controller.rb:69 2 ./script/.../user_controller.rb:72 if params['user'] == 'admin'Continue execution. To continue execution use cont command.
(rdb:2) cont 127.0.0.1 - - [11/07/2006:15:09 EDT] "POST /user/login HTTP/1.1" 302 96 http://localhost:3000/bug/list -> /user/login 127.0.0.1 - - [11/07/2006:15:12 EDT] "GET /bug/list HTTP/1.1" 200 3830 http://localhost:3000/bug/list -> /bug/list
List of all commands
(rdb:1) help
ruby-debug help v.0.1.3
Commands
b[reak] [file|class:]<line|method> [if expr]
b[reak] [class.]<line|method> [if expr]
set breakpoint to some position,
optionally if expr == true
cat[ch] <an Exception> set catchpoint to an exception
cat[ch] show catchpoint
disp[lay] <expression> add expression into display expression list
undisp[lay][ nnn] delete one particular or all display expressions
b[reak] list breakpoints
del[ete][ nnn] delete some or all breakpoints
c[ont] run until program ends or hit breakpoint
r[un] alias for cont
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, - list backwards, nn-mm list given lines
up[ nn] move to higher frame
down[ nn] move to lower frame
fin[ish] return to outer frame
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
pp expression evaluate expression and print its value
h[elp] print this help
<everything else> evaluate
If you find a bug, please file it to the project tracker. Thank you.
Enjoy.
Cool looking library, but I had trouble installing on Windows. Many of my tools are installed under ‘Program Files’ and the space breaks the install script:
Building native extensions. This could take a while…
Microsoft® Program Maintenance Utility Version 8.00.50727.42 Copyright© Microsoft Corporation. All rights reserved.
‘c:\program’ is not recognized as an internal or external command, operable program or batch file. NMAKE : fatal error U1077: ‘c:\program’ : return code ‘0×1’ Stop.
Justin,
I’m sorry but I don’t have precompiled binary for Windows. You might try to compile it yourself if you have Visual Studio installed.
Kent,
This is great. I was just debugging soap4r today! Well done. Thank you.
Nice library, but here are my issues (probably already known): -> it compiles with warnings for gcc-4 -> added require ‘ruby-debug’ in development.rb environment and I get: integer 4294967294 too big to convert to `int’ when I try to load whatever page in my Rails application. Please let me know if you need more details about this errors.
aurelian,
I’ve removed these warnings in the latest version.
As for the error, does it happen with any application you try to debug, or only with this particular rails application? It would be great if I had a small script/app to reproduce this problem.
Thanks.
Hi,
With another (simple application, nothing special, no 3-rd party plugins) it seams to work.
Well, it’s not working with lighttpd because of “wrong argument type FCGI::Stream (expected File)” error is thrown by the Rails App, but with WEBrick or Mongrel it’s ok.
As for the problem with maximum range integer I will try to investigate this days and hopefully I will be able to tell you what went wrong, or where did that error comme.
aurelian,
I would appreciate it.
On OSX 10.4.7, ruby 1.8.4, intel, ruby-debug 0.1.5 – stepping, and list work but I can’t seem to get breakpoints to work. I set them but I never hit them.
Martin,
How do you set your breakpoints?
Note that you have to use just a name of a file without any path information.
I think I have isolated the problem.
I’m using tzinfo in my Rails (1.1.4) application. Because of that, at the first load of a page (after I start the server, webrick or mongrel) I got the error:
After I hit refresh in my browser it seams to work.
To reproduce, create a new Rails project, create a database table and scaffold it, add require ‘tzinfo’ in environment.rb and require ‘ruby-debug’ in environments/development.rb. Start the web server and load in your browser the page that adds a new object (the form).
Anyway, the same application seams to work without any problems on another platform (i586). Mine is ubuntu (6.06) for AMD64.
Both with the same versions for ruby, ruby-debug, rails and tzinfo.
Kent,
The problem was fixed in version 0.2 For the record here is a sample run under 0.1.5
Blenny:$ rdebug debugerbug.rb ./debugerbug.rb:3: class Foo (rdb:1) l 1-13 [1, 13] in ./debugerbug.rb 1 #!/usr/bin/env ruby -w 2 => 3 class Foo 4 def meth_a 5 p “at a” 6 end 7 def meth_b 8 instance_eval(“meth_a”) 9 end 10 end 11 12 f = Foo.new 13 f.meth_b (rdb:1) b 5 Set breakpoint 1 at ./debugerbug.rb:5 (rdb:1) b 8 Set breakpoint 2 at ./debugerbug.rb:8 (rdb:1) b 12 Set breakpoint 3 at ./debugerbug.rb:12 (rdb:1) c “at a” Blenny:$
Martin,
It’s nice to know that your problem is fixed. I’ve made some changes to the breakpoint registration procedure.
I'm trying out ruby-debug 0.6 at the moment (0.6.2 didn't work), following the steps on your tutorial.
First difference is that you need to write these lines in environment.db:
# Debugger SCRIPTLINES_ = {} if ENV['RAILS_ENV'] == 'development' require 'ruby-debug' Debugger.start if ENV['RAILS_ENV'] == 'development'
The important one here is Debugger.start. Without it you can't debug at all.
The next difference, while you are debugging, is that you can't just type an expression, it won't evaluate unless you use the 'eval' command
(rdb:14)params Unknown command (rdb:14)eval params {"action"=>"listing", "controller"=>"site"}
I'm still testing, will post more comments as I go through it. Thanks for a very informative article, there is very little help available on this very promising gem.
Nicolas,
This tutorial is quite old and I need to find some time to update it.
Two comments:
You don't need to define
SCRIPT_LINESconstant anymoreIf you want your commands to be auto evaluated you should run
set autoevalcommand (available in version 0.7)is there any way to make this do the same thing that breakpoint/breakpointer does? So that the application does need access to the terminal it started in but uses IP instead?
Is it possible to use the debugger from the rails console?
Thanks for a great tool. John
It is possible to use it with rails (google for ruby-debug rails). As a note for windows users -- do gem install ruby-debug (don't download the gem file and then install that). Good luck!
prompt what dependency with ruby-debug-base.
Nice. Thanks for such a nice tool.
I need to turn OFF readline support on Win32. IRB has a switch for this --noreadline but I didn't find the way to do this in Ruby-Debug.
Is there a switch or can we please have one?
A user can also run irb from the rdb commandline. This will allow the user to query for instance variables defined at that point as well as run console type operations. I like this facility more than breakpoint because it allows me to step through my action code. Very useful. Thanks for the writeup.
I disagree with you. Extrefox
Yo hoodia
Pill Alli
Upgraded to rails 2.02 & ruby-debug-0.10.1 then the servers refused to start in debug mode. This saved my day: Modified ruby\gems\1.8\gems\rails-2.0.2\lib\commands\servers as follow to see what's wrong
rescue Exception
puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
exit
rescue MissingSourceFile => e puts "Error - " + FILE puts e.inspect exit rescue Exception => e puts "Error - " + FILE puts e.inspect exit end
Then did that modification and it's working http://dev.rubyonrails.org/ticket/11601
Sorry I pasted some code that print out messy: The lines in bold are the originals and I removed them and replaced by: rescue MissingSourceFile => e puts "Error - " +_ FILE_ puts e.inspect exit rescue Exception => e puts "Error - " +_ FILE_ puts e.inspect exit
Then check the link below and did the modifications. http://dev.rubyonrails.org/ticket/11601
I am very new to this ruby-debug gem. I installed ruby-debug using the gem install. When I try to run rdebug with a simple code I get a load error. Is there something obivious I am missing?
Is there a windows version that works?
pill good!!!