Post-mortem debugging

Posted on December 20, 2006

Using rdebug script

You run your application with rdebug and use -m command line option:

    # rdebug -m script_name

For example,

    $ cat t.rb 
    def t1
      raise 'test'
    end
    def t2
      t1
    end
    t2

    $ rdebug -m t.rb 
    ./t.rb:1: def t1
    (rdb:1) c
    ./t.rb:2: raise 'test'
    (rdb:post-mortem) l=
    [-3, 6] in ./t.rb
       1  def t1
    => 2    raise 'test'
       3  end
       4  def t2
       5    t1
       6  end
    (rdb:post-mortem)

Notice the new post-mortem prompt. It indicates that at this point you can't use any stepping commands other than [cont]inue. All other commands are still available, so you can [eval]uate an expression in this context, move up* and *down the stack, etc.

Explicit activation of post-mortem debugging

You can activate the post-mortem mode with Debugger.post_mortem method from your script:

    $ cat t.rb 
    require 'rubygems'
    require 'ruby-debug'

    Debugger.start
    Debugger.post_mortem

    def t1
      raise 'test'
    end
    def t2
      t1
    end
    t2

    $ ruby t.rb 
    t.rb:8: raise 'test'
    (rdb:post-mortem) l=
    [3, 12] in t.rb
       3  
       4  Debugger.start
       5  Debugger.post_mortem
       6  
       7  def t1
    => 8    raise 'test'
       9  end
       10  def t2
       11    t1
       12  end
    (rdb:post-mortem)

Note of caution: Debugger.post_mortem method installs a special at_exit hook. So if your application exits by calling Kernel#exit! method, the debugger is not activated! Be careful.

Local post-mortem debugging

All previous examples describe the case when an application exits without handling an exception. What happens if we've got a peculiar block of code that is not supposed to raise any exceptions, yet, contrary to all expectations, it still does. Debugger.post_mortem method accepts a block of code and activates the post-mortem mode when it executes it.

    $ cat t.rb 
    require 'rubygems'
    require 'ruby-debug'

    Debugger.start

    def t1
      raise 'test'
    end
    def t2
      t1
    end

    begin
      Debugger.post_mortem do
        t2
      end
    rescue
      debugger
      puts 'handled'
    end

    $ ruby t.rb 
    t.rb:7: raise 'test'
    (rdb:post-mortem) l=
    [2, 11] in t.rb
       2  require 'ruby-debug'
       3  
       4  Debugger.start
       5  
       6  def t1
    => 7    raise 'test'
       8  end
       9  def t2
       10    t1
       11  end
    (rdb:post-mortem) c
    t.rb:19: puts 'handled'
    (rdb:1) l=
    [14, 23] in t.rb
       14    Debugger.post_mortem do
       15      t2
       16    end
       17  rescue
       18    debugger
    => 19    puts 'handled'
       20  end
    (rdb:1) c
    handled

    $

Notice that the debugger is still activated when we finished with post-mortem breakpoint.

Source code reloading

Another feature that has been implemented in the latest versions is the source code reloading. This feature is very useful when you debug your Rails application in development mode. You start your application, you make some changes, you hit your browser's Refresh button and you are done with it. No need to restart your mongrel all the time.

So wouldn't it be nice if ruby-debug also be able to reflect all these code changes instead of displaying stale source code?

By entering reload command, you can instruct the debugger to refresh all source code it's aware of. You can also automate this process by using reload on command. In this case, the debugger will be checking the file timestamp and reload the file if it's been updated automatically.

New irb command (experimental)

Evan Weaver popped the question in his blog:

It would be nice to be able to drop into an IRB instance, too, but I don’t know how to do that.

Enter irb command - it activates an irb instance with the current frame's binding. This feature is somewhat experimental and is not available in remote mode. (I wasn't able to install my own input method in order to redirect standard IO).

That's it for now. Enjoy.

Comments
  1. Suraj N. KurapatiDecember 20, 2006 @ 07:44 PM

    WOW! :-O

    Post-mortem debugging is simply brilliant! It feels like the next killer innovation for Ruby.

    Kudos to you, sir! :-)

  2. Suraj N. KurapatiDecember 20, 2006 @ 07:51 PM

    I posted a mention about this brilliant innovation on ruby-talk:

    http://www.ruby-forum.com/topic/91961

    Hope you don’t mind. :-)

  3. Kent SibilevDecember 21, 2006 @ 04:27 AM

    Suraj,

    Thank you for bug reports!

  4. Suraj N. KurapatiDecember 21, 2006 @ 09:00 AM

    Any plans on releasing a new 0.5.2 gem with the bug fixes? :-)

  5. ChrisDecember 21, 2006 @ 09:37 AM

    Wicked cool.

  6. Kent SibilevDecember 21, 2006 @ 11:59 AM

    Suraj,

    I’ve just uploaded a new version.

  7. Suraj N. KurapatiDecember 21, 2006 @ 03:52 PM

    Thanks for the release, Kent.

    Now all I need is to somehow configure Test::Unit and rSpec to raise assertion-failed exceptions—so that ruby-debug with post-mortem mode can come to the rescue.

  8. HomerDecember 29, 2006 @ 06:25 AM

    Can someone please explain what is the difference between post-mortem debugging and MS Visual Studio asking to “Break” on an exeption in Debug mode ?

  9. Noah DanielsJanuary 18, 2007 @ 08:15 PM

    Thanks, this looks like a great tool. One thing though – I can get regular debugging to work in Rails (using webrick), and I can get postmortem debugging to work in a non-Rails Ruby app, but I cannot get postmortem to work in Rails, either with local or remote debugging. Webrick is interrupted initially for me to ‘continue’ it from a debugger prompt, but then when the rails app throws an exception, it’s just tossed to the web browser to display, and nothing comes up in the webrick console window.

    Am I doing something wrong? Thanks!

  10. Kent SibilevJanuary 21, 2007 @ 09:39 AM

    Noah,

    You can use post_mortem Rails plugin for that.

    $ ./script/plugin install http://svn.datanoise.com/post_mortem
  11. MeekishMarch 14, 2007 @ 02:02 AM

    This is one revolutionary piece of software. I just found an unhandled exception that would have taken me literally hours to track down. Thanks K!

  12. JessicaApril 01, 2007 @ 07:05 PM

    Thanks for the excellent work and resource. Nice work on top of that.

  13. MerlynMay 06, 2007 @ 06:07 PM

    Just want to express gratitude for information.