1. 概要

このチュートリアルでは、コアダンプを管理および構成する方法を説明します。 kernel.core_pattern を調査してから、coredumpctlの使用に移ります。

2. 序章

コアダンプは、プログラムがクラッシュした後にLinuxカーネルによって自動的に生成されるファイルです。 このファイルには、メモリ、レジスタ値、およびクラッシュ時のアプリケーションの呼び出しスタックが含まれています。

3. 信号を使用してコアダンプを生成する

このセクションでは、プログラムを終了し、コアダンプを生成するように強制する方法を学習します。 このために、 kill コマンドを使用します。このコマンドは、がsignalsを使用してアプリケーションを終了します。 これらの信号はコアダンプを生成します。

signal、 のマニュアルページにある表を見ると、コアダンプでプログラムを終了するシグナルのリストがわかります。 これらは、コアで識別されるアクションを持つシグナルです。

       Signal      Standard   Action   Comment
       ────────────────────────────────────────────────────────────────────────
       SIGABRT      P1990      Core    Abort signal from abort(3)
       SIGALRM      P1990      Term    Timer signal from alarm(2)

例として、sleepを無期限に実行されるプログラムとして使用してみましょう。

$ sleep 500
[1] 5464
$ kill -s SIGTRAP $(pgrep sleep)
[1]+  Trace/breakpoint trap (core dumped) sleep 500

「コアダンプ」のメッセージは、コアダンプが成功したことを示しています。 また、SIGTRAPの信号を示す「トレース/ブレークポイントトラップ」にも気づきます。

このフレームワークが整ったので、コアダンプがどのように構成されているかを見てみましょう。

4. コアダンプの構成

コアダンプを設定する方法は2つあります。 1つはパイプを介してコアダンプを渡し、もう1つはファイルに保存します。

主な構成パラメーターはkernel.core_patternです。 これは、ファイルベースとパイプベースの両方のコアダンプに適用されます。 この構成パラメーターに加えて、ファイルベースのダンプにはサイズ制限があります。 このサイズは、ulimit。を使用して構成できます。

次のセクションでは、両方の構成タイプについて説明します。

4.1. コアダンプをパイプにリダイレクトする

パイプを介してコアダンプを生成するようにシステムを構成する方法を見てみましょう。 まず、パイプからコアダンプを抽出するためのサンプルプログラムが必要です。その後、カーネルを構成して引数としてプログラム名を提供し、コアダンプをプログラムに提供します[X197X ]。

クラッシュするプロセスがsleepの場合にのみ、コアダンプを生成するプログラムを作成しましょう。

#!/usr/bin/python2.7
# Filename: /tmp/core_dump_example.py
import sys

# Expect sys.argv to have %e configured in kernel.core_pattern
process_filename = sys.argv[1]

if process_filename == "sleep":
    with open("/tmp/sleep_core_dump", "wb") as core_dump:
        core_contents = bytearray(sys.stdin.read())
        core_dump.write(core_contents)

ここで、プログラムが最初の引数をチェックし、sleepが含まれている場合にのみコアダンプを出力することに注意してください。 これを/tmp/core_dump_example.pyに保存し、実行可能権限を付与しましょう。

これで、コアダンプを生成するたびにOSがスクリプトを呼び出すようにします core のマニュアルページを読むことで、kernel.core_pattternプロパティをsysctlで構成することでこれを実現できます。

$ sudo sysctl -w kernel.core_pattern="|/tmp/core_dump_example.py %e"

パターンの先頭にあるパイプは、OSがコアダンプの内容をstdinを介してスクリプトに渡す必要があることを示しています。

最後に%eがあることに注意してください。 %eは、クラッシュしたアプリケーションのプロセス名に展開されるテンプレートです。 core のマニュアルページで説明されている、利用可能なテンプレートは他にもたくさんあります。

コアダンプを作成してみましょう。

$ sleep 500 &
[1] 8828
$ kill -s SIGTRAP $(pgrep sleep)
[1]+  Trace/breakpoint trap (core dumped) sleep 500

Pythonスクリプトを使用して作成したファイルの署名を確認しましょう。

