hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

crashコマンドの使い方



1 crashコマンドとは?

crashコマンドは、カーネルデバッグ時に使用するコマンドです。カーネルに何らかの不具合が発生してクラッシュすると、vmcore(ダンプファイル)が生成されます。生成されたvmcoreをcrashコマンドで解析することで、カーネルクラッシュの原因を特定することができます。

2 検証環境

AlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 8.6 (Sky Tiger)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
4.18.0-372.9.1.el8.x86_64

3 インストール方法

crashパッケージをインストールします。

[root@server ~]# dnf -y install crash

crashコマンドの版数は以下のとおりです。

[root@server ~]# crash --version
crash 7.3.2-2.el8.alma
-help-

kernel-debuginfoパッケージをインストールするため、リポジトリを追加します。

[root@server ~]# dnf config-manager --add-repo=https://repo.almalinux.org/vault/8.6/BaseOS/debug/x86_64/

kernel-debuginfoパッケージをインストールします。

[root@server ~]# dnf install kernel-debuginfo-4.18.0-372.9.1.el8

SysRq(echo c > /proc/sysrq_trigger)によりカーネルをクラッシュさせます。再起動後、/var/crash/配下に採取されたvmcoreを確認します。

[root@server ~]# ls -l /var/crash/127.0.0.1-2023-02-09-06\:08\:11/
合計 65552
-rw-------. 1 root root    57723  2月  9 20:08 kexec-dmesg.log
-rw-------. 1 root root 67007812  2月  9 20:08 vmcore
-rw-------. 1 root root    49196  2月  9 20:08 vmcore-dmesg.txt

crashコマンドの引数に指定するカーネルを確認します。

[root@server ~]# ls -l /usr/lib/debug/lib/modules/4.18.0-372.9.1.el8.x86_64/vmlinux
-rwxr-xr-x. 1 root root 925778760  5月 10  2022 /usr/lib/debug/lib/modules/4.18.0-372.9.1.el8.x86_64/vmlinux

4 crashコマンド起動方法

vmcoreとカーネルイメージを引数にしてcrashコマンドを実行します。

[root@server ~]# crash /var/crash/127.0.0.1-2023-02-09-06\:08\:11/vmcore /usr/lib/debug/lib/modules/4.18.0-372.9.1.el8.x86_64/vmlinux
-snip-
WARNING: kernel relocated [180MB]: patching 105260 gdb minimal_symbol values

      KERNEL: /usr/lib/debug/lib/modules/4.18.0-372.9.1.el8.x86_64/vmlinux
    DUMPFILE: /var/crash/127.0.0.1-2023-02-09-06:08:11/vmcore  [PARTIAL DUMP]
        CPUS: 4
        DATE: Thu Feb  9 20:07:56 JST 2023
      UPTIME: 00:55:55
LOAD AVERAGE: 0.00, 0.03, 0.00
       TASKS: 160
    NODENAME: server
     RELEASE: 4.18.0-372.9.1.el8.x86_64
     VERSION: #1 SMP Tue May 10 08:57:35 EDT 2022
     MACHINE: x86_64  (2808 Mhz)
      MEMORY: 4 GB
       PANIC: "sysrq: SysRq : Trigger a crash"
         PID: 1489
     COMMAND: "bash"
        TASK: ffff8f7fc1e50000  [THREAD_INFO: ffff8f7fc1e50000]
         CPU: 1
       STATE: TASK_RUNNING (SYSRQ)

5 コマンド一覧、ヘルプを表示する方法(help)

5.1 コマンド一覧を表示する方法

引数なしでhelpを実行すると、コマンド一覧を表示することができます。

crash> help

*              files          mod            sbitmapq       union
alias          foreach        mount          search         vm
ascii          fuser          net            set            vtop
bpf            gdb            p              sig            waitq
bt             help           ps             struct         whatis
btop           ipcs           pte            swap           wr
dev            irq            ptob           sym            q
dis            kmem           ptov           sys
eval           list           rd             task
exit           log            repeat         timer
extend         mach           runq           tree

crash version: 7.3.2-2.el8.alma   gdb version: 7.6
For help on any command above, enter "help <command>".
For help on input options, enter "help input".
For help on output options, enter "help output".

5.2 コマンドのヘルプを表示する方法

helpと入力したあとコマンド名を入力すると、コマンドのヘルプを表示することができます。

btコマンドのヘルプを表示してみます。

crash> help bt

NAME
  bt - backtrace
-snip-

次に、modコマンドのヘルプを表示してみます。

crash> help mod

NAME
  mod - module information and loading of symbols and debugging data
-snip-

6 logコマンドの使い方

logコマンドは、カーネルログバッファに保存されているログを表示するコマンドです。

6.1 引数無しで実行する方法

引数なしでlogコマンドを実行してみます。今回、SysRqによってカーネルパニックを発生させて、その時に生成したvmcoreを使って解析をしています。SysRqによるカーネルパニックが、カーネル起動後3354秒で発生していることがわかります。

