mdb

巷では、コロナウィルスが大流行り。影響が各所に出てる。病院はクラスターだから、オンライン診療なんかがいいんでないかいなんて、もてはやされているみたい。

病院をサロン代わりに使ってる年寄りに、自宅から医師に面談出来るようなシステムをセットアップ出来るのかな? はなはだ疑問。そのうちに、無料でセットアップしますとか言う詐欺が出てこないか心配。

セットアップして、ウィルスをついでに植え付けるとかね。やりたい放題にされちゃうぞ。甘言にはくれぐれも乗らないように。そのうちに、防災無線で注意喚起されたりして。

オンライン診療を受けてる人のインタビューをやってた。病院へ行かなくていいので、ウィルスの心配が全くないので、安心です。ネット上には、恐い々ウィルスが多数徘徊してるぞ。注意めされ。

ウィルスの撲滅に向けて、皆さんも出来る事をしましょう。皆さんが使っているパソコンの能力をちょっと貸していただけませんか?

Folding@home

その趣旨で、上記のような試みが昔から行われている。これを、 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