MRIを読む (3) デバッグ方法の入り口を覚える
gdbを試したい
gdbがない
$ gdb rubies/bin/ruby-2.1.4 The program 'gdb' can be found in the following packages: * gdb * gdb-minimal Ask your administrator to install one of them
gdbを入れる
apt-get install -y gdb
gdbで止める
putsしたところを止める。
$ gdb rubies/bin/ruby-2.1.4 GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from rubies/bin/ruby-2.1.4...done. (gdb) b rb_io_puts Breakpoint 1 at 0x51970: rb_io_puts. (2 locations) (gdb) r -e 'puts :hi' Starting program: /home/vagrant/rubies/bin/ruby-2.1.4 -e 'puts :hi' [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". [New Thread 0x7ffff7ff7700 (LWP 2593)] Breakpoint 1, rb_io_puts (argc=1, argv=0x7ffff7eec038, out=93824997809280) at io.c:6984 6984 { (gdb) l 6979 * test 6980 */ 6981 6982 VALUE 6983 rb_io_puts(int argc, VALUE *argv, VALUE out) 6984 { 6985 int i; 6986 VALUE line; 6987 6988 /* if no argument given, print newline. */ (gdb)
gdbでいろいろできそう。 gdbの使い方を覚えねば。 rubyの値を表示してくれるようなマクロを探したい。
coreを取ってみる
実行中のプロセスにコアをダンプする。
$ rubies/bin/ruby-2.1.4 -e 'loop { p :hi; sleep 5 }' & $ gcore 2081 # ここは適宜読み替えてください
とっただけではどうしようもない
gdbrubyを使ってバックトレースを見る
CoreからRubyのバックトレースを表示するgdbruby.rbを作った
を参考に表示させてみる
$ rubies/bin/gem-2.1.4 install gdbruby $ rubies/bin/gdbruby.rb core.2081 rubies/bin/ruby-2.1.4 environ: XDG_SESSION_ID=2 TERM=xterm-256color SHELL=/bin/bash SSH_CLIENT=10.0.2.2 54405 22 SSH_TTY=/dev/pts/0 USER=vagrant LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31 MAIL=/var/mail/vagrant PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games PWD=/home/vagrant LANG=en_US.UTF-8 SHLVL=1 HOME=/home/vagrant LOGNAME=vagrant SSH_CONNECTION=10.0.2.2 54405 10.0.2.15 22 LC_CTYPE=ja_JP.UTF-8 LESSOPEN=| /usr/bin/lesspipe %s XDG_RUNTIME_DIR=/run/user/1000 LESSCLOSE=/usr/bin/lesspipe %s %s _=rubies/bin/ruby-2.1.4 ruby_version: "2.1.4" c_backtrace: #0 pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238 #1 0x00007fd6eb996e6f in native_cond_timedwait (ts=<optimized out>, mutex=<optimized out>, cond=<optimized out>) at thread_pthread.c:352 #2 native_sleep (th=0x7fd6edcc95f0, timeout_tv=0x7fff40dffe10) at thread_pthread.c:1061 #3 0x00007fd6eb99877b in sleep_timeval (th=0x7fd6edcc95f0, tv=..., spurious_check=1) at thread.c:1049 #4 0x00007fd6eb99bf35 in rb_thread_wait_for (time=...) at thread.c:1118 #5 0x00007fd6eb8aeb70 in rb_f_sleep (argc=1, argv=0x7fd6eb6f2060) at process.c:4230 #6 0x00007fd6eb975174 in vm_call_cfunc_with_frame (ci=<optimized out>, reg_cfp=0x7fd6eb7f1ed0, th=0x7fd6edcc95f0) at vm_insnhelper.c:1489 #7 vm_call_cfunc (th=0x7fd6edcc95f0, reg_cfp=0x7fd6eb7f1ed0, ci=<optimized out>) at vm_insnhelper.c:1579 #8 0x00007fd6eb979f24 in vm_exec_core (th=th@entry=0x7fd6edcc95f0, initial=initial@entry=0) at insns.def:1028 #9 0x00007fd6eb97db8f in vm_exec (th=th@entry=0x7fd6edcc95f0) at vm.c:1398 #10 0x00007fd6eb9810da in invoke_block_from_c (th=0x7fd6edcc95f0, block=<optimized out>, self=<optimized out>, argc=argc@entry=0, argv=argv@entry=0x0, blockptr=blockptr@entry=0x0, cref=cref@entry=0x0, defined_class=8) at vm.c:817 #11 0x00007fd6eb981d44 in vm_yield (argc=0, argv=0x0, th=<optimized out>) at vm.c:856 #12 rb_yield_0 (argv=0x0, argc=0) at vm_eval.c:938 #13 loop_i () at vm_eval.c:1008 #14 0x00007fd6eb829b0e in rb_rescue2 (b_proc=b_proc@entry=0x7fd6eb981cf0 <loop_i>, data1=data1@entry=0, r_proc=r_proc@entry=0x0, data2=data2@entry=0) at eval.c:754 #15 0x00007fd6eb973a3e in rb_f_loop (self=140561089356800) at vm_eval.c:1042 #16 0x00007fd6eb9839a1 in vm_call_cfunc_with_frame (ci=<optimized out>, reg_cfp=0x7fd6eb7f1f70, th=0x7fd6edcc95f0) at vm_insnhelper.c:1489 #17 vm_call_cfunc (ci=<optimized out>, reg_cfp=0x7fd6eb7f1f70, th=0x7fd6edcc95f0) at vm_insnhelper.c:1579 #18 vm_call_method (th=0x7fd6edcc95f0, cfp=0x7fd6eb7f1f70, ci=<optimized out>) at vm_insnhelper.c:1767 #19 0x00007fd6eb97a865 in vm_exec_core (th=th@entry=0x7fd6edcc95f0, initial=initial@entry=0) at insns.def:999 #20 0x00007fd6eb97db8f in vm_exec (th=th@entry=0x7fd6edcc95f0) at vm.c:1398 #21 0x00007fd6eb989996 in rb_iseq_eval_main (iseqval=iseqval@entry=140561093547920) at vm.c:1662 #22 0x00007fd6eb825a8f in ruby_exec_internal (n=0x7fd6ee0cd790) at eval.c:253 #23 0x00007fd6eb8293ad in ruby_exec_node (n=0x7fd6ee0cd790) at eval.c:318 #24 ruby_run_node (n=<optimized out>) at eval.c:310 #25 0x00007fd6eb82566b in main (argc=3, argv=0x7fff40e00ff8) at main.c:36 ruby_backtrace: [4] sleep() <- -e:1 [3] block in <main>() <- -e:1 [2] loop() <- -e:1 [1] <main>() <- -e:1
バックトレースが出た。
デバッグシンボルを調べる。
rubyをビルドしたときのconfigureオプションを表示する - Qiitaのコマンドを打ってgccに-g
オプション渡しているか確認してみた。
最初から入ってるシステムのrubyだとついてる。
$ rubies/bin/ruby-2.1.4 -r rbconfig -e 'puts RbConfig::CONFIG["configure_args"]' '--prefix=/home/vagrant/rubies' '--program-suffix=-2.1.4'
あれ、ないけどデバッグシンボルついてるのかな。
coreを取ってみる2
man core
すると、コアダンプするシグナルはsignal(7)
にあると書かれているので、man 7 signal
で見る。
SIGQUIT
やSIGABRT
もcoreを吐くとあったので試しにkill -3 PID
やkill -ABRT PID
などで殺してみるが、コアを吐かない。
Ubuntu 12.10 で core ファイルが作成されない - @tmtms のメモ
のようなブログを見つけたのでulimit -a
で確認(coreだけ見るならulimit -c
でとれるとman bash
に書いてあった)すると、0に設定されている。
もう一度man core
をよく見ると、コアファイルが作成されない状況について、ulimit
にもしっかり触れられていた。
上限を引き上げる。
$ ulimit -c 100000
もういちどABRTしてみると、しっかりコアはいてくれた。
まとめ
gdb
でrubyのc関数の中で止まる方法を覚えたgcore
で実行中のRubyプロセスのコアをダンプする方法を覚えたkill
でコアをダンプするシグナルを送り、コアをダンプする方法を覚えたcore
がでない状況について調べる方法を覚えた
実際に使いこなすためには
実例で学べないので難しそう。Rubyじゃなくてもいいので実例で学ぶ方法を探したい。
試したい
ここで紹介されているツールを試してみたい。
Ruby プロセスを追いかけるツール9選 - sonots:blog
つぎ
環境構築や、読む下準備ばかりしているので明日こそMRIを読みはじめるぞ。