crash> log
[    0.000000] Linux version 4.18.0-372.9.1.el8.x86_64 (mockbuild@142f1156fd3c4b36be0752fc556cdb86) (gcc version 8.5.0 20210514 (Red Hat 8.5.0-10) (GCC)) #1 SMP Tue May 10 08:57:35 EDT 2022
-snip-
[ 3354.190163] sysrq: SysRq : Trigger a crash
[ 3354.191105] Kernel panic - not syncing: sysrq triggered crash
[ 3354.191753] CPU: 1 PID: 1489 Comm: bash Kdump: loaded Not tainted 4.18.0-372.9.1.el8.x86_64 #1
[ 3354.192081] Hardware name: Red Hat KVM/RHEL-AV, BIOS 1.15.0-2.module_el8.6.0+2880+7d9e3703 04/01/2014
[ 3354.192352] Call Trace:
[ 3354.193123]  dump_stack+0x41/0x60
[ 3354.193597]  panic+0xe7/0x2ac
[ 3354.193962]  ? printk+0x58/0x6f
[ 3354.194300]  sysrq_handle_crash+0x11/0x20
[ 3354.194664]  __handle_sysrq.cold.13+0x48/0xfb
[ 3354.194977]  write_sysrq_trigger+0x2b/0x30
[ 3354.195296]  proc_reg_write+0x39/0x60
[ 3354.195654]  vfs_write+0xa5/0x1a0
[ 3354.196018]  ksys_write+0x4f/0xb0
[ 3354.196329]  do_syscall_64+0x5b/0x1a0
[ 3354.196707]  entry_SYSCALL_64_after_hwframe+0x65/0xca

6.2 時刻を表示する方法(-T)

-Tは時刻を表示するオプションです。カーネルの起動時刻が2023年2月9日 19時12分01秒であることがわかります。

crash> log -T
[Thu Feb  9 19:12:01 JST 2023] Linux version 4.18.0-372.9.1.el8.x86_64 (mockbuild@142f1156fd3c4b36be0752fc556cdb86) (gcc version 8.5.0 20210514 (Red Hat 8.5.0-10) (GCC)) #1 SMP Tue May 10 08:57:35 EDT 2022
-snip-

6.3 ログの重要度を表示する方法(-m)

-mはログの重要度を表示するためのオプションです。重要度は、値が小さいほど重要度が高く、早急に処置が必要になります。以下は重要度の一覧です。

KERN_EMERG   0
KERN_ALERT   1
KERN_CRIT    2
KERN_ERR     3
KERN_WARNING 4
KERN_NOTICE  5
KERN_INFO    6
KERN_DEBUG   7

-mオプションを指定してlogコマンドを実行してみます。"Linux version..."の重要度はKERN_NOTICE(5)であることがわかります。一方、"Kernel panic.."の重要度はKERN_EMERG(0)であり、ただちに対処する必要があることがわかります。

crash> log -m
[    0.000000] <5>Linux version 4.18.0-372.9.1.el8.x86_64 (mockbuild@142f1156fd3c4b36be0752fc556cdb86) (gcc version 8.5.0 20210514 (Red Hat 8.5.0-10) (GCC)) #1 SMP Tue May 10 08:57:35 EDT 2022
-snip-
[ 3354.191105] <0>Kernel panic - not syncing: sysrq triggered crash

7 setコマンドの使い方

setコマンドを使うことで、コンテキストを切り替えることができます。たとえば、コンテキストをsystemd(PIDが1)に切り替えたとします。このあとtaskコマンドを実行する場合、task 1と明にPIDを指定しなくても、taskと実行するだけでsystemdのtask_struct構造体の中身を表示することができます。taskコマンド以外でも、明にPIDを指定する必要がなくなります。

7.1 プロセスコンテキストを表示する方法

引数なしでsetコマンドを実行すると、現在実行中のプロセスコンテキストを表示します。

crash> set
    PID: 1489
COMMAND: "bash"
   TASK: ffff8f7fc1e50000  [THREAD_INFO: ffff8f7fc1e50000]
    CPU: 1
  STATE: TASK_RUNNING (SYSRQ)

7.2 プロセスコンテキストを切り替える方法(set PID)

プロセスコンテキストをsystemdに切り替えます。プロセスコンテキストをsystemdに切り替えることで、この後で実行するコマンドにおいて、明にPIDを指定する必要がなくなります。

crash> set 1
    PID: 1
COMMAND: "systemd"
   TASK: ffff8f7fc0bad000  [THREAD_INFO: ffff8f7fc0bad000]
    CPU: 0
  STATE: TASK_INTERRUPTIBLE

7.3 表示画面のスクロールオフ・オンの切り替え方法(set scroll off/set scroll on)

デフォルトでは画面のスクロールがオンになっているので、crashコマンドの出力が1画面に収まらない場合は、スペースキーを押下して画面をスクロールする必要があります。

crash> set scroll off
scroll: off (/usr/bin/less)

8 rdコマンドの使い方

rdコマンドはメモリの内容を表示するコマンドです。

8.1 メモリ内容を16進数/10進数(-d)で表示する方法

グローバル変数jiffiesの中身を表示してみます。jiffiesの値が0x1002e9d9bであることがわかります。jiffiesは、Linuxカーネルが起動してから定期的にカウントアップする変数です。

crash> rd jiffies
ffffffff8dc06000:  00000001002e9d9b                    ........

jiffiesの中身を10進数で表示してみます。jiffiesの値が4298022299であることがわかります。

crash> rd -d jiffies
ffffffff8dc06000:       4298022299

8.2 メモリ内容を文字列として表示する方法(-a)

メモリに格納されているASCII文字を表示してみます。

crash> rd -a linux_banner
ffffffff8d200100:  Linux version 4.18.0-372.9.1.el8.x86_64 (mockbuild@142f1156f
ffffffff8d20013c:  d3c4b36be0752fc556cdb86) (gcc version 8.5.0 20210514 (Red Ha
ffffffff8d200178:  t 8.5.0-10) (GCC)) #1 SMP Tue May 10 08:57:35 EDT 2022

9 modコマンドの使い方

modコマンドは、モジュールのロード/アンロードするコマンドです。

9.1 モジュール一覧を表示する方法

