kgdb in openbsd

連休で暇なんで、近くの露天風呂へ行ってきた。地元の人しか知らないような隠れ湯。 山の中なんで、まだ桜が咲いていて、その花びらが湯に落ちてきて、風情がありましたよ。

ゆったり日向ぼっこしてた老人と目が合ってしまったので、一期一会と思って話しかけて みたぞ。隣の村からひと山超えてやってきたとの事。よく来てるそうだ。

今の季節、山菜いいですねぇって始まった、山菜談義。山菜の王様はなんだ? こしあぶら? タラの芽?やまうど? 出るわ出るは、いろんな名前のやつが。やがて、蕎麦の話になり、 きのこの話に、とりとめもなく続く。

おかげで、すっかり日焼け。こんな山の中でも紫外線が強いので強力に焼けたよ。 こんな日焼け、若い頃の山スキー以来だな。この時期、山形の月山でずっとスキーしてた ものね。

たまにはいいね。見ず知らずの人とのんびり会話するのも。世間では、マストドンなんてのが 大盛り上がりみたいで、 Mastodon(マストドン)とか、 Mastodonを楽しく歩こう なんてのも始まったみたいだけど、やっぱりフェースツーフェスが一番だと思うぞ。 (こんな事を書くようになっちゃ、爺の証拠だわな)

で、まだ連休が続いていたので、CQ出版から出てる、インターフェースなんて雑誌を、 本当に久しぶりに買ってみた。

新科学計算ソフトウルトラ大集合、ですって。やっぱりPythonとRが鉄板だな。そして パソコンを使えない若者が好む、スマホ向けも、その手のやつが大分有るようだ。

手書きで数式を入力すると、その式を元にグラフを書いてくれるやつが有るそうだ。 無料なんで試して、若者気分を味わってみるかな。

どこもかしこも、pythonで、 Python 3の組み込み関数を速攻理解しようなんてのも続いている。

kgdb for qemu-kvm

前回の続きで、CentOSにqemu-kvmを突っ込み、ゲストOSとしてOpenBSDを入れて、 ごにょごにょやってる。OpenBSDのカーネル観光の土台作り。

DDBとKGDBは排他になってるので、DDBの方を殺して、KGDBが有効になったカーネルを作る。 下記は、その設定の抜粋。(includeしてるGENERICの方でDDB宣言を無効にしとく事)

makeoptions DEBUG="-g"

#option         DDB             # in-kernel debugger
#option         DDB_SAFE_CONSOLE # allow break into ddb during boot

option         KGDB            # Remote debugger support; exclusive of DDB
option         "KGDB_DEVNAME=\"com\"",KGDBADDR=0x2f8,KGDBRATE=9600

そして、起動時に十分にbootオプション(debuggerに落ちるなら、-d)を入力する時間を 与えるため、設定をする。

# cat /etc/boot.conf
set timeout 120

それから、qemuにシリアルラインを生やすため、-serial ptyを追加した、起動コマンドを 用意しる。

[cent tmp]$ cat com
/usr/libexec/qemu-kvm  -m 256M -net nic -net user -s \
  -redir tcp:2022::22 -serial pty disk &
sleep 2
vncviewer localhost:5900

これで起動すると、下記のように、/dev/pts/4がそのシリアルだと教えてくれる。

