core (2)
new machine
数度にわたってOpenBSDのKERNELのcoreをみたくて、いろいろやってるけど成功していない。 dumpエリアが不足って仮定をした。
で、最初から十分なdumpエリアを確保すべく、新規マシンを用意する事にした。とはいえWindows10のHDDも不足ぎみ。で、ばっさりVMWAREで動かしているOpenBSD(64Bit)を削除する事にした。
度重なるsysupgradeで、仮想HDDが肥大化してるんだ。だからこのOSを削除して、一時的に32BitのOpenBSDをいれる事にした。実験が終わる頃7.2が出るはずだから、そうしたら64Bit版を新規に入れればよい。
仮想シリアルの設定。 起動時に接続のチェックボックスをON、 名前パイプのラジオボタンで、名前は、 \\.\pipe\mypipename サーバーです 接続先はアプリですを指定。
ob$ df -h Filesystem Size Used Avail Capacity Mounted on /dev/wd0a 7.8G 3.1G 4.3G 41% / mfs:55960 495M 4.0K 470M 0% /tmp ob$ swapctl -kl Device 1K-blocks Used Avail Capacity Priority /dev/wd0b 4188960 0 4188960 0% 0
雑に言うと12Gの仮想DISKを用意してルートに8G、スワップに4Gと言う構成。 メモリーは1G割当てで、その半分がRAMーDISKと言うスモール構成。それでもi386でMPなマシンだ。
Xは仮想では動かないので入れていない。大事なソースとポーツは一式tarで固めてvirtualBox側からもってきた。後は、 gdb,emacs-no_x11,w3m,bash
を入れただけ。
ttys,rc.conf.local,boot.conf,sysctl.conf,fstab,installurlをcpしてから多少編集。 .bashrc,.emacs.d,.profile,.tmux.conf,.w3mもcpしてきた。これで既存の32Bitマシンとそっくりさんが出来上がった。違うのは、パーテションの切りかただけだ。
coredumpの実験
ob# inddb Stopped at db_enter+0x4: popl %ebp ddb{0}> call panic panic: uvm_fault(0xd3633960, 0x0, 0, 1) -> e Stopped at db_enter+0x4: popl %ebp TID PID UID PRFLAGS PFLAGS CPU COMMAND *499159 58620 0 0x3 0 0K sysctl db_enter() at db_enter+0x4 : ddb{0}> boot crash dumping to dev 1, offset 6283071 dump 1021 1020 1019 ... 6 5 4 3 2 1 0 succeeded rebooting... >> OpenBSD/i386 BOOT 3.44 boot> booting hd0a:/bsd: 10431259+2479108+245780+0+1130496 [708146+107+587008+631014]=0xf786c4 entry point at 0x201000 [ using 1926852 bytes of bsd ELF symbol table ] : starting RPC daemons:. savecore: no core dump checking quotas: done. :
1Gのメモリーを割当てたので、それだけ分をDUMPしたって事だな。ちゃんと成功してる。それにもかかわらず、savecoreで回収していない。
DUMP先は、仮想HDDの後ろの方なんで、VMWAREの分割されたHDDに変化があるかと思ったけど、痕跡すら見付られず。
話半分メモリーも半分
上記でcoreを作ってる(と思われる)案内の所が1021からカウントダウンして、最後は成功で終ってる。前回は成功してなかったので、少しは進歩したな。
で、1021って搭載メモリーを表しているはずなんだけど、本当か? 本来ならgdbで監査したい所なんだけど、それは不可能。なら、搭載メモリーを半分にしてみるか。仮想PCだと簡単にそういう事が出来るので嬉しい。
ddb{0}> boot crash dumping to dev 1, offset 7331647 dump 509 508 507 506 ... 4 3 2 1 0 succeeded : starting network starting early daemons: syslogd. starting RPC daemons:. savecore: no core dump checking quotas: done.
やっぱりメモリー依存性が確認出来た。だからスワップエリアは最低でもメモリー容量以上は欲しいという要求なんだな。
/etc/rc
# /var/crash should be a directory or a symbolic link to the crash directory # if core dumps are to be saved. if [[ -d /var/crash ]]; then savecore $savecore_flags /var/crash fi
savecoreを起動してる部分。
ob# savecore -v /var/crash dumpoff = 4022238720 (7855935 * 512) savecore: /bsd: kvm_dump_mkheader: invalid magic in cpu_hdr savecore: no core dump
これを見ると保存場所を指定して実行してる。更に詳しく -v も付けてみた。けど、肝心のdumpが無いから、そんなのやり様がないと言う結果だ。
dump on ddb
だったらddb上で直接 dumpsys(void) を呼出たらどうよ。
call dumpsys
なにかVMWAREだとハングするなあ。VMWAREを強制STOPしないとOSが終了しない。で、次回は起動出来無い。メモリーサイズ分のファイルが出来てる。強制的にタスクを殺す。メモリー相当分のファイルが残っていると、再起動出来無い。その憎らしいファイルをWindowsを再起動しないと削除出来無い。踏んだり蹴ったり。
qemu README-main
舞台を再びVirtualBOXに移す。問題はメモリーをどれだけ少く出来るかだ。133M以内だな。
qemuに面白い解説が出てた。
2. Create a virtual disk image: $ qemu-img create -f qcow2 virtual.img 10G 3. Install the OS: $ qemu-system-i386 -m 32 -monitor stdio -no-fd-bootchk \ -hda virtual.img -cdrom cd70.iso -boot d 5. Boot normally from the virtual disk: $ qemu-system-i386 -m 32 -nographic -no-fd-bootchk -hda virtual.img
32MあればOpenBSDは動くのか。だったら、精一杯頑張って、96Mぐらいのメモリー割当てでいいかな。まあ、やってみるべ。
新しいOpenBSDが降ってきたら、qemuでも入れて、そこでやってみるかな。
coredump in small memory
で、96Mのメモリーを割り付けて起動。無事に動いたので、早速実験。
vbox# inddb Stopped at db_enter+0x4: popl %ebp ddb{0}> call panic panic: uvm_fault(0xd17581e0, 0x0, 0, 1) -> e Stopped at db_enter+0x4: popl %ebp TID PID UID PRFLAGS PFLAGS CPU COMMAND * 52383 74121 0 0x3 0 0K sysctl : ddb{0}> boot crash dumping to dev 1, offset 76560 dump 94 93 92 91 90 ... 3 2 1 0 succeeded : avecore: reboot after panic: uvm_fault(0xd17581e0, 0x0, 0, 1) -> e savecore: system went down at Wed Sep 28 16:16:23 2022 savecore: writing core to /var/crash/bsd.6.core savecore: writing kernel to /var/crash/bsd.6 :
今度はdumpのステータスが成功ってなってる。まあ、成功か失敗かなんてVGAのコンソールじゃ結果が流れてしまって見られない。オイラーみたいにシリアルの設定をしてTeraTermで接続。それのバックログを見るなんて事をしないと無理だろな。こういう工夫が楽しいんだ。
box# ls -l /var/crash total 528968 -rw------- 1 root wheel 2 Sep 28 16:17 bounds -rw------- 1 root wheel 15093330 Sep 20 16:04 bsd.0 -rw------- 1 root wheel 139792916 Sep 20 16:04 bsd.0.core -rw------- 1 root wheel 15093330 Sep 28 16:17 bsd.6 -rw------- 1 root wheel 100598292 Sep 28 16:17 bsd.6.core -rw-r--r-- 1 root wheel 5 May 8 2020 minfree
そして、死体安置所での保存状況。今度はオーバーフローしないで、ちゃんと収まっているな。
そして注目の検死確認。
vbox# fuser -N bsd.6 -M bsd.6.core -f /home/sakae /home/sakae: 57788c
文句も言われずにちゃんと確認出来た。いやー長い道程だったなあ。
vbox# ps -N bsd.6 -M bsd.6.core -O paddr PID PADDR TT STAT TIME COMMAND 50259 d16c8b18 00 Ip 0:00.06 (ksh) 74121 d16c800c 00 RK+U 0:00.00 (sysctl) 99968 d16c865c C0 S+pU 0:00.02 (getty)
検死の指南書 by crash(8)
The -O paddr option prints each process' struct proc address. This is very useful information if you are analyzing process contexts in gdb(1).
メモリーが不足したような場合、何が大判振舞してるか、こんなコマンドで確認しろとな。
vbox# vmstat -N bsd.6 -M bsd.6.core -m Memory statistics by bucket size Size In Use Free Requests HighWater Couldfree 16 456 56 1151 1280 0 32 1565 99 3027 640 0 64 2474 534 13863 320 189 : Memory usage type by bucket size Size Type(s) 16 devbuf, pcb, rtable, ifaddr, dirhash, ACPI, proc, in_multi, exec, VM swap, UVM amap, UVM aobj, USB, USB device, temp 32 devbuf, rtable, ifaddr, vnodes, UFS mount, sem, dirhash, ACPI, proc, ether_multi, VM swap, UVM amap, USB, USB device, NDP, temp :
汎用のgdbを取出してみる。
vbox# gdb (gdb) file /var/crash/bsd.6 Reading symbols from /var/crash/bsd.6...(no debugging symbols found)...done. (gdb) target kvm /var/crash/bsd.6.core #0 0xd03d521e in boot () (gdb) bt #0 0xd03d521e in boot () #1 0xd028d899 in reboot () #2 0xd036dc86 in db_reboot () #3 0xd036d86d in db_boot_crash_cmd () #4 0xd036cf23 in db_command () #5 0xd036dbbe in db_command_loop () #6 0xd091fd1f in db_trap () #7 0xd082494f in db_ktrap () #8 0xd0489975 in trap () #9 0xd03b5fb5 in calltrap () #10 0xd0824e84 in db_enter ()
残念ながら、debug情報が落ちているので、詳細を追求はオイラーの腕では無理だ。だって嫌いな石とまともに対面する必要が有りますからね。
カーネルへの live patch
coredumpに関連するソースを見ていると、dumpdevってのが頻出してる。何処で元ネタが定義されるかな? conf/swapgeneric.c
dev_t rootdev = NODEV; dev_t dumpdev = NODEV; struct swdevt swdevt[] = { { NODEV, 0 }, /* to be filled in */ { NODEV, 0 } };
dev_t
て最もらしい型名が付いているけど単なる32Bitの整数。で、いきなりこの名前が出て來るって事は、グローバル変数だな。ならば、どのアドレスが所在地か?
vbox# nm bsd.6 | grep dumpdev d0e8d750 D dumpdev
本当は生きているカーネルから探るのが筋だけど、それをやると怒られてしまうので、おあつらえむきなコピーから採取。
で、どんな風にデバイスを表現してる?
box# ls -l /dev/wd0* brw-r----- 1 root operator 0, 0 Apr 25 14:05 /dev/wd0a brw-r----- 1 root operator 0, 1 Sep 28 16:17 /dev/wd0b : vbox# ls -l /dev/wd2* brw-r----- 1 root operator 0, 32 Apr 25 14:05 /dev/wd2a brw-r----- 1 root operator 0, 33 Sep 30 07:35 /dev/wd2b : brw-r----- 1 root operator 0, 46 Apr 25 14:05 /dev/wd2o brw-r----- 1 root operator 0, 47 Apr 25 14:05 /dev/wd2p
デバイスはメジャーとマイナーの組み合わせで表現されてた。で、マイナー番号がパーテションに対応されてるのね。
dump
ddbに落ちて、デバイスを wd0b から wd2b に変更してみる。
db{0}> x dumpdev dumpdev: 1 ddb{0}> w dumpdev 0x21 dumpdev 1 = 21 ddb{0}> pp dumpdev dumpdev: 0x21
こうしておいて、dumpさせる。
ddb{0}> boot crash dumping to dev 21, offset 8 dump 132 131 130 ... 3 2 1 0 4095 4094 ... 3847 3846 succeeded rebooting... : savecore: no core dump checking quotas: done.
どうやら、wd0bはデフォで使われて、足りない分はwd2bにスイッチされてると思われる。 再起動後はデバイス番号が元に戻ってしまうので、savecoreは発動していないっぽい。
強制 savecore
vbox# inddb Stopped at db_enter+0x4: popl %ebp ddb{0}> pp dumpdev dumpdev: 0x1 ddb{0}> w dumpdev 0x21 dumpdev 1 = 21 ddb{0}> c ddb.trigger: 0 -> 1 vbox# savecore -v /var/crash dumpoff = 4096 (8 * 512) savecore: reboot savecore: system went down at Fri Sep 30 07:21:23 2022 savecore: writing core to /var/crash/bsd.7.core savecore: writing kernel to /var/crash/bsd.7
ならば再びddbに落ちてデバイスを再設定。それから手動でsavecoreを実施。
一見成功したように見えるかどwd0b相当しかsavecoreしてるぞ。オーバーフロー分(memoryは384Mを割当てている)は無視されてるな。
vbox# ls -l /var/crash total 831752 -rw------- 1 root wheel 2 Sep 30 07:35 bounds -rw------- 1 root wheel 15093330 Sep 20 16:04 bsd.0 -rw------- 1 root wheel 139792916 Sep 20 16:04 bsd.0.core -rw------- 1 root wheel 15093330 Sep 28 16:17 bsd.6 -rw------- 1 root wheel 100598292 Sep 28 16:17 bsd.6.core -rw------- 1 root wheel 15093330 Sep 30 07:35 bsd.7 -rw------- 1 root wheel 139792916 Sep 30 07:35 bsd.7.core -rw-r--r-- 1 root wheel 5 May 8 2020 minfree vbox# cd /var/crash/ vbox# pstat -N bsd.7 -M bsd.7.core -T 71/7030 files 1524 vnodes 0M/5253M swap space vbox# fstat -N bsd.7 -M bsd.7.core fstat: can't read process at f53e2c38
試しに、検死してみると、動いたり動かなかったりだ。 ちゃんとしたcoredumpを取得したかったら、最初からそういう環境を作っておけって事ですな。
dumpon
FreeBSDには、ちゃんとそれ用のコマンドが用意されてる。
root@fbox:~ # dumpon -l ada0s1b
マニュアルをつらつら読むと、ネットワークを経由したdumpをするのが主目的と思われる。 人材が豊富だと、こういう所にも手を出せるのか。羨しいな。
Starting in FreeBSD 13.0, dumpon can configure a series of fallback dump devices. For example, an administrator may prefer netdump(4) by default, but if the netdump(4) service cannot be reached or some other failure occurs, they might choose a local disk dump as a second choice option.