引数なしでmodコマンドを実行すると、モジュールの一覧が表示されます。以下の実行例では、モジュールがロードされていないので、"not loaded"と表示されています。

crash> mod
     MODULE       NAME                         BASE           SIZE  OBJECT FILE
ffffffffc033b080  failover               ffffffffc0339000    16384  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0345040  net_failover           ffffffffc0341000    24576  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0353440  virtio_console         ffffffffc034c000    36864  (not loaded)  [CONFIG_KALLSYMS]
-snip-

9.2 モジュールを個別にロードする方法(-s)

-sはロードするモジュールを指定するオプションです。ここでは、failoverモジュールをロードしてみます。

crash> mod -s failover
     MODULE       NAME                         BASE           SIZE  OBJECT FILE
ffffffffc033b080  failover               ffffffffc0339000    16384  /usr/lib/debug/lib/modules/4.18.0-372.9.1.el8.x86_64/kernel/net/core/failover.ko.debug

モジュールの一覧を確認します。OBJECT FILE欄にロードしたモジュールのファイル名が表示されているので、failoverモジュールがロードされたことがわかります。

crash> mod
     MODULE       NAME                         BASE           SIZE  OBJECT FILE
ffffffffc033b080  failover               ffffffffc0339000    16384  /usr/lib/debug/lib/modules/4.18.0-372.9.1.el8.x86_64/kernel/net/core/failover.ko.debug
-snip-

9.3 モジュールをアンロードする方法(-d)

-dはアンロードするモジュールを指定するオプションです。ここでは、failoverモジュールをアンロードしてみます。

crash> mod -d failover

モジュール一覧を確認します。OBJECT FILE欄が"not loaded"になっているため、failoverモジュールがアンロードされたことがわかります。

crash> mod
     MODULE       NAME                         BASE           SIZE  OBJECT FILE
ffffffffc033b080  failover               ffffffffc0339000    16384  (not loaded)  [CONFIG_KALLSYMS]
-snip-

9.4 モジュールを一括でロードする方法(-S)

-Sは全てのモジュールを一括でロードするオプションです。モジュールを一括でロードします。

crash> mod -S

モジュール一覧を確認します。全てのモジュールがロードされたことがわかります。

crash> mod -S
     MODULE       NAME                         BASE           SIZE  OBJECT FILE
ffffffffc033b080  failover               ffffffffc0339000    16384  /usr/lib/debug/lib/modules/4.18.0-372.9.1.el8.x86_64/kernel/net/core/failover.ko.debug
ffffffffc0345040  net_failover           ffffffffc0341000    24576  /usr/lib/debug/lib/modules/4.18.0-372.9.1.el8.x86_64/kernel/drivers/net/net_failover.ko.debug
ffffffffc0353440  virtio_console         ffffffffc034c000    36864  /usr/lib/debug/lib/modules/4.18.0-372.9.1.el8.x86_64/kernel/drivers/char/virtio_console.ko.debug
-snip-

10 netコマンドの使い方

netコマンドは、ネットワークに関係する情報を表示するコマンドです。

10.1 net_device構造体を表示する方法

オプションなしでnetコマンドを実行すると、net_device構造体を表示することができます。net_device構造体は、NICの情報(NICの名前、NICの状態、IPアドレス(*)等)を保持するデータ構造です。以下の実行例では、loとeth0のnet_device構造体の先頭アドレス、名前、IPアドレスが表示されていることがわかります。
(*) 正確にはnet_device構造体がポイントするin_ifaddr構造体に格納されています。

crash> net
   NET_DEVICE     NAME   IP ADDRESS(ES)
ffff8f7fc0e86000  lo     127.0.0.1
ffff8f7fc0e85000  eth0   192.168.122.68

10.2 arpキャッシュを表示する方法(-a)

-aはarpキャッシュを表示するオプションです。

crash> net -a
NEIGHBOUR        IP ADDRESS      HW TYPE    HW ADDRESS         DEVICE  STATE
ffff8f7fc4ecf200 192.168.122.1   ETHER      52:54:00:02:06:f9  eth0    REACHABLE

10.3 プロセスが使用しているソケットの情報を表示する方法(-s)

-sはプロセスが使用しているソケットの情報を表示するオプションです。まず、psコマンドを実行して、sshdプロセスの状態を確認します。ここでは、sshdプロセスのソケットの情報を表示してみます。

crash> ps sshd
   PID    PPID  CPU       TASK        ST  %MEM     VSZ    RSS  COMM
    842      1   2  ffff8f7fc2ec8000  IN   0.1   92408   7820  sshd
   1471    842   2  ffff8f7fc4ee5000  IN   0.2  153500  10352  sshd
   1488   1471   1  ffff8f7fc518d000  WA   0.1  153500   5908  sshd
   1512    842   1  ffff8f7fd15d8000  IN   0.2  153500  10528  sshd
   1516   1512   1  ffff8f7fc2c3d000  IN   0.1  153500   6100  sshd

sshd(PID=1471)が使用しているソケットの情報を表示してみます。sshdはソケットを5つ使用していて、それぞれ、FD(ファイルディスクリプタ)の5,6,7,9,12を使用していることがわかります。そして、1つはINETドメイン、残り4つはUNIXドメインのソケットであることがわかります。INETドメインのソケット情報では、192.168.122.68:22と192.168.122.1:42156の間でTCPコネクションが確立していることがわかります。

