How do I configure ruby to enter the debugger on C

2019-01-20 13:13发布

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?

2条回答
淡お忘
2楼-- · 2019-01-20 13:23

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.

查看更多
老娘就宠你
3楼-- · 2019-01-20 13:28

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:

查看更多
登录 后发表回答