mdb
巷では、コロナウィルスが大流行り。影響が各所に出てる。病院はクラスターだから、オンライン診療なんかがいいんでないかいなんて、もてはやされているみたい。
病院をサロン代わりに使ってる年寄りに、自宅から医師に面談出来るようなシステムをセットアップ出来るのかな? はなはだ疑問。そのうちに、無料でセットアップしますとか言う詐欺が出てこないか心配。
セットアップして、ウィルスをついでに植え付けるとかね。やりたい放題にされちゃうぞ。甘言にはくれぐれも乗らないように。そのうちに、防災無線で注意喚起されたりして。
オンライン診療を受けてる人のインタビューをやってた。病院へ行かなくていいので、ウィルスの心配が全くないので、安心です。ネット上には、恐い々ウィルスが多数徘徊してるぞ。注意めされ。
ウィルスの撲滅に向けて、皆さんも出来る事をしましょう。皆さんが使っているパソコンの能力をちょっと貸していただけませんか?
その趣旨で、上記のような試みが昔から行われている。これを、 Covid19 に特化したやつも絶賛運用中。
そしてOSS界も協力しましょってんで、 Debian,4/5~のオンラインイベント「COVID-19バイオハッカソン」に参加へが、始まった。
コードのトリアージって、もう死にそうなコードを助け上げるって事だな。死にそうなコードと言えば、なんとか.rb だな。外来種のPython菌が余りにバンデミックしてしまったので、今や風前の灯です。国定品に指定されてるんだから、国が責任持って拡散しなよ。
だれか、突然変異のきっかけを作らないかな。
python菌と言えば、minixにも住み着いているぞ。
$ python Python 1.5.2 (#5, Feb 7 2106, 06:28:15) [C] on minix3 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>>
これはもう、古生物だな。
found mdb
minixを入れて、gdbが無い無いと騒いでいた。ふとした事で、3.2.1のソースエリアをザッピングしてたんだ。そしたら、mdbなんて言う不穏な物を発見した。
能書きには、
INFORMATION on mdb version 2.6.0 (Sept 9/96). MDB is the MINIX debugger which allows you to place breakpoints and control the execution of a program. It has a lot of the features that you would expect in a program debugger; for example, stack traces and single step execution. The current version works with MINIX for PC and was developed and tested under MINIX 1.7.x (32 bit version). It should work with 16 bit MINIX. How to Install :
ってな事が書いてある。ソースが有るならバイナリーも置いてあるだろうってんで、探すも見つからず。ならば自分でコンパイル、エラーがわんさかと発生したぞ。直す気力無し。gdbに道を譲ったのかな?
1.7の時代から動いているなら、book版の3.1.0はどうよ? /usr/src/commandsの下にemacsとかと並置して置いてあった。本来のminixコマンドは、simpleの下に突っ込んであったぞ。なんか不均衡だな。
そして、バイナリーも作成して有ったぞ。
run mdb
README.TXTに簡単な使い方が載ってた。
3) The sample comand file and log output. To test this, type something like the following "mdb -llog.new /usr/bin/sleep @sample" The output "log.new' should be similar to the distributed "log" file; but not necessarily exactly the same.
sleepコマンドをデバッグするんだな。それにしてもsleep時間の指定が有ってもよさそう。 まて、それはデバック内で設定するんだろうな。sampleを見ろだな。
$ cat sample r 10 ;; run with 10 y ;; print segment mapping __sendrec b ;; set BP B ;; Display BP c ;; continue x 2 ;; display regs for 2 instraction t ;; backtrace all q ;; kill traceed process
debuggerへのコマンド列になるのね。実行結果のログ
Sorting 0 MINIX symbols .... r 10 Process stopped. y Separate I & D space Pid: 197 Virtual Physical Length address address T: 0x00000000 0x0000dc00 2048 (0x00000800) D: 0x00000000 0x0000e400 1024 (0x00000400) S: 0x00004000 0x00012400 1024 (0x00000400) __sendrec b __sendrec: symbol not found B c 0000:0565 5B pop ebx Process stopped by signal 14 x 2 fs gs ds es edi esi ebp ebx edx 000f000f 000f000f 0000000a 00004298 0000426c 0000485c 000053f6 ecx eax eip cs psw esp ss 00000032 00000000 00000565 00000007 00000202 00004268 0000000f 0000:0565 5B pop ebx 0000:0566 5D pop ebp t _start+0565(0x00000000,0x00004298) _start+0313(0x00000000,0x00000048,0x00004298) _start+04F7(0x000042e8) _start+0213(0x0000000a) _start+D3() q mdb ptrace error : No such process 0x00000565 Q
何となく分かったような分からないような。
small program
自分で、小さなプログラムを書いてみる。
$ cat mysleep.c /* sleep - suspend a process for x sec Author: Andy Tanenbaum */ #include <sys/types.h> #include <stdlib.h> #include <unistd.h> #include <minix/minlib.h> _PROTOTYPE(int main, (int argc, char **argv)); int zzZ(secs) int secs; { sleep(secs); return(0); } int main(argc, argv) int argc; char *argv[]; { register seconds; seconds = 3; zzZ(seconds); return(0); }
タンネンバウム教授のコードを改変するって、教授にたてついたリーナスみたいな気分だぞ。
$ cc -v mysleep.c mkdir /tmp/acd219 /usr/lib/em_cemcom.ansi -L -D__minix -D__i386 "-D_EM_WSIZE=4" "-D_EM_PSIZE=4" "- D_EM_SSIZE=2" "-D_EM_LSIZE=4" "-D_EM_FSIZE=4" "-D_EM_DSIZE=8" -D__ACK__ -D_ACK -Vw4.4i4.4p4.4f4.4s2.2l4.4d8.4 -Vr mysleep.c /tmp/acd219/a.k "mysleep.c", line 12: (warning) 'zzZ' old-fashioned function definition /usr/lib/em_opt /tmp/acd219/a.k > /tmp/acd219/b.m rm -f /tmp/acd219/a.k /usr/lib/i386/cg -F__fp_hook /tmp/acd219/b.m > /tmp/acd219/c.ack.s rm -f /tmp/acd219/b.m /usr/lib/i386/as - -o /tmp/acd219/d.o /tmp/acd219/c.ack.s rm -f /tmp/acd219/c.ack.s /usr/lib/em_led -a0:4 -a1:4 -a2:4 -a3:4 -b0:0 -b1:0 -o /tmp/acd219/e /usr/lib/i3 86/crtso.o /tmp/acd219/d.o /usr/lib/i386/libd.a /usr/lib/i386/libc.a /usr/lib/i3 86/libfp.a /usr/lib/i386/libe.a /usr/lib/i386/end.a /usr/lib/cv -x -mi386 /tmp/acd219/e a.out rm -f /tmp/acd219/d.o rm -f /tmp/acd219/e rmdir /tmp/acd219
このコンパイラは変わっててC語やmodula-2語やPascal語を受け付けるとか、そんな訳で、フロントエンドを通して、共通語に直す。それがkサフィックスを付けたファイル。次に簡単な最適化をしてmサフィックス付きのファイルになる。後はそれをアセンブルしてoサフィックスになる。それとライブラリィーをリンクして最終出力になる。
$ cc -S mysleep.c "mysleep.c", line 12: (warning) 'zzZ' old-fashioned function definition $ more mysleep.s .sect .text; .sect .rom; .sect .data; .sect .bss .extern _zzZ .sect .text _zzZ: push ebp mov ebp,esp push 8(ebp) call _sleep pop ecx xor eax,eax leave ret .extern _main _main: push ebp mov ebp,esp push esi mov esi,3 push esi call _zzZ pop ecx xor eax,eax pop esi leave ret
アセンブル語になると、関数名の先頭にアンダーバーが付くのはお約束なんだな。
$ nm a.out | grep zzZ 00000054 T _zzZ $ nm a.out | grep main 00000050 T ___main 00000064 T _main
実行ファイルから、アドレスを抜き出してみた。
$ mdb a.out Sorting 77 MINIX symbols .... * y Separate I & D space Pid: 0 mdb ptrace error : No such process * R Process stopped. * y Separate I & D space Pid: 246 Virtual Physical Length address address T: 0x00000000 0x008c3c00 2048 (0x00000800) D: 0x00000000 0x008c4400 1024 (0x00000400) S: 0x00020000 0x008e4400 1024 (0x00000400)
R 又は r で、プログラムがロードされるんだな。
* _main b * B 1: _main (0x64) - * c Breakpoint hit. _main: 0000:0064 CC int 3 * x 12 fs gs ds es edi esi ebp ebx edx 000f000f 000f000f 000060cc 0001c9c8 00000000 00004b8c 00020338 ecx eax eip cs psw esp ss 00020340 00000011 00000064 00000007 00000246 00020330 0000000f _main: 0000:0064 CC int 3 0000:0065 89E5 mov ebp,esp 0000:0067 56 push esi 0000:0068 BE03000000 mov esi,00000003 0000:006D 56 push esi 0000:006E E8E1FFFFFF call _zzZ ; 0054 0000:0073 59 pop ecx 0000:0074 31C0 xor eax,eax 0000:0076 5E pop esi 0000:0077 C9 leave 0000:0078 C3 ret 0000:0079 0000 add [eax],al
形通りmainにBPを置いて、継続。止まった所で、レジスタとメモリーの逆アセンブル。
* c 0000:04A9 5B pop ebx Process stopped by signal 14 * t __sendre+11(0x00000000,0x000202b8) __syscal+17(0x00000000,0x00000048,0x000202b8) __sigsus+1B(0x00020308) __sleep+96(0x00000003) _zzZ+0B(0x00000003) _main+0F() begtext+01()
継続すると最後はシグナル発生で止まるんだな。それまで、全てのバックトレース(って、奇妙な機能)を確認。
再帰
mdbをmdbでdebug出来るか? 考えていてもしょうがないので、手を動かす。 コマンドは、こんなの
$ cat cm R y _main b
$ mdb /usr/bin/mdb @cm Sorting 0 MINIX symbols .... Process stopped. Separate I & D space Pid: 146 Virtual Physical Length address address T: 0x00000000 0x0085e000 32768 (0x00008000) D: 0x00000000 0x008a4800 17408 (0x00004400) S: 0x0001c800 0x008c1000 1024 (0x00000400) _main: symbol not found 0x00000000
シンボルが欠落してるのかな?
$ file /usr/bin/mdb /usr/bin/mdb: MINIX-PC 32-bit executable, sep I&D stripped $ file a.out a.out: MINIX-PC 32-bit executable, sep I&D not stripped
a.outは普通にコンパイルしたやつ。mdbでは情報が落とされている。
# ii) For tracing of syscalls, uncomment: # FOR_SYSCALLS =syscalls.o decode.o ioctl.o DEF_SYSCALLS =-DSYSCALLS_SUPPORT : install: mdb install -cs -o bin mdb /usr/bin
mdbのMakefile中、上記の -cs を、-cに変えて、strip禁止にした。
* B 1: _main (0x16fa) - * _main x 4 fs gs ds es edi esi ebp ebx edx 000f000f 000f000f 000080d4 0001d5b8 00000000 0000485c 00001ce8 ecx eax eip cs psw esp ss 00005cb8 00000000 00000000 00000007 00000202 0001d72c 0000000f _main: 0000:16FA CC int 3 0000:16FB 89E5 mov ebp,esp 0000:16FD 83EC24 sub esp,+24 0000:1700 56 push esi
今度は大丈夫。逆アセンブル方法も分かった(ソースちら見の効果)。
コンパイルする時、システムコールをトレースする機能を有効にしておいたんだ。そしたら、zコマンドが使えるようになってた。
今度はprintenv.cを肴にして観察会。
* z _main Break point set - use the 'c n' command * c syscall to FS type IOCTL (54) Sending (80245408) Other IOCTL device=1 request= T|8 flags=8000 size =36 result=0 Receiving (80245408) Other IOCTL device=3 request=T|8 flags=8000 size =36 0000:1356 5D pop ebp Process stopped by signal 5
余り思った物が引っかからないな。
* t __sendre+12(0x00000001,0x0001fe1c) __syscal+17(0x00000001,0x00000036,0x0001fe1c) __ioctl+25(0x00000001,0x80245408,0x0001fe64) __tcgeta+13(0x00000001,0x0001fe64) __isatty+12(0x00000001) ___flush+88(0x00000055,0x00000198) __doprnt+05B8(0x00000006,0x0002031c,0x00000198) _printf+1C(0x00000004,0x0002036e) _main+27()
今度は、観察場所を変更
* z _sendre Break point set - use the 'c n' command * c syscall to FS type IOCTL (54) Sending (80245408) Other IOCTL device=1 request= T|8 flags=8000 size =36 result=0 Receiving (80245408) Other IOCTL device=3 request=T|8 flags=8000 size =36 0000:1356 5D pop ebp Process stopped by signal 5 * c syscall to MM type BRK (17) p1=2c8 result=0 m2_p1=2c8 0000:1356 5D pop ebp Process stopped by signal 5 * c syscall to FS type WRITE (4) i1=1 i2=17 HOME=/home/sakae result=17 0000:1356 5D pop ebp Process stopped by signal 5 : syscall to FS type WRITE (4) i1=1 i2=10 EDITOR=vi result=10 0000:1356 5D pop ebp Process stopped by signal 5 * c syscall to MM type EXIT (1) i1=0 child exited with status 0 mdb ptrace error : No such process
今度はminixの根幹を成すIPCのルーチンの一つをトレース対象に選んでみた。
minixはUnixやLinuxと違って、マイクロカーネルを採用してる。カーネルを極力小さくしましょって思想。普通のUnixだとファイルシステムやメモリーマネージャー等がカーネル内に配置されてる。けど、そういうものをカーネル外に追い出して、ユーザープロセスにしちゃった。 (結果、カーネルは小さくなる)
そうすると、カーネルとファイルシステム間とかの通信が必要になる。それにIPC(Inter Process Commnication)を採用。minixでは、これの実現にPIPEを使ってる。
要求が有る時、そのメッセージをあて先目掛けて投げる(send)。受ける方は送信元を指定して受信(receiv)。このメッセージは、当然システムコール(相当)に成るんで、同時にやってしまう(sendre)の3種類が用意されてる。
上記では、_sendreをトレースしたんで、リナで言うstrace相当と言う事になる。
マイクロカーネルのおかげで、カーネルは極小になったんだけど、ペナルティーとして遅いと言う弊害が出た。それに噛みついたのが、ご存知のリナス君。
ネットで大論争を引き起こしながら、糞石上でスピード命、便利ならそれでいいじゃんと言う方針で開発を進めた。 BSDがAT&T との裁判でもたもたしてる間に、勢力を伸ばしてしまったと言う構図。
拡張性とか考えずに糞石の動けばいいやだったもので、内部はスパゲッティ。どうせすぐにソースコードを書き換えちゃうんだから、ちゃんと文書化したって直ぐに陳腐化する。だったら、そんなの最初からやらない方がまし。
かくして、悪貨がはこびっております。
最後にmdbの使い方のまとめとして、dateのシステムコールを追ってみる。/usr/bin/dateはstripされてるんで、自前でコンパイルしておく。
$ mdb a.out Sorting 129 MINIX symbols .... * R Process stopped. * z __sendre Break point set - use the 'c n' command * c syscall to MM type TIME (13) result=0 m2_l1=5e882e72 0000:1E8E 5D pop ebp Process stopped by signal 5 * c syscall to FS type WRITE (4) i1=1 i2=29 Sat Apr 4 06:51:30 GMT 2020 result=29 0000:1E8E 5D pop ebp Process stopped by signal 5 * c syscall to MM type EXIT (1) i1=0 child exited with status 0 mdb ptrace error : No such process * Q