crash> net -s 1471
PID: 1471   TASK: ffff8f7fc4ee5000  CPU: 2   COMMAND: "sshd"
FD      SOCKET            SOCK       FAMILY:TYPE SOURCE-PORT DESTINATION-PORT
 5 ffff8f7fd2877180 ffff8f7fc4d60000 INET:STREAM  192.168.122.68-22 192.168.122.1-42156
 6 ffff8f7fc0421080 ffff8f7fc47a8d80 UNIX:STREAM
 7 ffff8f7fd2851600 ffff8f7fc3760900 UNIX:DGRAM
 9 ffff8f7fc0421b80 ffff8f7fc47aa400 UNIX:STREAM
12 ffff8f7fc4211340 ffff8f7fc47a8000 UNIX:STREAM

10.4 プロセスが使用しているソケットの詳細情報を表示する方法(-S)

-Sはプロセスが使用しているソケットの詳細情報を表示するオプションです。socket構造体の中身を表示することができます。

crash> net -S 1471
PID: 1471   TASK: ffff8f7fc4ee5000  CPU: 2   COMMAND: "sshd"
FD       SOCKET             SOCK
 5  ffff8f7fd2877180  ffff8f7fc4d60000

struct socket {
  state = SS_CONNECTED,
  type = 1,
  flags = 0,
  wq = 0xffff8f7fc2c8f880,
  file = 0xffff8f7fc4d11700,
  sk = 0xffff8f7fc4d60000,
  ops = 0xffffffff8d2fd3a0
}
-snip-

10.5 10進/16進表記のIPアドレスをドット・デシマル形式に変換する方法(-N)

-Nは10進/16進表記のIPアドレスをドット・デシマル形式に変換するオプションです。netコマンドでsocket構造体を表示すると、saddrとdaddrというメンバがあります。このメンバには送信元IP、送信先IPアドレスが格納されていますが、IPアドレスが10進数で格納されているため、わかりずらいです。-Nオプションを使うことで理解しやすいドット・デシマル形式に変換することができます。

crash> net -S 1471
-snip-
          saddr = 1148889280,
          daddr = 24815808,
-snip-

saddrをドット・デシマル形式に変換すると、送信元IPアドレスが192.168.122.68であることがわかります。

crash> net -N 1148889280
192.168.122.68

次にdaddrをドット・デシマルに変換すると、送信先IPアドレスが192.168.122.1であることがわかります。

crash> net -N 24815808
192.168.122.1

11 disコマンドの使い方

disコマンドは、逆アセンブルを表示するコマンドです。

11.1 逆アセンブルを表示する方法

ip_output()の逆アセンブルを表示してみます。

crash> dis ip_output
0xffffffff8cc7c780 <ip_output>: nopl   0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffff8cc7c785 <ip_output+5>:       push   %r12
0xffffffff8cc7c787 <ip_output+7>:       mov    %rsi,%r12
-snip-

11.2 逆アセンブル表示とソースファイルの対比を表示する方法(-l)

-lは逆アセンブルとソースファイルを表示するオプションです。

crash> dis -l ip_output
/usr/src/debug/kernel-4.18.0-372.9.1.el8/linux-4.18.0-372.9.1.el8.x86_64/net/ipv4/ip_output.c: 410
0xffffffff8cc7c780 <ip_output>: nopl   0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffff8cc7c785 <ip_output+5>:       push   %r12
0xffffffff8cc7c787 <ip_output+7>:       mov    %rsi,%r12
0xffffffff8cc7c78a <ip_output+10>:      push   %rbp
0xffffffff8cc7c78b <ip_output+11>:      mov    %rdi,%rbp
0xffffffff8cc7c78e <ip_output+14>:      push   %rbx
0xffffffff8cc7c78f <ip_output+15>:      mov    %rdx,%rbx
0xffffffff8cc7c792 <ip_output+18>:      sub    $0x38,%rsp
0xffffffff8cc7c796 <ip_output+22>:      mov    0x10(%rdx),%rsi
0xffffffff8cc7c79a <ip_output+26>:      mov    %gs:0x28,%rax
0xffffffff8cc7c7a3 <ip_output+35>:      mov    %rax,0x30(%rsp)
0xffffffff8cc7c7a8 <ip_output+40>:      xor    %eax,%eax
/usr/src/debug/kernel-4.18.0-372.9.1.el8/linux-4.18.0-372.9.1.el8.x86_64/./include/linux/skbuff.h: 1003
0xffffffff8cc7c7aa <ip_output+42>:      mov    0x58(%rdx),%rax
0xffffffff8cc7c7ae <ip_output+46>:      and    $0xfffffffffffffffe,%rax
0xffffffff8cc7c7b2 <ip_output+50>:      mov    (%rax),%rcx
/usr/src/debug/kernel-4.18.0-372.9.1.el8/linux-4.18.0-372.9.1.el8.x86_64/net/ipv4/ip_output.c: 413
-snip-

11.3 ソースファイルを表示する方法(-s)

-sはソースファイルを表示するオプションです。-sには、シンボル名もしくは仮想アドレスを指定します。

シンボル名としてip_outputを指定してみます。ip_output()のソースコードが表示されたことがわかります。

crash> dis -s ip_output
FILE: net/ipv4/ip_output.c
LINE: 410

  405                               ip_finish_output,
  406                               !(IPCB(skb)->flags & IPSKB_REROUTED));
  407   }
  408
  409   int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
* 410   {
  411           struct net_device *dev = skb_dst(skb)->dev, *indev = skb->dev;
  412
  413           IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
  414
  415           skb->dev = dev;
  416           skb->protocol = htons(ETH_P_IP);
  417
  418           return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
  419                               net, sk, skb, indev, dev,
  420                               ip_finish_output,
  421                               !(IPCB(skb)->flags & IPSKB_REROUTED));
  422   }

crash>

仮想アドレスとして0xffffffff8cc7c780を指定してみます。ip_output()のソースコードが表示されたことがわかります。

