How to debug C code in Ruby (ruby/ruby).
This article is to debug the C source code running a specific unit test in Ruby itself (ruby/ruby).
First you can set your preferred compiler flags like this.
Build
$ autoconf $ optflags=-O0 debugflags="-g3 -ggdb3 -gdwarf-4" \ ./configure \ --prefix=path/to/prefix \ --enable-shared $ make
Run a test
Then if you want to run a specific test in make test-all
, the command is like this. The V=1
is the verbose option useful to see the actual command line executed in the make
command, and the result clearly.
$ make test-all V=1 TESTS="-v test/socket/test_socket.rb -n TestSocket#test_timestamp" exec ./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems "./test/runner.rb" --ruby="./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems" --excludes-dir=./test/excludes --name=!/memory_leak/ -v test/socket/test_socket.rb -n TestSocket#test_timestamp ... [1/0] TestSocket#test_timestamp = 0.00 s Finished tests in 0.005708s, 175.2008 tests/s, 2102.4094 assertions/s. 1 tests, 12 assertions, 0 failures, 0 errors, 0 skips ruby -v: ruby 3.1.0dev (2021-06-23T12:48:42Z master 7c31ecd3ac) [aarch64-linux]
Debug with gdb
The first option is to add a gdb
command before the binary miniruby
of above command line, removing --name=!/memory_leak/
.
$ gdb -q -ex "set breakpoint pending on" --args ./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems "./test/runner.rb" --ruby="./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems" --excludes-dir=./test/excludes -v test/socket/test_socket.rb -n TestSocket#test_timestamp Reading symbols from ./miniruby... warning: File "/home/jaruga/git/ruby/ruby/.gdbinit" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load". To enable execution of this file add add-auto-load-safe-path /home/jaruga/git/ruby/ruby/.gdbinit line to your configuration file "/home/jaruga/.gdbinit". To completely disable this security protection add set auto-load safe-path / line to your configuration file "/home/jaruga/.gdbinit". For more information about this security protection see the "Auto-loading safe path" section in the GDB manual. E.g., run from the shell: info "(gdb)Auto-loading safe path" (gdb)
The second option is to use the specific make
target. Here it is.
$ cp -p run.gdb run.gdb.org $ vi run.gdb $ diff -u run.gdb.org run.gdb --- run.gdb.org 2021-06-25 16:10:56.044523121 +0000 +++ run.gdb 2021-06-25 16:10:19.452419169 +0000 @@ -1,4 +1,5 @@ set breakpoint pending on +b main b rb_assert_failure b rb_bug b ruby_debug_breakpoint $ make gdb-ruby V=1 TESTRUN_SCRIPT='./test/runner.rb -v test/socket/test_socket.rb -n TestSocket#test_timestamp' ... Breakpoint 1, main (argc=6, argv=0xfffffffff3a8) at ./main.c:35 35 { (gdb)
That's all.