netbsd(3)
夏休みの課題図書じゃ無いけれど、岩波ジュニア新書から出ている『さわっておどろく!』って本を 手に取ってみた。副題は、点字・点図がひらく世界ってついてた。
想像出来ると思うけど、視的しょうがいの方がいかにコミュニケーションを取っていくかという 事について書かれている。
私は恥ずかしながらこの本によって、点字の世界を初めて知りましたよ。 明治の終わり頃には、先駆者の努力によって、日本語用の点字が確立されているんですね。 日本語用と言うからには、英語用の点字 も勿論有るわけで、他の言語用も世界で使われている。
身近な所にある点字としては、缶ビールとかの蓋に付いているあれですね。点字は、縦3個横2列 のドットの組み合わせで、1文字を表すきまりだ。6Bitだから、63種(ドットが1個も無いのは文字と みなさない)の文字を表現出来る。
ひらがなや濁音記号数字とかを含めると、63種では収まらないので、2字連結して、1字としてる とか、JIS文字で言う、切り替え符号があったりとか、何やらコンピュータ系の文字コードと そっくりになっている。ユニコードにも点字パターンが登録されてるしね。
ああ、コンピュータの文字コードは、点字に比べてずっと後輩になるんだね。そうすると、文字 コードは、点字からアイデアを頂いてきたのか。
3X2のドットの組み合わせと言うと、8進数2桁で表せるな。たとえば、あ、と言う点字は、040、 か、と言う点字は、041 と言った具合。
UNIXが最初に載った、PDP11も確か、8進数を使っていたな。od なんてコマンドは、歴史ある コマンドなんだな。何で最初は8進数かと想像したら、この頃のレジスタ数は8個だったから、8進数で 表すと収まりが良かった、なーんてね。あのeaxとか言うレジスタが有る石も、レジスタ数は8個 なんだよな。
歴史 od コマンドは Version 1 AT&T UNIX から登場しました。
それが、いつの間にか、16進数が幅を利かせるようになっちゃったな。これは、1語長が32Bitとか になって、16進にすると圧縮率が高くなるって理由なんだな。 それとも、beefとかcafeとかdeadとかfaceとか、16進数で、意味有る単語を作りたかったから?
他に4文字16進数単語って有るのかな? ruby -pe 'p $_ if ...' とかの一行野郎を試して みようとしたが、期待通りに動かん。しょうがないので、replのお世話になってみる。 単語帖は、FreeBSDに備え付けの由緒あるやつを使いました。
irb(main):001:0> IO.foreach('/usr/share/dict/words') do |w| irb(main):002:1* puts w if w =~ /^[a-f]{4}$/ irb(main):003:1> end abac abed acca adad adda affa baba babe bade baff bead beef caba cade cede dabb dace dada dade daff dead deaf deed ecad edea face fade faff feed => nil
feedとかfadeとか、覚えておいて損はないか。
ああ、いつの間には脱線してるな。脱線ついでに、点字って読解スピードはどのぐらいなんで しょうか? 30wpmぐらいは出るんですかね? 聞く符合、モールス信号だと、そのぐらいは 判読出来るそうですよ。
ついでに、点字のドット間隔は、1mmぐらいが限界のようです。 (指センサーの分解能は個人差が大きいらしい。日頃から中華文化で盲牌で鍛えていると、それなり の分解能を達成出来るかなぁ)
点字フォントで検索してみたら、 墨点字フォントとか 点字フォント(Unicode6点) なんてのが出てきました。いろいろ有るんですね。
netbsd de kgdb
前回は、netbsdのsparc版で、カーネルにgdbを組み込もうとして、あえなく撃沈した。きっと、 今更sparcでごにょぼにょやろうなんて輩はいないんで、ちゃんとメンテナンスされていない んだろうね。ふと、エリック・レイモンドが言ってた事を思い出したぞ。目玉は多いほど良い。 だから、OSSなんだってね。
目玉が多いのはどんなプラットフォームだ? 考えるまでもなく、i386だよ。残念ながら。 kgdbを動かすって事は、下の層まで潜る必要性が無いって事だな。だったら、もう1000歩下がって (最初の1000歩は、sparc版でddb実現)、インテル系でnetbsd de kgdb で、いいじゃん。
早速i386cd-5.1.2.isoを落としてきて、VMWAREで、netbsdが入ったものを作りましたよ。 前週の案内では、リモートデバックをやるには、2台のnetbsd機が必要とな。そしてその間を シリアル回線で接続するそうな。
取りあえず1台作ったので、そこでgdbを動かす事にする。マシンの名前はremとした。 rem機で、gdbとddbを組み込んだ、カーネルを作る。そしたら、その機をそのまま、WIndows上で コピー。コピーしたマシンは名前をtagとでもしよう。そして、tag機の方で、カーネルを インストールする方針。 remは、リモートの略。tagはターゲットの略です。以下、rem機での作業。
: # create GENERIC/.gdbinit rm -f .gdbinit echo "source ../../../../gdbscripts/bdump" >> .gdbinit echo "source ../../../../gdbscripts/cpus" >> .gdbinit echo "source ../../../../gdbscripts/kdump" >> .gdbinit echo "source ../../../../gdbscripts/lwps" >> .gdbinit echo "source ../../../../gdbscripts/msgbuf" >> .gdbinit echo "source ../../../../gdbscripts/pgrpdump" >> .gdbinit echo "source ../../../../gdbscripts/procs" >> .gdbinit echo "source ../../../../gdbscripts/vchain" >> .gdbinit echo "source ../../../../gdbscripts/vdump" >> .gdbinit # create vers.c sh ../../../../conf/newvers.sh # compile GENERIC/vers.o cc -ffreestanding -fno-zero-initialized-in-bss -g -O2 -std=gnu99 -fno-strict-aliasing -Werror -Wall -Wno-main -Wno-format-zero-length -Wpointer-arith -Wmissing-prototypes -Wstrict-prototypes -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -Wno-unreachable-code -Wno-sign-compare -Wno-pointer-sign -Wno-attributes -Wextra -Wno-unused-parameter -Werror -march=i486 -mtune=pentiumpro -Di386 -I. -I../../../../contrib/dev/ath/netbsd -I../../../../../common/include -I../../../../arch -I../../../.. -nostdinc -DLKM -DMAXUSERS=32 -D_KERNEL -D_KERNEL_OPT -I../../../../lib/libkern/../../../common/lib/libc/quad -I../../../../lib/libkern/../../../common/lib/libc/string -I../../../../lib/libkern/../../../common/lib/libc/arch/i386/string -I../../../../../common/include -I../../../../dist/ipf -c vers.c
ほう、gdbが便利に使えるように、ドットファイルを作ってくれているのか。どんな便利機能が 入ってるか、後で確認しておこう。
# link GENERIC/netbsd ld -Map netbsd.map --cref -T ../../../../arch/i386/conf/kern.ldscript -Ttext c0100000 -e start -X -o netbsd ${SYSTEM_OBJ} ${EXTRA_OBJ} vers.o NetBSD 5.0.2 (SAKAE-$Revision: 1.915.2.3 $) #0: Sat Aug 25 13:26:15 JST 2012 text data bss dec hex filename 9816851 423908 616532 10857291 a5ab4b netbsd mv -f netbsd netbsd.gdb strip -g -o netbsd netbsd.gdb 635.47 real 224.92 user 325.65 sys
コンパイルの最後のフェーズでリンクが行われました。そして、gdbが使う情報が一杯詰まった カーネルの名前を、netbsd.gdbに改名。そのファイルから、gdb情報をそぎ落として、netbsdって 名前のファイルを作ってる。
10分強で、コンパイルしてるね。mips版のコンパイルに3時間弱かかった事を思えば、いかに シュミレータが遅いか良く分かると言うものだ。
このrem機をそのままVMWARE上のdir毎コピーして、vmwareの設定ファイルを編集。tag機を起動すると、 移動したんかコピーしたんか聞かれるので、コピーしたって答えてあげる。 後は、カーネルをインストール。
続いて、vmwareの設定で、シリアルを追加。パイプを選んで、rem機はサーバー(tag機はクライアント) 、相手はvmwareって設定しておく。
vmwareのシリアルポート は、アプリにもパイプを使って接続出来るみたいなので、何かの時に、役に立つかも知れないな。
これで準備万端整った。まずは、tag機を、boot -d して起動するんだな。そうすると、よそからの gdb接続待ちになるとな。
が、そんな風にはならずに、いきなり、fatal breakpoint とか言って、ddbに落ちちゃったよ。 なんで、そうなるの? ぐぐる先生に聞いても、知らんと言われるし。結局、ソース嫁。
kgb waitingを頼りに、ソースを漁ると、arch/i386/kgb_machdep.c に、kgb_connectっていう、 いかにもってのが見つかった。こやつは、何処から呼ばれる?
調べてみたら、arch/i386/machdep.cに有った。
#ifdef DDB if (boothowto & RB_KDB) Debugger(); #endif #ifdef IPKDB ipkdb_init(); if (boothowto & RB_KDB) ipkdb_connect(0); #endif #ifdef KGDB kgdb_port_init(); if (boothowto & RB_KDB) { kgdb_debug_init = 1; kgdb_connect(1); } #endif if (physmem < btoc(2 * 1024 * 1024)) { printf("warning: too little memory available; " "have %lu bytes, want %lu bytes\n" "running in degraded mode\n" "press a key to confirm\n\n", ptoa(physmem), 2*1024*1024UL); cngetc(); } }
これを見ると、DDBの方が優先される。しょうがないので、DDBのオプション無しでKGDBだけを イネーブルにして、コンパイルし直したよ。とほほ。関係ないけど、2M以下のメモリーだと やばいんか。
run gdb
紆余曲解の末、やっと走らせる事が出来た。
tag$ cat /boot.cfg menu=Boot normally:boot netbsd menu=Boot single user:boot netbsd -s menu=Disable ACPI:boot netbsd -2 menu=For KGDB debugging:boot -d menu=Drop to boot prompt:prompt default=4 timeout=5
tag機は、boot時にbootメニューに一度落ちてから、boot -dしなきゃいけないんだけど、面倒 なので、boot.cfgを改変しといたよ。
waitingが出てきたら、rem機でrootになってから、次のようにする。rem機のシリアルもtty00を 使うようにした。
rem# gdb netbsd.gdb GNU gdb 6.5 Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386--netbsdelf"... (gdb) set remotebreak 1 (gdb) set remotebaud 9600 (gdb) target remote /dev/tty00 Remote debugging using /dev/tty00 0xc057287c in breakpoint () (gdb) bt #0 0xc057287c in breakpoint () #1 0xc0574bc7 in kgdb_connect (verbose=1) at ../../../../arch/i386/i386/kgdb_machdep.c:242 #2 0xc0576fba in init386 (first_avail=13225984) at ../../../../arch/i386/i386/machdep.c:1974 #3 0xc01002c2 in begin () (gdb) f 3 #3 0xc01002c2 in begin () (gdb) l 44 #if defined(__GNUC__) && !defined(_LKM) 45 static struct cpu_info *x86_curcpu(void); 46 static lwp_t *x86_curlwp(void); 47 48 __inline static struct cpu_info * __unused 49 x86_curcpu(void) 50 { 51 struct cpu_info *ci; 52 53 __asm volatile("movl %%fs:%1, %0" : 54 "=r" (ci) : 55 "m" 56 (*(struct cpu_info * const *)offsetof(struct cpu_info, ci_self))); 57 return ci; 58 } 59 60 __inline static lwp_t * __attribute__ ((const)) 61 x86_curlwp(void) 62 { 63 lwp_t *l;
macdep.cって、巨大なソースなんだよな。XENのコードも大分入っているし。。。Linuxとも 仲良くしたいんかな。博愛主義だなあ。リナスは、BSDの事を鼻にもひっかけない のにね。debianはRMSの博愛主義が効いてて、FreeBSDをカーネルにしたって良いよって態度。 親分の主張が、正義なんだなあ。
(gdb) b sys_execve Breakpoint 1 at 0xc048920b: file ../../../../kern/kern_exec.c, line 465. (gdb) c Continuing. Ignoring packet error, continuing... Ignoring packet error, continuing...
ありゃら、接続が切れちゃったよ。何でかな? 考えても分からないので別な方向へ手を出して みる。 Remote Kernel Debugging via Qemu なんてのをFreeBSDでやってるお方が居た。NetBSDでも一緒でしょ。
NetBSDでもQemu
qemuのソースを取ってきて、一からコンパイルしてもいいんだけど、いろいろと前準備が 必要なので、pkgになってるのを使わせてもらいましょ。
rem# PKG_PATH="ftp://ftp5.jp.netbsd.org/pub/NetBSD/packages/5.1/i386/All/" rem# export PKG_PATH rem# pkg_add -f qemu-*
pkg_add )に、-fを付けているのは、無理やりインストールするぞって印、全ては事故責任だからね。 ついでに、sudoとscreenも入れておいた。
rem$ ls /usr/pkg/bin/qem* /usr/pkg/bin/qemu /usr/pkg/bin/qemu-system-mips64 /usr/pkg/bin/qemu-ga /usr/pkg/bin/qemu-system-mips64el /usr/pkg/bin/qemu-img /usr/pkg/bin/qemu-system-mipsel /usr/pkg/bin/qemu-io /usr/pkg/bin/qemu-system-ppc /usr/pkg/bin/qemu-nbd /usr/pkg/bin/qemu-system-ppc64 /usr/pkg/bin/qemu-system-arm /usr/pkg/bin/qemu-system-ppcemb /usr/pkg/bin/qemu-system-cris /usr/pkg/bin/qemu-system-s390x /usr/pkg/bin/qemu-system-lm32 /usr/pkg/bin/qemu-system-sh4 /usr/pkg/bin/qemu-system-m68k /usr/pkg/bin/qemu-system-sh4eb /usr/pkg/bin/qemu-system-microblaze /usr/pkg/bin/qemu-system-sparc /usr/pkg/bin/qemu-system-microblazeel /usr/pkg/bin/qemu-system-sparc64 /usr/pkg/bin/qemu-system-mips /usr/pkg/bin/qemu-system-x86_64
色々入りましたなあ。おまけでperlとかも付いてきたぞ。 そんじゃ、qemu環境にnetbsdを入れてみる。
rem$ qemu -m 128 -cdrom ./i386cd-5.1.2.iso -hda ./DISK.img -nographic -boot d Welcome to the NetBSD 5.1.2 installation CD =============================================================================== ACPI should work on all modern and legacy hardware, however if you have problems, please try disabling it. If you encounter problems on hardware manufactured after 1998 with ACPI enabled, please file a problem report including output from the 'dmesg' command. 1. Install NetBSD 2. Install NetBSD (no ACPI) 3. Install NetBSD (no ACPI, no SMP) 4. Drop to boot prompt Choose an option; RETURN for default; SPACE to stop countdown. Option 1 will be chosen in 0 seconds. booting cd0a:netbsd 10090076+518916+618576 [521184+509293]=0xbb2988 Loading /miniroot.kmod
最初、sgabios.bin が無いって言われて終了しちゃったよ。しょうがないのでLinux側からROMを 引っこ抜いてきて/usr/pkg/share/qemu内にインストールしたら、動き出した。けど、上記の メッセージのままで、うんともすんとも言わなくなっちゃった。
しょうがないので、Linux側で
qemu-system-i386 -m 128 -cdrom i386cd-5.1.2.iso -hda DISK.img -boot d -curses qemu-system-i386 -m 128 -hda ./DISK.img -curses
して、作ってあげたよ。そして、debug用のカーネルもインストールしたDISK.imgを、netbsd側に輸入した。 こういう時って、OSを色々入れておくと便利だ。
qemuとkgdbのコラボ
rem$ qemu -s -m 64 -hda DISK.img -redir tcp:2222::22 >/dev/null 2>&1
どうやら、pkgから入れたqemuでは、stdioとのやり取りが旨くいかないようなんで、ネット 経由で、ターゲットマシンに入るのが吉。画面がチカチカして見苦しかったので、std{out,err}を 闇に葬る事もやってます。
rem$ ssh -p 2222 localhost : mini$ dmesg|more : total memory = 65136 KB avail memory = 52072 KB timecounter: Timecounters tick every 10.000 msec timecounter: Timecounter "i8254" frequency 1193182 Hz quality 100 Bochs Bochs mainbus0 (root) cpu0 at mainbus0 apid 0: Intel 686-class, id 0x633 ioapic0 at mainbus0 apid 1: pa 0xfec00000, version 11, 24 pins : mini$ df -h Filesystem Size Used Avail %Cap Mounted on /dev/wd0a 868M 232M 592M 28% / kernfs 1.0K 1.0K 0B 100% /kern ptyfs 1.0K 1.0K 0B 100% /dev/pts procfs 4.0K 4.0K 0B 100% /proc
カーネルとコンパイル環境だけだと、こんなもので 済んじゃうですねぇ。
本題に戻って、qemuの場合は、オプションに -sを渡す事により、kgdbの待ちに 入るようだ。こういう状態になったら、別端末から、gdbを起動する。
rem# gdb ./netbsd.gdb GNU gdb 6.5 Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386--netbsdelf"... (gdb) target remote localhost:1234 Remote debugging using localhost:1234 [New thread 1] 0xc0572915 in x86_stihlt () (gdb) bt #0 0xc0572915 in x86_stihlt () #1 0xc048b0f6 in idle_loop (dummy=0xc6007c80) at ../../../../kern/kern_idle.c:81 #2 0xc01002e1 in lwp_trampoline ()
ちゃんと止まってくれたね。でも、VMWAREと違って、止まる所が異なってる。
(gdb) b sys_execve Breakpoint 1 at 0xc048920b: file ../../../../kern/kern_exec.c, line 465. (gdb) c Continuing. Breakpoint 1, sys_execve (l=0xc70f6d40, uap=0xc710fd00, retval=0xc710fd28) at ../../../../kern/kern_exec.c:465 465 { (gdb) l 460 * exec system call 461 */ 462 /* ARGSUSED */ 463 int 464 sys_execve(struct lwp *l, const struct sys_execve_args *uap, register_t *retval) 465 { 466 /* { 467 syscallarg(const char *) path; 468 syscallarg(char * const *) argp; 469 syscallarg(char * const *) envp; (gdb) detach Ending remote debugging. (gdb) q rem$
CTRL-Cも効くし、これは便利。
rem$ cat ./.gdbinit source ../../../../gdbscripts/bdump source ../../../../gdbscripts/cpus source ../../../../gdbscripts/kdump source ../../../../gdbscripts/lwps source ../../../../gdbscripts/msgbuf source ../../../../gdbscripts/pgrpdump source ../../../../gdbscripts/procs source ../../../../gdbscripts/vchain source ../../../../gdbscripts/vdump file netbsd.gdb set remotebreak 1 target remote localhost:1234
更に、上記のような設定をしておくと、gdbだけで、debug?を始められるんで、ルンルン(死語) です。
おまけ
gdbを使って、カーネルにパッチを当てるなんて事、出来るのね。初めて知りましたよ。
gdb --write /netbsd set rtc_offset=-540 quit