crash> dis -s 0xffffffff8cc7c780
FILE: net/ipv4/ip_output.c
LINE: 410

  405                               ip_finish_output,
  406                               !(IPCB(skb)->flags & IPSKB_REROUTED));
  407   }
  408
  409   int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
* 410   {
  411           struct net_device *dev = skb_dst(skb)->dev, *indev = skb->dev;
  412
  413           IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
  414
  415           skb->dev = dev;
  416           skb->protocol = htons(ETH_P_IP);
  417
  418           return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
  419                               net, sk, skb, indev, dev,
  420                               ip_finish_output,
  421                               !(IPCB(skb)->flags & IPSKB_REROUTED));
  422   }

crash>

12 taskコマンドの使い方

taskコマンドは、task_struct構造体の情報を表示するコマンドです。task_struct構造体は、プロセスの名前、PID、状態等を保持するデータ構造です。

12.1 task_struct構造体の中身を表示する方法

PIDを指定してtaskコマンドを実行すると、PIDで指定したプロセスのtask_struct構造体の中身を表示することができます。

psコマンドを実行して、rsyslogdプロセスのPIDを確認します。PIDが1077であることがわかります。

crash> ps rsyslogd
   PID    PPID  CPU       TASK        ST  %MEM     VSZ    RSS  COMM
   1077      1   2  ffff8f7fc37d5000  IN   0.1  215856   6804  rsyslogd

次に、rsyslogdのPIDを指定してtaskコマンドを実行します。

crash> task 1077
PID: 1077   TASK: ffff8f7fc37d5000  CPU: 2   COMMAND: "rsyslogd"
struct task_struct {
  thread_info = {
    flags = 128,
    status = 0
  },
-snip-

12.2 task_struct構造体のメンバの値を表示する方法(-R)

-Rは構造体のメンバの値を表示するオプションです。

rsyslogdのPIDを指定してtaskコマンドを実行します。このとき、-Rオプションにcommメンバ(プロセス名)を指定すると、プロセス名がrsyslogdであることがわかります。

crash> task 1077 -R comm
PID: 1077   TASK: ffff8f7fc37d5000  CPU: 2   COMMAND: "rsyslogd"
  comm = "rsyslogd\000)\000\000\000\000\000",

-Rオプションにpidメンバの値を指定すると、PIDが1077であることがわかります。

crash> task 1077 -R pid
PID: 1077   TASK: ffff8f7fc37d5000  CPU: 2   COMMAND: "rsyslogd"
  pid = 1077,

13 filesコマンドの使い方

filesコマンドは、プロセスがオープンしているファイルの情報を表示するコマンドです。

13.1 プロセスがオープンしているファイルの情報を表示する方法

PIDを指定して、rsyslogdがオープンしているファイルの情報を表示してみます。

crash> files 1077
PID: 1077   TASK: ffff8f7fc37d5000  CPU: 2   COMMAND: "rsyslogd"
ROOT: /    CWD: /
 FD       FILE            DENTRY           INODE       TYPE PATH
  0 ffff8f7fc4aaa000 ffff8f7fc040b0c0 ffff8f7fc0e9eae8 CHR  /dev/null
  1 ffff8f7fc554a800 ffff8f7fc040b0c0 ffff8f7fc0e9eae8 CHR  /dev/null
  2 ffff8f7fc554a800 ffff8f7fc040b0c0 ffff8f7fc0e9eae8 CHR  /dev/null
  3 ffff8f7fc397d600 ffff8f7fc040b300 ffff8f7fc0e9c688 CHR  /dev/urandom
  4 ffff8f7fc2c72200 ffff8f7fd29fae40 ffff8f7fd28758f0 SOCK UNIX
  5 ffff8f7fc3649600 ffff8f7fd29f9c00 ffff8f7fd2995a70 REG  /var/log/messages
  6 ffff8f7fc52e2700 ffff8f7fd29f9b40 ffff8f7fd29909b0 REG  /var/log/secure
  7 ffff8f7fc68b6600 ffff8f7fd2a09540 ffff8f7fc1409c30 UNKN inotify
  8 ffff8f7fc4ab7e00 ffff8f7fc4001cc0 ffff8f7fd2992ff0 REG  /var/log/cron
  9 ffff8f7fc68b6000 ffff8f7fc172cf00 ffff8f7fc637adf0 REG  /run/log/journal/971f5080a9c549438e6e9a21eeb90854/system.journal

13.2 プロセスがオープンしているファイルの情報を表示する方法

psコマンドを実行して、sshdプロセスのPIDを確認します。ここでは、PID1471 のsshdがオープンしているファイルの情報を表示してみます。

crash> ps sshd
   PID    PPID  CPU       TASK        ST  %MEM     VSZ    RSS  COMM
    842      1   2  ffff8f7fc2ec8000  IN   0.1   92408   7820  sshd
   1471    842   2  ffff8f7fc4ee5000  IN   0.2  153500  10352  sshd
   1488   1471   1  ffff8f7fc518d000  WA   0.1  153500   5908  sshd
   1512    842   1  ffff8f7fd15d8000  IN   0.2  153500  10528  sshd
   1516   1512   1  ffff8f7fc2c3d000  IN   0.1  153500   6100  sshd

-RオプションにSOCKを指定してfilesコマンドを実行すると、sshdが使用しているソケットが表示されることがわかります。

crash> files 1471 -R SOCK
PID: 1471   TASK: ffff8f7fc4ee5000  CPU: 2   COMMAND: "sshd"
ROOT: /    CWD: /
 FD       FILE            DENTRY           INODE       TYPE PATH
  5 ffff8f7fc4d11700 ffff8f7fd29600c0 ffff8f7fd28771b0 SOCK TCP
  6 ffff8f7fc62c3e00 ffff8f7fc43fda80 ffff8f7fc04210b0 SOCK UNIX
  7 ffff8f7fc3649300 ffff8f7fd29d6600 ffff8f7fd2851630 SOCK UNIX
  9 ffff8f7fc391eb00 ffff8f7fc43fd9c0 ffff8f7fc0421bb0 SOCK UNIX
 12 ffff8f7fc4dbe200 ffff8f7fd2a67c00 ffff8f7fc4211370 SOCK UNIX

-RオプションにTCPを指定してfilesコマンドを実行すると、sshdが使用しているTCPソケットが表示されることがわかります。

crash> files 1471 -R TCP
PID: 1471   TASK: ffff8f7fc4ee5000  CPU: 2   COMMAND: "sshd"
ROOT: /    CWD: /
 FD       FILE            DENTRY           INODE       TYPE PATH
  5 ffff8f7fc4d11700 ffff8f7fd29600c0 ffff8f7fd28771b0 SOCK TCP

14 fuserコマンドの使い方

fuserコマンドは、ファイルやソケットを使用しているプロセスの情報を表示するコマンドです。

/var/log/messagesを使用しているプロセスの情報を表示してみます。rsyslogd、in:imjournal、rs:mainの3つのプロセスが/var/log/messagesを使用していることがわかります。

crash> fuser /var/log/messages
 PID         TASK        COMM             USAGE
 1077  ffff8f7fc37d5000  "rsyslogd"       fd
 1123  ffff8f7fc2c38000  "in:imjournal"   fd
 1129  ffff8f7fc2c3a800  "rs:main Q:Reg"  fd

15 symコマンドの使い方

symコマンドは、シンボル情報を表示するコマンドです。

15.1 シンボル情報の一覧を表示する方法(-l)

シンボル情報の一覧を表示してみます。

crash> sym -l
0 (D) __per_cpu_start
0 (D) fixed_percpu_data
1000 (D) cpu_debug_store
2000 (D) irq_stack_backing_store
6000 (D) cpu_tss_rw
9000 (D) gdt_pag
-snip-

15.2 モジュールに含まれるシンボル情報を表示する方法(-s)

failoverモジュールに含まれるシンボル情報を表示してみます。

crash> sym -m failover
ffffffffc0339000 MODULE START: failover
ffffffffc0339000 (t) failover_unregister
ffffffffc0339090 (t) failover_get_bymac
ffffffffc0339120 (t) failover_slave_unregister
-snip-

15.3 特定の文字列を含むシンボル情報を表示する方法(-q)

ip_forwardという文字列を含むシンボル情報を表示してみます。

crash> sym -q ip_forward
ffffffff8c814490 (t) selinux_ip_forward
ffffffff8cc781f0 (t) ip_forward_finish
ffffffff8cc78280 (T) ip_forward
ffffffff8cc79b20 (T) ip_forward_options
ffffffff8cc79cb4 (t) ip_forward_options.cold.8

なお、小文字tはstatic宣言をした関数を表します。static宣言をすると、他のファイルから参照できなくなります。

static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)

