エラー時にexit(1)しちゃうようなプログラムにコアダンプさせる
かなり久々の記事。
昨日、一昨日とmixiが障害発生のために閲覧できなくなっていた。
DDoSアタックでもないらしいし、なにが原因かなーと思ってたら、
mixiのCTO @nealsato氏がtwitterで下記のツイートをしてた。
二日とも複数台のmemcachedが連続して落ちました。コアは吐かずにストンと落ちるので、原因追及に時間がかかりましたが、memcachedへの接続数が異常に多いと落ちる事は再現できました。
#mixi
コア吐かないってことはプログラム側でexitしてるんだろうなーと思いつつ、
またまたtwitterで@kazuho氏による下記ツイートを発見。
「正常終了してるなら exit を LD_PRELOAD して SEGV させてコアダンプ採取すればいいじゃない」ってじっちゃんが言ってた
おーなるほどと思い、実際やってみた。
まずコアダンプしてくれるか設定確認。
# ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 4096 max locked memory (kbytes, -l) 32 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) unlimited virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
core file sizeが0だとコアダンプしてくれないので、
下記コマンドを実行。
# ulimit -c 1048576
これでコアファイルのサイズは1MBになり、
コアダンプしてくれるようになる。
んで、テストプログラム。
///// // test.c #include <stdio.h> #include <stdlib.h> int main() { puts("hello, world!"); exit(0); } /////
コンパイルして実行。
# gcc -o test test.c # ./test hello, world!
次はexitのラッパー関数。
///// // sigsegv.c #include <signal.h> void exit(int status) { raise(SIGSEGV); } /////
# gcc -fPIC -shared -o sigsegv.o sigsegv.c
んでexitを置き換えて実行。
# LD_PRELOAD=./sigsegv.o ./test hello, world! セグメンテーション違反です (core dumped)
成功!
これは色々使えそう。