gcore_with_breakpoint 作りました
gcore_with_breakpointって何?
- プログラムを止めずに core dump が取れる!!
- break point を設定して、そのポイントでの core dump が取れる!!
- break point のアドレスを控えておけば、debuginfo の無い環境でも core dump が取れる!!
↓
↓
↓
- なので、ユーザ環境への変更を最低限に抑えつつ、core dump を取得可能に!!
usage: gcore_with_breakpoint [-o filename] [-b breakpoint] [-n prog_name | pid]
もともと gdb に備わっている機能を簡単に呼び出せるようにしているだけですが、結構便利です。
デバッグ対象のプロセスを極力停止させずに、任意のブレークポイントでの core dump を取得するために、gdb パッケージに付いてきた gcore スクリプトをベースに作成しました。
他ノードと通信しながら動作するような、止めると再度通常の状態まで戻るのに時間がかかるようなサーバプロセスをデバッグしたい時に、結構役立つのではないでしょうか。
デバッグの度に動作が止まるのも嫌ですし。
なお、そもそも gcore って何?ってことについてはこちらを参照してください。
簡単に書くと、デバッグ対象のプロセスを極力停止させずに core dump を取得することができるコマンドです。
元々は手元でオリジナルのgcoreにブレークポイントだけを追加してその場しのぎで使っていたのですが、使っているうちにだんだんと書き換わっていって、そこそこ使えるようになったので公開することにしました。
gcore_with_breakpoint は gcore に以下3機能を追加しました。
- core を取得するためのブレークポイントを「-b」で設定できる(ブレークしそうにない場合にはCtrl+Cで止められます)
- プロセスidの代わりに「-n」でプログラム名を指定すると、裏でプロセスidを引いてくれる
- 複数のプロセスに対して同時にgcoreを実行できる
ただ、メインの目的は
- core を取得するためのブレークポイントを「-b」で設定できる
です。
「-b」で使用できる書式は、以下のように gdb で使用できるものと同じです。
-b "functionname"
-b "filename:functionname"
-b "filename:linenumber"
-b "*address"
ところで、複数プロセスを作ったりしているので、本当は Bash ではなく Python とかで書いたほうが良いのかなーとも思っているんですが、用が足りているのでとりあえずそのままにしています。
gcore_with_breakpoint 実行サンプル1
デバッグ対象プログラムが "zabbix_agentd"。
"common.c:140" でブレークポイントをセットした core dump として core.7995 を取得できています。
# gcore_with_breakpoint -b "common.c:140" -n zabbix_agentd
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
0x00000036642954f0 in __nanosleep_nocancel () from /lib64/libc.so.6
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6
0x00000036642954f0 in __nanosleep_nocancel () from /lib64/libc.so.6
0x00000036642950f5 in waitpid () from /lib64/libc.so.6
Breakpoint 1 at 0x40e143: file common.c, line 140.
Breakpoint 1 at 0x40e143: file common.c, line 140.
Breakpoint 1 at 0x40e143: file common.c, line 140.
Breakpoint 1 at 0x40e143: file common.c, line 140.
Breakpoint 1 at 0x40e143: file common.c, line 140.
Breakpoint 1 at 0x40e143: file common.c, line 140.Breakpoint 1, AGENT_VERSION (cmd=0x7fff4a8ff780 "agent.version", param=0x7fff4a8fef80 "", flags=0,
result=0x7fff4a902890) at common.c:141
141 { ←ここでブレークポイントに掛かってます。
Saved corefile core.7995 ←目的のcoreファイル。Program received signal SIGINT, Interrupt.
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6Program received signal SIGINT, Interrupt.
0x00000036642950f5 in waitpid () from /lib64/libc.so.6Program received signal SIGINT, Interrupt.
0x00000036642954f0 in __nanosleep_nocancel () from /lib64/libc.so.6Program received signal SIGINT, Interrupt.
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6Program received signal SIGINT, Interrupt.
0x00000036642954f0 in __nanosleep_nocancel () from /lib64/libc.so.6
Saved corefile core.7994
Saved corefile core.7997
Saved corefile core.7990
Saved corefile core.7993
Saved corefile core.7996
gcore_with_breakpoint 実行サンプル2
デバッグ対象プログラムが "zabbix_agentd"。
以下の例では "*0x40e143" でブレークポイントをセットした core dump として core.7995 を取得できています。
"*0x40e143" は "common.c:140" のアドレスなので、"common.c:140" でブレークしたのと同じ結果になります。
これは例えば顧客が debug symbol を持っておらず、かつ顧客の環境でしか現象が再現しない場合に役立ちます。
あらかじめ "common.c:140" のアドレスを調べておけば、顧客のサービスを(ほぼ)停止せずにcore dump取得ができるからです。
もちろん解析時には debug symbol を用意した環境が必要ですが、顧客のサービスを止めずに顧客のプロセスをデバッグできるのは便利です。
# gcore_with_breakpoint -o zabbix_agentd_core -b "*0x40e143" -n zabbix_agentd
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
Using host libthread_db library "/lib64/libthread_db.so.1".
0x00000036642950f5 in waitpid () from /lib64/libc.so.6
Breakpoint 1 at 0x40e143: file common.c, line 141.
0x00000036642954f0 in __nanosleep_nocancel () from /lib64/libc.so.6
Breakpoint 1 at 0x40e143: file common.c, line 141.
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6
Breakpoint 1 at 0x40e143: file common.c, line 141.
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6
Breakpoint 1 at 0x40e143: file common.c, line 141.
0x00000036642954f0 in __nanosleep_nocancel () from /lib64/libc.so.6
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6
Breakpoint 1 at 0x40e143: file common.c, line 141.
Breakpoint 1 at 0x40e143: file common.c, line 141.Breakpoint 1, AGENT_VERSION (cmd=0x7fff4a8ff780 "agent.version", param=0x7fff4a8fef80 "", flags=0,
result=0x7fff4a902890) at common.c:141
141 { ←ここでブレークポイントに掛かってます。
Saved corefile zabbix_agentd_core.7995 ←目的のcoreファイル。Program received signal SIGINT, Interrupt.
0x00000036642950f5 in waitpid () from /lib64/libc.so.6Program received signal SIGINT, Interrupt.
0x00000036642954f0 in __nanosleep_nocancel () from /lib64/libc.so.6Program received signal SIGINT, Interrupt.
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6Program received signal SIGINT, Interrupt.
0x00000036642c7d63 in __select_nocancel () from /lib64/libc.so.6Program received signal SIGINT, Interrupt.
0x00000036642954f0 in __nanosleep_nocancel () from /lib64/libc.so.6
Saved corefile zabbix_agentd_core.7996
Saved corefile zabbix_agentd_core.7994
Saved corefile zabbix_agentd_core.7993
Saved corefile zabbix_agentd_core.7997
Saved corefile zabbix_agentd_core.7990