一方、大文字Tはstatic宣言はしていないので、他のファイルから参照できます。

int ip_forward(struct sk_buff *skb)

15.4 シンボル情報の前後のシンボル情報を表示する方法(-p,-n)

ip_forwardの前にあるシンボル情報を表示してみます。ip_forwardの前にip_forward_finish が存在することがわかります。

crash>  sym -p ip_forward
ffffffff8cc781f0 (t) ip_forward_finish /usr/src/debug/kernel-4.18.0-372.9.1.el8/linux-4.18.0-372.9.1.el8.x86_64/net/ipv4/ip_forward.c: 66
ffffffff8cc78280 (T) ip_forward /usr/src/debug/kernel-4.18.0-372.9.1.el8/linux-4.18.0-372.9.1.el8.x86_64/net/ipv4/ip_forward.c: 87

ip_forwardの後にあるシンボル情報を表示してみます。ip_forwardの後にip_options_rcv_srr が存在することがわかります。

crash> sym -n ip_forward
ffffffff8cc78280 (T) ip_forward /usr/src/debug/kernel-4.18.0-372.9.1.el8/linux-4.18.0-372.9.1.el8.x86_64/net/ipv4/ip_forward.c: 87
ffffffff8cc786f0 (T) ip_options_rcv_srr /usr/src/debug/kernel-4.18.0-372.9.1.el8/linux-4.18.0-372.9.1.el8.x86_64/net/ipv4/ip_options.c: 616

16 listコマンドの使い方

listコマンドは、単方向リストにつながっている構造体の情報を表示するコマンドです。

16.1 単方向リストにつながれたノードの情報を表示する方法

単方向リストにつながっているfile_system_type構造体メンバの値を表示してみます。file_system_type構造体は、ファイルシステムの情報を保持するデータ構造です。以下のように、グローバル変数file_systemsが単方向リストの先頭要素を示すポインタで、各file_system_type構造体が単方向リストにつながっています。ここでは、リスト先頭から末尾まで、file_system_type構造体メンバ(name,fs_flag)の値を表示してみます。

                 ffffffff8e09a5c0    file_system_type{}                         file_system_type{}
file_systems --------------------> +--------------------+           +-------> +--------------------+
                                   |      *name         | -> sysfs  |         |      *name         | -> rootfs
                                   +--------------------+           |         +--------------------+
                                   |      fs_flags      | -> 8      |         |      fs_flags      | -> 0
                                   +--------------------+           |         +--------------------+
                                   |                    |           |         |                    |
                                   +--------------------+           |         +--------------------+
                                   |       *next        | ----------+         |       *next        | ----->
                                   +--------------------+                     +--------------------+
                                   |                    |                     |                    |
                                   |                    |                     |                    |
                                   +--------------------+                     +--------------------+