$ file /tmp/sleep_core_dump
/tmp/sleep_core_dump: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from 'sleep 500', real uid: 1000, effective uid: 1000, real gid: 1000, effective gid: 1000, execfn: '/usr/bin/sleep', platform: 'x86_64'

を使用してコアダンプ上のファイル 、クラッシュしたプログラムが / usr / bin/sleep。 また、このプロセスを開始したUIDなどの他の情報も表示されます。

4.2. コアダンプをファイルにリダイレクトする

続いて、 コアダンプファイルを生成するようにシステムを構成します。 これをする、 kernel.core_patternを目的のファイル名に設定します core のマニュアルページにあるテンプレートを使用して、コアダンプファイル名を装飾できます。

まず、コアダンプファイル名を設定しましょう。

$ sudo sysctl -w kernel.core_pattern="/tmp/%e_core_dump.%p"

sleep アプリケーションがクラッシュすると、sleep_core_dump.pidのパターンのファイルが/tmpの下に表示されると予想されます。 ここで、 %e はプログラム名、%pはプログラムのPIDです。

絶対パスの代わりに、ファイル名を指定できることに注意してください。 これにより、クラッシュするプロセスの現在の作業ディレクトリにコアダンプファイルが作成されます。

次に、ulimitを使用して課せられた制限を確認する必要があります。 コアダンプファイルには、デフォルトで制限が設定されています ulimitによって設定されたこれらの制限は、パイプベースのコアダンプハンドラーには影響しません。

コアダンプサイズの単位はブロックです。 ブロックごとに何バイトあるかを調べてみましょう。

$ stat -fc %s .
4096

ブロックあたり4096バイトを使用して、制限を5 MBに設定しましょう。これは、例で5MBを超えるコアダンプが生成されることを想定していないためです。 これは、 nblocks =desired_limit / block_size として計算できます。ここで、desired_limitとblock_sizeはどちらもバイト単位です。 5 MBは、1280ブロック=(5 * 1024 * 1024)/4096に相当します。

コアダンプには、デフォルトで0に設定されたハード制限があります。 制限を設定するには、/etc/security/limits.confに次の2行を追加する必要があります。

baeldung_user hard core 1280
baeldung_user soft core 1280

ハード制限はシステム全体の制限であり、ソフト制限はユーザーベースの制限です。 ソフト制限は、対応するハード制限よりも小さくする必要があります。 この後、再起動する必要があります。

再起動後のコアダンプファイルのサイズ制限を確認しましょう。

$ ulimit -c
1280

すばらしい、それは効果を発揮しました。 コアダンプを作成してみましょう。