[cent tmp]$ ./com
char device redirected to /dev/pts/4 (label serial0)
VNC server running on `::1:5900'
 :

やおら、gdbを起動して、シリアルで接続するも、無しのつぶて。

[cent DEBUG]$ gdb -q bsd.gdb
Reading symbols from bsd.gdb...done.
(gdb) set serial baud 9600
(gdb) target remote /dev/pts/4
Remote debugging using /dev/pts/4
Ignoring packet error, continuing...
warning: unrecognized item "timeout" in "qSupported" response
Ignoring packet error, continuing...
Remote replied unexpectedly to 'vMustReplyEmpty': timeout

ネットを彷徨うと、こんなのもあったけど、やはりkgdbとは接続出来ず。 kgdb waiting ... と、OpenBSD側にメッセージが出たままになる。

(gdb) set architecture i386:x86-64:intel
(gdb) target remote | exec /usr/libexec/qemu-kvm -gdb stdio

で、ふと、dmesgを見てたら、カーネルのkgdb受付用ポートと、ハード?側に用意された ポートのアドレスが違う事に気付いてしまった。

$ dmesg
com0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo

これはもう、kgdbのポートを変更する鹿。変更後のdmesgでは、com0がkgdb用に割り当てられたって確認出来た。

com0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo
com0: kgdb

でも、相変わらず

[cent DEBUG]$ gdb -q bsd.gdb
Reading symbols from bsd.gdb...done.
(gdb) target remote /dev/pts/4
Remote debugging using /dev/pts/4
Ignoring packet error, continuing...
warning: unrecognized item "timeout" in "qSupported" response
Ignoring packet error, continuing...
Remote replied unexpectedly to 'vMustReplyEmpty': timeout

となってしまって、意志疎通が出来ない状態。CentOS側のgdbを起動しておいて、OpenBSD側からちょっかいを出しても、その逆でも同様。

こちらの方も、同様なお悩みがあるようですよ。

KGDB with sparc as target

text    data    bss     dec     hex
9632556 245784  671744  10550084        a0fb44
mv bsd bsd.gdb
strip -S -o bsd bsd.gdb
    2m00.90s real     1m19.50s user     0m27.67s system

この間、何度コンパイルしたやら。コンパイルするたびにデバイスを減らしていったら、大分スピードアップが図れたな。

alias ddb='sysctl ddb.trigger=1'

qemu-kvmな環境ではkgdbは使えないという結論を下さざるを得ない。諦めて、ddbを使う 環境に戻した。何時でもddbに突入出来るように、上のようなエイリアスを書いておいたよ。

それから、不思議な事に、ddbを生かした環境でも、Cent側でgdbを起動して、target remote :1234 すると、普通にgdbでtarget側のOpenBSDを観察出来る事。どういう仕組みで動いて いるのかな?

本物のOpenBSD 6.0 上で確認する

で、しょうがないので、生粋のOpenBSD 6.0 環境でやってみる。qemu-system-x86_64の中で 動いているやつが対象です。

text    data    bss     dec     hex
9417580 224104  651264  10292948        9d0ed4
mv bsd bsd.gdb
strip -S -o bsd bsd.gdb

real    1m47.274s
user    0m48.520s
sys     0m51.920s

この差は、qemu-kvmのオーバーヘッドかな? まだ削れそうな所が有るから、暇に任せて やってみるかな。それより、kgdbが動くかの確認が先。

結論を書いてしまえば、CentOSと同じ症状になり失敗しました。何か見落としている所が 有るのだろうか? これ以上はソース嫁の世界かな。

VBOXにOpenBSD 6.1を入れる

気分を変えて、VBOXの方へFULLのOpenBSDを入れた。

何か新しいportsが来ていないか調べてみたら、hugs98が無くなっていた。古いので 誰も見向きもしなくなったんだろうね。ちょいと使うのには軽くていいんだけどな。 素のソースを取ってきて入れようとしたら、途中でエラー発生。

諦めて、6.0の時のportsをコピペ(こういうのをレシピの盗用と言います)してきて、 コンパイルしたら、無事に入った。果たしていつまで盗用が出来るやら?

で、気分を変えて、 chibi-scheme なんてのを試している。作者は、あのscheme-complate.elを書いた、Alex Shinnさん。

chibiって日本語だよな。彼はgaucheのshiroさんと一緒にやってたんで、日本語に感化 されて、名前を決めたに違いない。

Snow Package Managerというのも用意されてて、そのリポジトリぃーには、shiroさんの名前もうかがえる。 切磋琢磨してるんだな。

VBOX, VMWare間で、kgdb

失敗続きのkgdb、最後の悪あがきとして、VBOXとVMWareのコラボレーションでやってみる。 すでにVBOXの方へはOpenBSD6.1を入れたので、VMWare側にも入れる。VBOX側ではgdbを 起動して、VMWare側のOpenBSDを観測しよう。

Serial connectionを 思い出して、VMWare側はクライアント設定。VBOX側がサーバー側。tty00を一般ユーザーが 使うには、dialerに属している必要が有る。

(gdb) target remote /dev/tty00
Remote debugging using /dev/tty00
Ignoring packet error, continuing...
breakpoint () at cpufunc.h:343
343     cpufunc.h: No such file or directory.
        in cpufunc.h

VMWare側で、起動時に、-dしたら、上記のようになった。一応繋がっているみたい。 続いて、プロセスが生まれる所にBPを張る。

(gdb) b fork1

Breakpoint 2 at 0xffffffff8111be6f: file /usr/src/sys/kern/kern_fork.c, line 323.
(gdb) c
Continuing.
Can't send signals to this remote system.  SIGEMT not sent.

Program received signal SIGEMT, Emulation trap.
0xffffffff8111030a in main (framep=0xe) at /usr/src/sys/kern/init_main.c:189
189     {
(gdb) c
Continuing.
Can't send signals to this remote system.  SIGEMT not sent.

Program received signal SIGEMT, Emulation trap.
breakpoint () at cpufunc.h:343
343     cpufunc.h: No such file or directory.

fork1は、437行目に有るんだけど、上では、mainの入り口を指しているな。それから、cpufunc.hが 見つからないと言ってきてるけど、arch/amd64/include/cpufunc.hに有るぞ。

/* Break into DDB/KGDB. */
static __inline void
breakpoint(void)
{
        __asm volatile("int $3");
}

asm命令が書いてあるんで、gdbはいかんともしがたいから、無いって嘘をついているのかな。 で、続きをやろうとしたら、クライアント側がハングした。

クライアント側を立ち上げた後、サーバー側から接続に行くと、

 vmx| I125: serial0: Overrun

VMWare側はパニ喰った。これ、VMWare側のログね。これから後に続くログを添えて、サポセンに連絡とか出てきた。遊びで使っているので、封印しておこう。

kgdb 諦めた

ddbが有効なやつでも、systemcallぐらいは、gdbでソースから追えるんで良しとしよう。 本当にddbで追及するのは、mainの中だけに限られるからね。

そんな訳で、コンパイルを繰り返していたqemu配下のdiskは、随分と肥大化してたんで、 インストールのやり直し。(都合、4回も6.1をインストールしたんで、もう慣れたものです)

Cent側にある、ソースをOpenBSD内に取り込むの、今まではrsycが定番だったけど、どうせ 一回しか出番がないので、scpを使ったよ。

$ scp -r cent:ob61/sys .

考えながら転送してるんで、少々時間がかかったぞ。

記念に出来たカーネルの状況。デフォルトのカーネルは、色々なハードに対応するため 太っているけど、関係ないのをそぎ落とすと、スリムになるな。

# ls -lh bsd obsd
-rw-r--r--  1 root  wheel   6.5M May  4 14:39 bsd
-rw-r--r--  1 root  wheel  10.2M May  4 14:39 obsd

そして、そのカーネルを逆Asmして、使われている命令を列挙してみた。ダントツでmovが 多いって事は、データをあちこちに移動させるのがカーネルの仕事ですって事だな。 次に多いのは、add。きっと、1を足し算する、小学生並みの事しかやってないんでしょね。 次は、何かの下請けを呼び出す事か。大体10命令に1回の割合で、下請けをこき使うとな。 カーネルは偉い人なんだな。

[cent tmp]$ objdump -D bsd >LOG
[cent tmp]$ wc LOG
  1662656  11019966 104634892 LOG
[cent tmp]$ cat LOG | cut -f3 | cut -d' ' -f1 | sort | uniq -c | sort -nr
 690527 mov
  98632 add
  74767 callq
  49340 je
  39628 and
  38567 cmp
  31862 test
  31210 movl
  29593 jne
  27210 push
  26283 sub
  24467 movzbl
  23448 jmp
  22882 lea
  20415 jmpq
  19731 movzwl
  19617 cmpl
  17348 xor
  15148 retq
  14794 leaveq
  13063 or
  11198 shl
  10885 movq
  10060 imul
   9876 int3
   9409 movslq
    :

インテルの糞石は、可変命令長なやつ。逆Asmした時、命令語の長さが不規則。それでも 頑張って、綺麗に並べるために、TABが使われている。

今回はそのTABを目印にフィールドを分解してみた。cutのフィールドセパレータは、 デフォでTABになってるのね。知らなかったぞ。

ああ、調子に乗って、OpenBSDのスリム化をやっていたら、とうとうやせ細って、立ち上がれ なくなったぞ。ちょいと悔しいな。