listコマンドを実行します。このとき-sオプションには、表示する構造体のメンバを指定します。ここでは、file_system_type構造体のnameとfs_flagsの値を指定しています。listコマンドの最後のパラメータには、リスト先頭のアドレスを指定します。実行結果を確認すると、リスト先頭がsysfs、その次がtmpfsであることがわかります。

crash> list file_system_type.next -s file_system_type.name,fs_flags ffffffff8e09a5c0
ffffffff8e09a5c0
  name = 0xffffffff8d534245 "sysfs"
  fs_flags = 8
ffffffff8e05abe0
  name = 0xffffffff8d55567f "tmpfs"
  fs_flags = 8
ffffffff8e086140
  name = 0xffffffff8d504698 "bdev"
  fs_flags = 0
ffffffff8e09a200
  name = 0xffffffff8d4eda8e "proc"
  fs_flags = 8
ffffffff8e0370a0
  name = 0xffffffff8d4fc855 "cgroup"
  fs_flags = 8
-snip-

16.2 双方向リストにつながれた構造体の情報を表示する方法

双方向リストにつながれたtask_struct構造体のcommメンバ(プロセスの名前)の値を表示してみます。

task_struct構造体は、プロセスの名前や状態等を保持するデータ構造です。以下のように、task_struct構造体は双方向リストにつながれています。先頭はinit_taskグローバル変数で参照することができます。ここでは、task_struct構造体のcommメンバを先頭から末尾まで表示してみます。

ffffffff8dc18840   task_struct{}                        task_struct{}
    init_task-> +----------------+                  +----------------+
                |     pid=0      |                  |     pid=1      |
                +----------------+                  +----------------+
                | comm=swapper/0 |                  |  comm=systemd  |
                +----------------+                  +----------------+
                |                |                  |                |
                |                |                  |                |
                |                |                  |                |
                |  list_head{}   |                  |   list_head{}  |
          -*-   +----------------+ <---+   +------> +----------------+
           |    |      *next     | ----|---+        |      *next     | ------->
         tasks  +----------------+     |            +----------------+
           |    |      *prev     |     +----------- |      *prev     |
          -*-   +----------------+                  +----------------+
                |                |                  |                |
                |                |                  |                |
                |                |                  |                |
                +----------------+                  +----------------+

whatisコマンドでinit_taskの型を調べると、init_taskはtask_struct構造体であることがわかります。

crash> whatis init_task
struct task_struct init_task;

init_task構造体の先頭アドレスを確認すると、0xffffffff8dc18840であることがわかります。

crash> rd init_task
ffffffff8dc18840:  0000000080004000                    .@......

listコマンドを実行します。このとき-hオプションには、双方向リスト先頭のアドレスを指定します。ここでは、双方向リスト先頭アドレスはffffffff8dc18840です。実行結果を確認すると、リスト先頭がswapper、その次がsystemdであることを確認することができます。

crash> list task_struct.tasks -s task_struct.comm -h ffffffff8dc18840
ffffffff8dc18840
  comm = "swapper/0\000\000\000\000\000\000"
ffff8f7fc0bad000
  comm = "systemd\000\060\000\000\000\000\000\000"
-snip-

17 treeコマンドの使い方

treeコマンドは、Radix treeやred-black treeにつながっている構造体の情報を表示するコマンドです。

17.1 確認に使うデータ

vmap_area構造体はメモリを管理するデータ構造です。以下のようにred-black treeにつながれています。"root"はrootノードを表しています。また、”l”はleft、"r"はrightを表しています。

                                                      (root)
                                                     vmap_area{}
                          ffff8f7fc0d30800 -> +---------------------+
                                              |    ulong va_start   |
                                              +---------------------+
                                              |    ulong va_end     |
                                              +---------------------+
                                              |                     |
                         rb_root{}            |                     |
                   +------------------+       |      rb_node{}      |
    vmap_area_root | ffff8f7fc0d30810 | ----> |+-------------------+|
                   +------------------+       || __rb_parent_color ||
                                              |+-------------------+|
                                              ||     *rb_right     ||-+
                                              |+-------------------+| |
                        (root/l)            +-||     *rb_left      || |         (root/r)
                        vmap_area{}         | |+-------------------+| |       vmap_area{}
 ffff8f7fc001e8c0->+---------------------+  | |                     | |  +---------------------+ <-ffff8f7fc7999c80
                   |                     |  | |                     | |  |                     |
                   |                     |  | |                     | |  |                     |
                   |                     |  | +---------------------+ |  |                     |
                   |                     |  | +---------------------+ |  |                     |
                   |     rb_node{}       |  |                         |  |     rb_node{}       |
                   |+-------------------+|<-+                         +->|+-------------------+|
                   || __rb_parent_color ||                               || __rb_parent_color ||
                   |+-------------------+|                               |+-------------------+|
                   ||     *rb_right     ||--+                            ||     *rb_right     ||--->
                   |+-------------------+|  |                            |+-------------------+|
                +--||     *rb_left      ||  |                        <---||     *rb_left      ||
                |  |+-------------------+|  |                            |+-------------------+|
  (root/l/l)    |  |                     |  |    (root/l/r)              |                     |
  vmap_area{}   |  |                     |  |    vmap_area{}             |                     |