$ sleep 500 &
[1] 9183
$ kill -s SIGTRAP $(pgrep sleep)
[1]+  Trace/breakpoint trap (core dumped) sleep 500
$ ls /tmp/*_core_*
-rw------- 1 user user 372K Jun 26 23:31 /tmp/sleep_core_dump.1780

目的のパターンでコアダンプファイルを作成しました。

5. プロセスを実行するためのコアダンプの生成

実行中のプロセスのコアダンプを生成すると便利な場合があります。 GDB は、実行中のプロセスのコアダンプをキャプチャできますが、 gcoreというユーティリティも付属しています。gcoreは、プロセスを実行しています。

gcoreを使用してコアダンプをキャプチャしてみましょう。

$ sleep 500 &
[1] 3000
$ sudo gcore -o sleep 3000
0x00007f975eee630e in clock_nanosleep () from /lib/x86_64-linux-gnu/libc.so.6
warning: target file /proc/3000/cmdline contained unexpected null characters
warning: Memory read failed for corefile section, 4096 bytes at 0xffffffffff600000.
Saved corefile sleep.3000
[Inferior 1 (process 3000) detached]

sleepプロセスが3000のPIDで開始されたことがわかります。 その後、 gcore が起動され、sleepプロセスに接続されました。 その結果、 gcore は、 sleep.3000 のコアダンプファイルを生成し、それ自体をデタッチしました。 gcoreがプロセスから切り離された後、プロセスは影響を受けずに正常に実行を継続します。

注: gcore をプロセスにアタッチするには、sudoが必要です。 sysctl を使用して、kernel.yama.ptrace_scope0に設定できます。 これにより、gcoresudoなしでプロセスにアタッチできるようになります。 ただし、これはセキュリティ上のリスクがあるため、注意して使用する必要があることに注意してください。 どのプロセスでも、 ptrace システムコールを使用して、プログラムの内部を調べることができます。

6. coredumpctlの概要

このセクションでは、coredumpctlというユーティリティを紹介します。 コアダンプを手動で構成するのとは対照的に、coredumpctlはコアダンプを自動的に管理します。 coredumpctlはコアダンプ自体を記録し、クラッシュの履歴を維持します。

次のセクションでは、coredumpctlがすでにシステムにインストールされていることを前提としています。

6.1. coredumpctlの構成

coredumpctl と呼ばれるサービスが付属しています systemd-コアダンプこれは、コアダンプを取得し、それを処理してメタデータを抽出するサービスです。 次に、この情報を下に保存します / var / lib / systemd /coredump/。

kernel.core_pattern をチェックすることで、このサービスが構成されているかどうかを確認できます。

$ sysctl -n kernel.core_pattern
|/lib/systemd/systemd-coredump %P %u %g %s %t 9223372036854775808 %h

kernel.core_patternがsystemd-coredumpを使用するように設定されていることを確認しました。これは、コアダンプに関連する情報をsystemd-coredumpに渡すようにカーネルに指示します。

coredumpctl、を試すには、最初に新しいコアダンプを生成する必要があります。

$ sleep 500 &
[1] 2826
$ kill -s SIGTRAP $(pgrep sleep)
[1]+  Trace/breakpoint trap (core dumped) sleep 500
$ coredumpctl
TIME                            PID   UID   GID SIG COREFILE  EXE
Sun 2020-06-28 18:52:59 BST    2826  1000  1000   5 present   /usr/bin/sleep

これは本当にクールです。 coredumpctl を試してみると、クラッシュの履歴があることがわかります。

6.2. 履歴からコアダンプファイルを抽出する

特定のクラッシュのコアダンプファイルを抽出するには、 PID、実行可能ファイルの名前、またはクラッシュの時刻のいずれかを使用できます。 例として、PIDを使用してsleepのコアダンプを保存してみましょう。

$ coredumpctl dump 2826 --output=core.dump
           PID: 2826 (sleep)
           UID: 1000 (user)
           ...
                Stack trace of thread 2826:
                #0  0x00007f7ec62f730e __GI___clock_nanosleep (libc.so.6 + 0xe030e)
                #1  0x00007f7ec62fceb7 __GI___nanosleep (libc.so.6 + 0xe5eb7)
           ...

コアダンプファイルに加えて、短い要約とそれに続くスタックトレースを見ることができます。 これは、systemd-coredumpによるコアダンプの前処理に由来します。

6.3. coredumpctlを使用したデバッグセッションの実行

debugコマンドを使用してデバッグセッションを開始する方法を見てみましょう。

$ coredumpctl debug 2826
...
Reading symbols from /usr/bin/sleep...
(No debugging symbols found in /usr/bin/sleep)
[New LWP 2959]
Core was generated by `sleep 500'.
Program terminated with signal SIGTRAP, Trace/breakpoint trap.
...
(gdb)

コアダンプファイルがロードされた状態でgdbが自動的に開かれたことに注目してください。

クラッシュを調べるために、「分解」と入力してみましょう。 その結果、次のような分解が見られます。

Dump of assembler code for function __GI___clock_nanosleep:
<__GI___clock_nanosleep+80>
   0x00007fb71b22c307 <+39>:    mov    eax,0xe6
   0x00007fb71b22c30c <+44>:    syscall
=> 0x00007fb71b22c30e <+46>:    mov    edx,eax

movwax、0xe6」の後にsyscall命令が続きます。 syscalls のリストを見ると、230(0xe6)が clock_nanosleep syscallであるように見えます。 これは、コアダンプがキャプチャされたポイントです。

7. 結論

このチュートリアルでは、コアダンプを構成する方法について説明しました。 後で、コアダンプの管理をはるかに簡単にするユーティリティ coredumpctl、について説明しました。