How do I configure ruby to enter the debugger on Ctrl-C (SIGINT)?
Asked Answered
P

2

3

I'd like to enter the debugger upon typing ctrl-C (or sending a SIGINT). I have installed the debugger (I'm running Ruby 1.9.3) and verified that it works. I've added this to my setup files (this is for Padrino, but I assume it would be similar for Rails):

# file: config/boot.rb
Padrino.before_load do
  trap("SIGINT") { debugger } if Padrino.env == :development
end

... but typing Ctrl-C does not invoke the debugger. In fact, if I replace debugger with puts "saw an interrupt!", typing Ctrl-C doesn't cause a print to happen either.

update

Following this suggestion from Mike Dunlavey, I tried explicitly calling catch Interrupt from within the debugger:

$ rdebug `which padrino` console
^Z^Z$HOME/usr/bin/padrino:9
require 'rubygems'
(rdb:1) catch Interrupt
Catch exception Interrupt.
(rdb:1) c
=> Loading development console (Padrino v.0.10.7)
=> Loading Application BlueDotAe
=> Loading Application Admin
irb(main):001:0>   C-c C-c^C
irb(main):001:0> 

No joy -- interrupt did not enter the debugger.

What am I missing?

Philoprogenitive answered 7/3, 2013 at 17:46 Comment(0)
P
4

If you want to trap SIGINT while running in the console, the short answer is: you cannot unless you monkey-patch IRB. Every Ruby app (whether padrino, or rails or whatnot) that uses the console will end up calling usr/lib/ruby/1.9.1/irb.rb, and in IRB.start, it does:

trap("SIGINT") do
  irb.signal_handle
end

... just before entering the main loop. This will override any trap("SIGINT") you might have put in your startup code.

But if you want to trap SIGINT in a script file (for example, if you want to profile your code as described by Mike Dunlavey here), you can create a script file such as:

# File: profile_complex_operation.rb
trap("SIGINT") { debugger }
MyApp.complex_operation

and then invoke it as in:

$ ruby profile_complex_operation.rb

Now, when you hit ^C (or send SIGINT from another process), it will enter the debugger.

Philoprogenitive answered 7/3, 2013 at 20:21 Comment(1)
Just a point of clarification - with this method when you enter the debugger do you enter the callstack at the point of the trap or at the point of code execution when you send the SIGINT?Blouin
M
1

You may try to use GDB wrapper for Ruby (GitHub).

Install on Linux via:

sudo apt-get install gdb python-dev ncurses-dev ruby-rvm
gem install gdb.rb

Basic usage:

require 'gdb'

# create a new GDB::Ruby instance and attach it to
# pid 12345
gdb = GDB::Ruby.new(12345)

# print the (ruby) backtrace of the remote process
gdb.backtrace.each { |line| puts line }

# show the current local variables, and their values
p gdb.local_variables

# evaluate arbitrary ruby code in the remote process
p gdb.eval('%(pid #{$$})')

# show how many instances of each class exist in the
# remote process
p gdb.object_space

# raise an exception in the remote process
gdb.raise Exception, "go boom!"

# close the connection to the remote process
gdb.quit

Or to debug the hung process, attach it via:

rvmsudo gdb.rb PID

then:

# in gdb get a ruby stacktrace with file names and line numbers
# here I'm filtering by files that are actually in my app dir
(gdb) ruby eval caller.select{|l| l =~ /app\//}

Source: Using gdb to inspect a hung ruby process

Some alternatives:

  • rbtrace - like strace, but for ruby code (usage: rbtrace -p <PID> --firehose).
  • debug.rb script by tmm1 (author of gdb.rb) which can help to debug a process using strace/gdb.

See also:

Mononucleosis answered 1/8, 2015 at 18:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.