GDBまとめ ①コアダンプを採取する
参考書籍 : Debug Hacks
①プロセスのコアダンプを採取する
コアダンプの採取で、問題が発生したときの状態を保存できる。
コアダンプを取ることによって、手元に再現環境がなくてもデバッグできる。
コアダンプを確認するには、ulimitを使う。
$ ulimit -c 0
0となっている場合はコアダンプが無効なので、ulimitで有効化する
$ ulimit -c unlimited
このコマンドで、コアファイルのサイズを無制限にし、問題発生時のプロセスのメモリをすべてダンプできる。
コアダンプを採る設定でエラーを起こすと、coreというコアファイルがカレントディレクトリに作成される
# file core core: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from './a.out', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: './a.out', platform: 'x86_64'
②コアファイルをGDBでデバッグする
作成されたコアファイルを使い、GDBでデバッグするには次のようにする。
$ gdb ./a.out -c core GNU gdb (Debian 9.2-1) 9.2 ... Core was generated by `./a.out'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x000055634d651135 in main () at err.c:6 6 *p = 1; (gdb)
err.cの6行目でSIGSEGV(セグメンテーション違反)を起こしているとわかる。
セグメンテーション違反はアクセスが許可されていないアドレスへのアクセスなので、その部分を修正する。
gdbのlistコマンドで周辺のソースを確認できる。
(gdb) list 1 #include <stdio.h> 2 3 int main() 4 { 5 int *p = NULL; 6 *p = 1; 7 return 0; 8 }
周辺のソースから、NULLポインタ参照が行われているとわかる。
③専用ディレクトリにコアダンプを生成する。
デフォルトではコアダンプがカレントディレクトリに生成されてしまうので、ダンプ先を設定する。
sysctl変数のkernel.core_patternに、ダンプ先をフルパスで指定することで変更できる。
/etc/sysctl.confを編集し、ダンプ先を指定する。
$ cat /etc/sysctl.conf | grep core kernel.core_pattern = /root/dump/%t-%e-%p-%c.core kernel.core_uses_pid = 0 $ sysctl -p
先程のa.outを実行すると、/root/dumpの下にコアファイルが作成される。
$ ls /root/dump/ 1595254562-a.out-32941-18446744073709551615.core
このファイル名は、"時刻-プロセス名-PID-コアダンプ最大サイズ.core"になっている。
④ユーザーモードヘルパーを使って自動でコアダンプを圧縮する
コアダンプを自動で圧縮するためには、/proc/sys/kernel/core_patternを書き換える
$ echo "|/usr/local/sbin/core_helper.sh %t %e %p %c" > /proc/sys/kernel/core_pattern $ cat /proc/sys/kernel/core_pattern |/usr/local/sbin/core_helper.sh %t %e %p %c $ sysctl -p
core_helper.shの中身は簡単で、
$ cat /usr/local/sbin/core_helper.sh #!/bin/sh exec gzip - > /root/dump/$1-$2-$3-$4.core.gz $ chmod +x /usr/local/sbin/core_helper.sh
単純にコアファイルを圧縮しているだけ。
⑤システム全体でコアダンプを有効化する(Kali Linuxの場合)
Kali Linuxではログイン時に/etc/profile/profile.d以下のスクリプトが全て実行される。
profile.d以下に、core.shを作り、ログイン時にコアダンプを有効化するようにする。
$ cat /etc/profile.d/core.sh #!/bin/sh ulimit -S -c unlimited > /dev/null 2>&1 echo "|/usr/local/sbin/core_helper.sh %t %e %p %c" > /proc/sys/kernel/core_pattern sysctl -p
/proc/sys/kernel/core_patternはcoreに初期化されてしまうので、上書きするようにする。
次に、/etc/sysctl.confに以下の設定を追加する。
fs.suid_dumpable=1
この設定で、SUIDされたプログラムもコアダンプをするようになる。
⑥コアダンプマスキングを利用して共有メモリをスキップする
大きな共有メモリを利用するアプリケーションをコアダンプしていると、ディスクの圧迫やシステムの負荷が高くなる。
プロセスごとに、コアダンプさせるメモリセグメントを選択する機能がカーネル2.6.23以降から実装されている。
設定方法は、/proc/
coredump_filterは7bitのビットマスクでメモリタイプを表しており
・ビット0 : 匿名プライベートメモリ
・ビット1 : 匿名共有メモリ
・ビット2 : ファイルを使用するプライベートメモリ
・ビット3 : ファイルを使用する共有メモリ
・ビット4 : ELFファイルマッピング(カーネル2.6.24以降から)
・ビット5 : プライベートなヒュージページ
・ビット6 : 共有されたヒュージページ
デフォルトは00000033(b00110011)になっている。