+-------------+ |  +---------------------+  |  +-------------+           +---------------------+
|             | |                           |  |             |
|+-----------+|<+                           +->|+-----------+|
|| rb_node{} ||                                || rb_node{} ||
|+-----------+|                                |+-----------+|
|             |                                |             |
+-------------+                                +-------------+

17.2 各ノードの位置を求める方法(-p)

パラメータ 意味
-t ツリーのデータ構造を指定するオプションです。radix、xarray、rbtreeの3つを指定することができます。vmap_area構造体は、red-black treeにつながっているのでrbtreeを指定します
-o 左右ノードへのポインタを含むrb_node構造体メンバを指定するオプションです。なお、-oはrbtreeのみで指定できるオプションです
-p ノードの先頭アドレス、位置を表示するオプションです。位置とは(root/l)や(root/l/l)のことです。(root/l)はrootノードの一階層下の左側につながっている要素を表します。(root/l/l)はさらにもう一段下の左側につながっている要素を表します
crash> tree -t rbtree -o vmap_area.rb_node vmap_area_root -p
ffff8f7fc0d30800
  position: root
ffff8f7fc001e8c0
  position: root/l
ffff8f7fc001e740
  position: root/l/l
-snip-

17.3 各ノードのメンバの値を表示する方法(-s)

-sは各ノードのメンバの値を表示するオプションです。ここでは、vmap_area構造体のva_startメンバとva_endメンバの値を表示してみます。なお、-xは値を16進で表示するオプションです。-pはノードの位置を表示するオプションです。

crash> tree -t rbtree -o vmap_area.rb_node vmap_area_root -s vmap_area.va_start,va_end -xp
ffff8f7fc0d30800
  position: root
  va_start = 0xffff9f21809d0000
  va_end = 0xffff9f21809d5000
ffff8f7fc001e8c0
  position: root/l
  va_start = 0xffff9f21806e8000
  va_end = 0xffff9f21806ed000
ffff8f7fc001e740
  position: root/l/l
  va_start = 0xffff9f2180668000
  va_end = 0xffff9f218066d000
-snip-

18 swapコマンドの使い方

swapコマンドは、スワップバイスの情報を表示するコマンドです。

crash> swap
SWAP_INFO_STRUCT    TYPE       SIZE       USED     PCT  PRI  FILENAME
ffff8f7fc2af0000  PARTITION   262140k      0k       0%   -2  /dev/vda2

19 repeatコマンドの使い方

repeatコマンドは、files等のコマンドを繰り返し実行したり、各コマンドの実行間隔を指定した秒数だけ遅らせることができるコマンドです。なお、repeatコマンドは、動作中のカーネルに対して実行します。

引数なしでcrashコマンドを実行します。引数なしでcrashコマンドを実行すると、動作中のカーネルの状態を確認することができます。

[root@server ~]# crash

setコマンドを実行して、スクロールをオフにします。

crash> set scroll off
scroll: off (/usr/bin/less)

psコマンドを実行してchronydのPIDを求めます。chronydのPIDが505であることがわかります。

crash> ps chronyd
   PID    PPID  CPU       TASK        ST  %MEM     VSZ    RSS  COMM
    785      1   3  ffff940386265000  IN   0.1  149124   5248  chronyd

setコマンドを実行して、コンテキストをchronydに変更します。

crash> set 785
    PID: 785
COMMAND: "chronyd"
   TASK: ffff940386265000  [THREAD_INFO: ffff940386265000]
    CPU: 3
  STATE: TASK_INTERRUPTIBLE

chronydがオープンしているファイルを2秒間隔で監視します。

crash> repeat -2 files
PID: 785    TASK: ffff940386265000  CPU: 3   COMMAND: "chronyd"
ROOT: /    CWD: /
 FD       FILE            DENTRY           INODE       TYPE PATH
  0 ffff94038523a300 ffff94038040b600 ffff940380eaf0f8 CHR  /dev/null
  1 ffff94038523a200 ffff94038040b600 ffff940380eaf0f8 CHR  /dev/null
  2 ffff94038523ab00 ffff94038040b600 ffff940380eaf0f8 CHR  /dev/null
  3 ffff94038523a700 ffff94038a410cc0 ffff94038a43ec30 SOCK UNIX
  5 ffff940385d5e800 ffff940381423180 ffff94038a273430 REG  /var/lib/sss/mc/passwd
  6 ffff94038619ec00 ffff94038a566780 ffff940381740030 SOCK UDP
  7 ffff94038619ed00 ffff94038a566c00 ffff940381741e70 SOCK UDPv6
  8 ffff940381bc1b00 ffff94038a564600 ffff9403817f0870 SOCK UNIX
PID: 785    TASK: ffff940386265000  CPU: 3   COMMAND: "chronyd"
ROOT: /    CWD: /
 FD       FILE            DENTRY           INODE       TYPE PATH
  0 ffff94038523a300 ffff94038040b600 ffff940380eaf0f8 CHR  /dev/null
  1 ffff94038523a200 ffff94038040b600 ffff940380eaf0f8 CHR  /dev/null
  2 ffff94038523ab00 ffff94038040b600 ffff940380eaf0f8 CHR  /dev/null
  3 ffff94038523a700 ffff94038a410cc0 ffff94038a43ec30 SOCK UNIX
  5 ffff940385d5e800 ffff940381423180 ffff94038a273430 REG  /var/lib/sss/mc/passwd
  6 ffff94038619ec00 ffff94038a566780 ffff940381740030 SOCK UDP
  7 ffff94038619ed00 ffff94038a566c00 ffff940381741e70 SOCK UDPv6
  8 ffff940381bc1b00 ffff94038a564600 ffff9403817f0870 SOCK UNIX
-snip-

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