1.記事一覧
記事は複数回に分けて投稿する予定です。AMD/XilinxのARM SoC(ZynqMP Kria K26 SOM)で動作する、AMD/Xilinx公式認定Ubuntuやベアメタル開発を勉強していく覚書きです。
ZynqMP(APU:Cortex-A53,Arm64) 組込みLinux入門編
- 【ZynqMP】1. 認定UbuntuでPLのGPIOを使う
- 【ZynqMP】2. 認定Ubuntuのカーネルビルド
- 【ZynqMP】3. 認定UbuntuのDeviceTree変更
- 【ZynqMP】4. 認定UbuntuでOpenAMPを試す【CR5Lockstep】
- 【ZynqMP】5. UARTでAMP【コア間通信】
- 【Linux】6. crash toolでカーネルメモリを見る
- 【Linux】6. 1.カーネルクラッシュダンプを取る←本記事
- 【Linux】6. 2.カーネルクラッシュダンプを見る
ZynqMP(RPU:Cortex-R5,Arm32) RPU入門編
2.crashでカーネルクラッシュダンプを調査【前編】
2-1. カーネルクラッシュダンプとは
Linuxを扱う上でかなり困る不具合の一つが、「たまにOSがフリーズする(またはpanicする)が、原因の検討がつかない」という状況です。聞いただけでもあまり関わりたくないと思うくらい面倒そうな状況です。
よく知られる方法で、アプリケーションプロセスが何らかの致命的なエラー(Busfault、SEGV)などを起こして強制終了する際、コアダンプ(coredump)というCPUレジスタや、プロセス、メモリ情報を記録したファイルを保存したファイルを生成できます。それをあとでGDBに読み込ませると、エラーを起こした瞬間のスタックトレースを得られます。それをソースコードと突き合わせて原因の箇所を特定できます。
コアダンプはプロセス単位のダンプ情報ですが、Linuxカーネルが管理するメモリ範囲をまるごとダンプできる仕組みがあります。それがカーネルクラッシュダンプです。
Linuxカーネルが動作を継続するのが極めて困難な場合に陥った状態をカーネルパニック(panic)と呼びます。障害情報を収集するクラッシュカーネルを予約メモリ領域にあらかじめ展開しておき、panic時にメインカーネルからクラッシュカーネルに実行が遷移して、メインカーネルのダンプ情報を生成して、ファイルシステムに保存します。
カーネルクラッシュダンプファイルは前回使用したcrashツールで解析できます。ただし、クラッシュした原因のヒントがある可能性があるだけで原因が判明するとは限らないそうです。カーネルクラッシュはできれば遭遇したくないですが、もしものときのためにやり方を練習してみようと思います。
2-2. カーネルクラッシュダンプ解析チュートリアル【前編】
チュートリアルとして、意図的にクラッシュを起こしてpanicさせ、カーネルクラッシュダンプを取得するとこまでを前半としたいと思います。次回の記事でカーネルクラッシュダンプをcrashツールに読み込ませていろいろ見てみることにします。
途中の過程でカーネルをクラッシュさせるので、やる方はバックアップ取りましょう。
目次:前編
- Linux-crashdumpパッケージの準備
- bootargs(KERNEL_CMDLINE)にクラッシュカーネル用のメモリ予約領域を設定する
- Sysrqで意図的にカーネルパニックを発生させクラッシュさせる
- カーネルクラッシュダンプファイルが生成されたことを確認
目次:次回後編
- crashでカーネルクラッシュダンプファイルを読み込む
- crash : bt(backtrace)でpanic発生箇所をさぐる
- crash : disでクラッシュ箇所の逆アセンブル
- 逆アセンブルだけでなくソースコードを表示したいとき
- crash : dis -sでクラッシュ箇所のソースコード表示
この記事の内容はgihyo.jpの柴田充也氏の記事とその他の参考資料を元にやっていきます。
- 第673回カーネルのクラッシュ情報を取得する:gihyo.jp 柴田充也氏
- 第674回カーネルのクラッシュ情報を解析する:gihyo.jp 柴田充也氏
- Ubuntu Server documentation Kernel crash dump
- カーネルクラッシュダンプ (Kdump) の概要と設定方法:Qiita:@Kernel_OGSun氏
- カーネルクラッシュダンプの解析方法:Qiita:@Kernel_OGSun氏
gihyoの記事はx86環境のため、環境準備はUbuntuの公式Docを見て情報を補います。Qiitaの記事も良記事ですが、OSがRHEL x86環境のため、こちらも適宜情報補完用に参考にしました。
開発ツール | VSCode(Remote-SSH) |
ターゲットOS | Xilinx認定Ubuntu22.04 Linux Kernel : 5.15.0-1031-xilinx-zynqmp |
ターゲットボード(インターネット接続必要) | Xilinx社製 Kria KR260 ロボティクススターターキット(SK-KR260-G) SOM : Xilinx社 Kria K26 SOM (Zynq UltraScale+ MPSoCベース) APU : Arm CA53x4 1333MHz arm64 RPU : Arm CR5x2 533MHz armv7-R SDRAM : DDR4 4GB |
3.環境準備
3-1. linux-crashdumpのセットアップ
Ubuntuでパッケージが用意されているので、インストールでほぼセットアップ出来ます。
$ sudo apt install linux-crashdump
途中設定を聞かれます。
「このオプションを選択すると、システムを再起動すると、システムブートローダのプロセス全体を経ることなく、kexecによってロードされたカーネルで再起動されます。kexec-toolsは再起動を処理すべきでしょうか?(機械翻訳)」
カーネルクラッシュダンプ取得後に自動再起動するのですが、kexecと呼ばれるクラッシュカーネルを起動する仕組みがそのまま、メインカーネルをロードして起動するか(Yes)、FSBLから起動し直すか(No)の選択になります。
ハードウェアを初期化してほしい場合が多いケースだと思うのでNoを選択します。
この設定は後から変更可能です。
“/etc/default/kexec”の以下を変更します。
LOAD_KEXEC
$ cat /etc/default/kexec
(...)
# Load a kexec kernel (true/false)
LOAD_KEXEC=false
(...)
続いての設定です。
「このオプションを選択すると、kdump-tools メカニズムが有効になります。クラッシュカーネルカーネルパラメータを有効にするには、再起動が必要です。kdump-tools をデフォルトで有効にしますか?」
クラッシュダンプを取得するために有効(Yes)にします。
この設定は後から変更可能です。
“/etc/default/kdump-tools”
USE_KDUMP
$ cat /etc/default/kdump-tools
# kdump-tools configuration
# ---------------------------------------------------------------------------
# USE_KDUMP - controls kdump will be configured
# 0 - kdump kernel will not be loaded
# 1 - kdump kernel will be loaded and kdump is configured
#
USE_KDUMP=1
(...)
3-2. bootargsでクラッシュカーネル用の予約メモリを設定
bootargsを更新します。bootargsの変更方法は以前の記事「【ZynqMP】3.認定UbuntuのDeviceTree変更」でやっています。変更したら必ず再起動が必要です。
今回は以下のように書き換えます。
$ cat /etc/default/flash-kernel
LINUX_KERNEL_CMDLINE="crashkernel=2G-:192M"
LINUX_KERNEL_CMDLINE_DEFAULTS=""
$ sudo flash-kernel
“crashkernel=2G-:192M”の意味はメインメモリが2GB以上ならば、192MBのクラッシュカーネルのメモリ領域を確保、です。2GB未満なら確保しません。
crashkernel=<memory min size>-<memory max size(省略可)>:<crash kernel size>
上記のようにメインメモリの容量で条件を分けることが出来ます。
今回のKria k26 SOM DDR4=4GBの環境では、クラッシュカーネル用に192MB程度の領域が必要でした。ちなみに168MB以下ではダンプ失敗の確認をしています。この領域はLinux管理外の領域になるため、単純に有効メモリ容量が減ります(3.6GB程度に減る)。4GBに対して200MBは少なくない容量のため、実際に使うかは状況によると思います。
設定できたら再起動を行います。
dmesgで確保できているか確認します。出来ているようです。
$ sudo dmesg |grep crash
[ 0.000000] crashkernel reserved: 0x000000002b400000 - 0x0000000037400000 (192 MB)
[ 0.000000] Kernel command line: root=LABEL=writable rootwait earlycon console=ttyPS1,115200 console=tty1 clk_ignore_unused uio_pdrv_genirq.of_id=generic-uio xilinx_tsn_ep.st_pcp=4 cma=1000M crashkernel=2G-:192M
カーネルクラッシュダンプが有効になっているか確認します。
$ kdump-config show
DUMP_MODE: kdump
USE_KDUMP: 1
KDUMP_COREDIR: /var/crash
crashkernel addr: 0x
/var/lib/kdump/vmlinuz: symbolic link to /boot/vmlinuz-5.15.0-1031-xilinx-zynqmp
kdump initrd:
/var/lib/kdump/initrd.img: symbolic link to /var/lib/kdump/initrd.img-5.15.0-1031-xilinx-zynqmp
current state: ready to kdump
kexec command:
/sbin/kexec -p --command-line=" root=LABEL=writable rootwait earlycon console=ttyPS1,115200 console=tty1 clk_ignore_unused uio_pdrv_genirq.of_id=generic-uio xilinx_tsn_ep.st_pcp=4 cma=1000M reset_devices systemd.unit=kdump-tools-dump.service nr_cpus=1" --initrd=/var/lib/kdump/initrd.img /var/lib/kdump/vmlinuz
“current state: ready to kdump”であれば有効になっています。また、”KDUMP_COREDIR:”のpathがカーネルクラッシュダンプファイルの保存先になっています。デフォルトは”/var/crash”です。
4.カーネルクラッシュダンプを取得する
4-1. SysRQによる強制クラッシュの実行
SysRQ(Magic System Request Key)とはLinuxが何らかの障害でShellの入力が出来ない状況でカーネルに割込みを発生させて特定の動作をさせる機能らしいです。
magic SysRq keyについて:MIRACLE Linux
SysRQにカーネルパニックを強制実行する機能があります。今回はそれを実行してダンプを取得できるか確認します。
当然ですが、念の為バックアップをとっておきましょう。
まず、SysRQを有効にします。
#SysRQを有効にする
$ sudo sysctl -w kernel.sysrq=1
kernel.sysrq = 1
#有効になったか確認
$ cat /proc/sys/kernel/sysrq
1
続いて、クラッシュを起こすのですが、その前にカーネルメッセージが見えたほうがうまく行かないときの原因究明に役立つので、シリアルコンソールに切り替えます。KR260ボードの場合、USB-JTAGと共用されているUARTはデフォルトでシリアルコンソールに設定されているので、そちらでログインします。
私は母艦PCはUbuntuのため、TeratermではなくCuteComを使用しています。ちょっと癖がありますが、通信ログを設定で残せるのでこれを使っています。
クラッシュを実行します。
$ sudo -s
root# echo c > /proc/sysrq-trigger
クラッシュを実行すると即Kernel panicします。その後クラッシュカーネルが起動し、ダンプを取得した後、再起動でFSBLから起動し直されます。
#ログ
root@kria:/home/ubuntu# echo c > /proc/sysrq-trigger
[ 2426.813967] sysrq: Trigger a crash
[ 2426.820550] Kernel panic - not syncing: sysrq triggered crash <カーネルパニック!
[ 2426.826288] CPU: 3 PID: 9779 Comm: bash Kdump: loaded Tainted: G C 5.15.0-1031-xilinx-zynqmp #35-Ubuntu
[ 2426.836970] Hardware name: ZynqMP KR260 revB (DT)
[ 2426.841659] Call trace:
[ 2426.844088] dump_backtrace+0x0/0x200
[ 2426.847743] show_stack+0x20/0x30
[ 2426.851049] dump_stack_lvl+0x68/0x84
[ 2426.854703] dump_stack+0x18/0x34
[ 2426.858011] panic+0x16c/0x35c
[ 2426.861057] sysrq_reset_seq_param_set+0x0/0x9c
[ 2426.865580] __handle_sysrq+0x90/0x1a0
[ 2426.869321] write_sysrq_trigger+0xbc/0x1a0
[ 2426.873496] proc_reg_write+0xb0/0x10c
[ 2426.877237] vfs_write+0xf8/0x2cc
[ 2426.880544] ksys_write+0x70/0x100
[ 2426.883938] __arm64_sys_write+0x24/0x30
[ 2426.887853] invoke_syscall+0x78/0x100
[ 2426.891594] el0_svc_common.constprop.0+0x54/0x184
[ 2426.896377] do_el0_svc+0x30/0xac
[ 2426.899684] el0_svc+0x28/0xb0
[ 2426.902730] el0t_64_sync_handler+0xa4/0x12c
[ 2426.906992] el0t_64_sync+0x1a4/0x1a8
[ 2426.910654] SMP: stopping secondary CPUs
[ 2426.914669] Starting crashdump kernel...
[ 2426.918582] Bye! <ーここからクラッシュカーネルが起動する
[ 0.000000] Booting Linux on physical CPU 0x0000000003 [0x410fd034]
[ 0.000000] Linux version 5.15.0-1031-xilinx-zynqmp (buildd@bos03-arm64-030) (gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #35-Ubuntu SMP Fri Jun 14 02:59:36 UTC 2024 (Ubuntu 5.15.0-1031.35-xilinx-zynqmp 5.15.152)
[ 0.000000] Machine model: ZynqMP KR260 revB
[ 0.000000] efi: UEFI not found.
(...)
[ 19.624926] systemd[1]: Started Journal Service.
[ 19.820471] systemd-journald[471]: Received client request to flush runtime journal.
[ 67.164737] reboot: Restarting system <ーダンプ取得完了。再起動
Zynq MP First Stage Boot Loader
Release 2023.2 Mar 18 2024 - 06:43:04
MultiBootOffset: 0x40
Reset Mode : System Reset
Platform: Silicon (4.0), Running on A53-0 (64-bit) Processor, Device Name: XCZUUNKNEG
QSPI 32 bit Boot Mode
FlashID=0x20 0xBB 0x20
PMU Firmware 2023.2 Mar 18 2024 06:43:04
(...)
Ubuntu 22.04.4 LTS kria ttyPS1
kria login:
うまく行けば再起動まで完了します。途中でメッセージが止まるようであれば、クラッシュカーネル用の予約メモリ容量が少なすぎる可能性があります。
4-2. クラッシュダンプファイル生成の確認
ダンプファイルは”/var/crash/”にあります。
$ ls /var/crash/
202408290941 kdump_lock kexec_cmd linux-image-5.15.0-1031-xilinx-zynqmp-202408290941.crash
$ ls /var/crash/202408290941/
dmesg.202408290941 dump.202408290941
日時が名前のフォルダが作成され、”dump.YYYYMMDDHHMM”のファイルがカーネルクラッシュダンプファイルになります。
ちなみに、”dmesg.YYYYMMDDHHMM”はその名の通りdmesgのログです。
5.最後に
今回はカーネルクラッシュダンプ解析のチュートリアル前編をやってみました。Ubuntu公式のドキュメントがしっかりしているのと、Xilinx認定Ubuntuだけあってパッケージも用意されていることからあまり困ることはありませんでした。
強いて言えば、bootargsのクラッシュカーネルのメモリ容量がドキュメントだと128MBを指定していたので、その値をそのまま使ったのですが、ダンプが生成されず困りました。海外のサイトで、メモリ容量は最初は十分大きいサイズを指定してから、徐々に減らしていって動作するか確認すると良いと記述があり、とりあえず2倍の256MBにしたらダンプが生成されたというエビソードがありました。
シリアルコンソールのbootメッセージも途中で止まるのが見えるので、可視化の手間を惜しまないのも大切だと思います。メモリ量によって、bootメッセージの止まる位置が変わるので、メモリ枯渇の瞬間が確実にわかります。
次回は後編です。クラッシュダンプをcrashツールで覗いてみます。