diff --git a/ja_JP.eucJP/books/handbook/kerneldebug/chapter.sgml b/ja_JP.eucJP/books/handbook/kerneldebug/chapter.sgml
index 1d6eab669c..15b639fe1b 100644
--- a/ja_JP.eucJP/books/handbook/kerneldebug/chapter.sgml
+++ b/ja_JP.eucJP/books/handbook/kerneldebug/chapter.sgml
@@ -1,690 +1,690 @@
カーネルデバッグ
原作 &a.paul; and &a.joerg;
- 訳: &a.jp.yoshiaki;.
- 18 March 1997.
+ 訳: &a.jp.yoshiaki;. 1997 年 3 月 18 日.
kgdb
によるカーネルのクラッシュダンプのデバッグ
ここではクラッシュダンプ (crash dump : 訳注 この文脈では
kernel 自身
の異常によって停止した場合に出力されるイメージを指します)
によるカー ネルデバッグの方法を示します.
ここではダンプするための十分なスワップ
(swap) の容量があるものとします.
もし複数のスワップパーティションを持ち,
最初のパーティションがダンプ
を保持するのに十分な大きさを持たない場合は
別のダンプデバイスを使うよ
うに (config kernel 行で)
カーネルのコンフィグをおこなうか, &man.dumpon.8;
コマンドを使って別のデバイスを示すことができます. &man.dumpon.8;
を使うもっともよい方法は変数 dumpdev を
/etc/rc.conf で設定することです. 一般的には
/etc/fstab で設定されているスワップデバイスが
使われるでしょう.
スワップに使えないデバイスへのダンプ,
例えばテープへのダンプは現在サポートさ
れていません. カーネルのコンフィグは
config -g によって行ってください.
FreeBSD
カーネルのコンフィグレーション
には FreeBSD のカーネルの設定の詳細がありますので
参照してください.
&man.dumpon.8; コマンドを使ってどこへダンプするか
カーネルに伝えてください
(&man.swapon.8; によってそのパーティションが
スワップとして設定された
後でなければならないことに注意してください). これは普通は
/etc/rc.conf や /etc/rc
で設定されます. あるいは
別の方法としてカーネルコンフィグレーションファイルの
config 行の dump 節 で
ダンプデバイスをハードコードすることができます.
この方法はあまりよくは
ありません. カーネルがブート時に crash
する場合のクラッシュダンプを取り
たい時だけ使うべきです.
以下では kgdbという用語は
- gdbを “カーネルデバッグモード”
- で動かしていることを意味します. gdbを
+ gdb
+ をカーネルデバッグモード
で動かしていることを意味します.
+ gdb を
オプションをつけて起動するか
kgdbという名前でリン
クして起動することでこのモードになります. デフォルトでは
このリンク は作られていません. また, このアイデアは
GNU関係者たちが彼らのツール
を別の名前で呼び出した時に異なった動作をするということを
好まない, と いう点で不評です.
あるいは将来この機能を廃止することになるかもしれません.
カーネルを作った時にそのコピーを
kernel.debug という名前で作 りましょう.
また, オリジナルに対して strip
-gを実行します.
オリジナルを普通にインストールします. また strip
していないカーネル も同様にインストールすることができますが,
シンボルテーブルの参照時間
がいくつかのプログラムでは劇的に増加するでしょう. また,
カーネル全体 はブート時に読み込まれ
スワップアウトされないため数メガバイトの物理メ
モリが無駄になります.
例えばブートプロンプトで
新しいカーネルの名前をタイプすることによって,
新しいカーネルをテストした場合で,
再びシステムを動かすのに別のカーネ
ルで立ち上げることが必要な場合はブートプロンプトで
フラグ
を使いシングルユーザの状態にしてください.
そして以下のような操作をおこな います.
&prompt.root; fsck -p
&prompt.root; mount -a -t ufs # /var/crash 用のファイルシステムを書き込み可能にする
&prompt.root; savecore -N /kernel.panicked /var/crash
&prompt.root; exit # ...マルチユーザモードへ移行
ここに示した &man.savecore.8; は (現在動いているものとは別の)
カーネルのシンボル名の抽出をおこなうために使っています.
抽出はデフォルトで
は現在動いているカーネルに対しておこなわれ,
クラッシュダンプとカーネルシンボ
ルのくい違いのためにまったく何もしません
(訳注:そのためにオプション
で実際にダンプをおこしたカーネルを指定します).
クラッシュダンプの起きた後に
/sys/compile/WHATEVERへ行き
kgdbを動かします. kgdb
より次のようにします.
symbol-file kernel.debug
exec-file /var/crash/kernel.0
core-file /var/crash/vmcore.0
こうすると,
クラッシュダンプを使ってカーネルソースを他のプログラムと同様に
デバッグすることができます.
次に kgdb
での手順のセッションのログを示します. 長い行は読
みやすくするために改行しました. また,
参照のために行番号を入れてあり ます. ただし, これは実際の
pcvtコンソールドライバの開発中の実際のエ
ラーのトレースです.
1:Script started on Fri Dec 30 23:15:22 1994
2:&prompt.root; cd /sys/compile/URIAH
3:&prompt.root; kgdb kernel /var/crash/vmcore.1
4:Reading symbol data from /usr/src/sys/compile/URIAH/kernel
...done.
5:IdlePTD 1f3000
6:panic: because you said to!
7:current pcb at 1e3f70
8:Reading in symbols for ../../i386/i386/machdep.c...done.
9:(kgdb) where
10:#0 boot (arghowto=256) (../../i386/i386/machdep.c line 767)
11:#1 0xf0115159 in panic ()
12:#2 0xf01955bd in diediedie () (../../i386/i386/machdep.c line 698)
13:#3 0xf010185e in db_fncall ()
14:#4 0xf0101586 in db_command (-266509132, -266509516, -267381073)
15:#5 0xf0101711 in db_command_loop ()
16:#6 0xf01040a0 in db_trap ()
17:#7 0xf0192976 in kdb_trap (12, 0, -272630436, -266743723)
18:#8 0xf019d2eb in trap_fatal (...)
19:#9 0xf019ce60 in trap_pfault (...)
20:#10 0xf019cb2f in trap (...)
21:#11 0xf01932a1 in exception:calltrap ()
22:#12 0xf0191503 in cnopen (...)
23:#13 0xf0132c34 in spec_open ()
24:#14 0xf012d014 in vn_open ()
25:#15 0xf012a183 in open ()
26:#16 0xf019d4eb in syscall (...)
27:(kgdb) up 10
28:Reading in symbols for ../../i386/i386/trap.c...done.
29:#10 0xf019cb2f in trap (frame={tf_es = -260440048, tf_ds = 16, tf_\
30:edi = 3072, tf_esi = -266445372, tf_ebp = -272630356, tf_isp = -27\
31:2630396, tf_ebx = -266427884, tf_edx = 12, tf_ecx = -266427884, tf\
32:_eax = 64772224, tf_trapno = 12, tf_err = -272695296, tf_eip = -26\
33:6672343, tf_cs = -266469368, tf_eflags = 66066, tf_esp = 3072, tf_\
34:ss = -266427884}) (../../i386/i386/trap.c line 283)
35:283 (void) trap_pfault(&frame, FALSE);
36:(kgdb) frame frame->tf_ebp frame->tf_eip
37:Reading in symbols for ../../i386/isa/pcvt/pcvt_drv.c...done.
38:#0 0xf01ae729 in pcopen (dev=3072, flag=3, mode=8192, p=(struct p\
39:roc *) 0xf07c0c00) (../../i386/isa/pcvt/pcvt_drv.c line 403)
40:403 return ((*linesw[tp->t_line].l_open)(dev, tp));
41:(kgdb) list
42:398
43:399 tp->t_state |= TS_CARR_ON;
44:400 tp->t_cflag |= CLOCAL; /* cannot be a modem (:-) */
45:401
46:402 #if PCVT_NETBSD || (PCVT_FREEBSD >= 200)
47:403 return ((*linesw[tp->t_line].l_open)(dev, tp));
48:404 #else
49:405 return ((*linesw[tp->t_line].l_open)(dev, tp, flag));
50:406 #endif /* PCVT_NETBSD || (PCVT_FREEBSD >= 200) */
51:407 }
52:(kgdb) print tp
53:Reading in symbols for ../../i386/i386/cons.c...done.
54:$1 = (struct tty *) 0x1bae
55:(kgdb) print tp->t_line
56:$2 = 1767990816
57:(kgdb) up
58:#1 0xf0191503 in cnopen (dev=0x00000000, flag=3, mode=8192, p=(st\
59:ruct proc *) 0xf07c0c00) (../../i386/i386/cons.c line 126)
60: return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
61:(kgdb) up
62:#2 0xf0132c34 in spec_open ()
63:(kgdb) up
64:#3 0xf012d014 in vn_open ()
65:(kgdb) up
66:#4 0xf012a183 in open ()
67:(kgdb) up
68:#5 0xf019d4eb in syscall (frame={tf_es = 39, tf_ds = 39, tf_edi =\
69: 2158592, tf_esi = 0, tf_ebp = -272638436, tf_isp = -272629788, tf\
70:_ebx = 7086, tf_edx = 1, tf_ecx = 0, tf_eax = 5, tf_trapno = 582, \
71:tf_err = 582, tf_eip = 75749, tf_cs = 31, tf_eflags = 582, tf_esp \
72:= -272638456, tf_ss = 39}) (../../i386/i386/trap.c line 673)
73:673 error = (*callp->sy_call)(p, args, rval);
74:(kgdb) up
75:Initial frame selected; you cannot go up.
76:(kgdb) quit
77:&prompt.root; exit
78:exit
79:
80:Script done on Fri Dec 30 23:18:04 1994
上の出力についてのコメントをします.
line 6:
これは DDB (後述) からのダンプです. このため
- “because you said to!” という
+ because you said to!
という
panicコメントがつき, ページフォルトのト ラップによって
DDBに入ったことが原因の, やや長いスタックトレー
スがあります.
line 20:
スタックトレースでのこれは
trap()関数の位置で す.
line 36:
新しいスタックフレームの使用を指定しています. これは現
在は必要ありません. trapの場合ではスタックフレームは正
しい場所を指していると考えられます. (私は新しいコアダンプ
を持っていません. 私のカーネルは長い間 panicを起こしていま
せん.) ソースコードの
- 403行を見ると,“tp”ポインタのアク
+ 403 行を見ると, tp
ポインタのアク
セスが失敗しているか配列のアクセスが範囲外である可能性が高
いことがわかります.
line 52:
怪しいポインタですが,
アクセスは正常におこなえました.
line 56:
ところが, 明らかにポインタはゴミを指しています. これで
エラーを見つけました! (ここのコードの部分からはよくわかり
ませんが,
tp->t_lineはコンソールデバイスの規定
する行を参照しているので,
もっと小さな整数でなければなりませ ん. )
DDD によるクラッシュダンプのデバッグ
カーネルのクラッシュダンプは ddd
のようなグラフィカルなデバッガで調べることもできます.
通常はコマンドラインで オプションをつけて
ddd を起動します. たとえば:
&prompt.root; ddd -k /var/crash/kernel.0 /var/crash/vmcore.0
クラッシュダンプを ddd
のグラフィカルなインターフェースを使って
見ることができます.
突然ダンプした場合の解析
カーネルが予想もしない時にコアダンプして config
-g
を行ってコンパイルされていなかった場合にはどうしたら
よいでしょう. すべてが失われるわけではありません.
パニックを起こさないでください.
もちろん, クラッシュダンプを使えるようにする必要があります.
使い方は前述の部分を見てください.
カーネルのコンパイルディレクトリ
(/usr/src/sys/arch/conf)
で, 設定ファイルを編集します. 以下の行のコメントを外します
(行が存在しなければ追加します):
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
カーネルを再構築しましょう.
Makefileのタイムスタンプの変更により, 例えば trap.o
などのいくつかの他のオブジェクトファイルも作り直さ
れます. 少しの幸運があれば,
オプションが追加されても作ら
れるコードは変更されず, いくらかのデバッグシンボル以外には
問題を
起こしたコードとそっくりな新しいカーネルを手に入れることが
できます. 少なくとも &man.size.1;
コマンドで古い方と新しい方のサイズを比較すべ きです.
これが食い違っていれば,
多分あきらめなければならないでしょう.
ダンプを使って前述のように動かして調べます.
デバッグシンボルは 必ずしも十分ではありません.
上の例ではスタックトレースでいくつかの関
数の行番号や引数リストが表示されないかもしれません.
もしより多くのデ バッグシンボルが必要であれば,十分になるまで
適切なオブジェクトファイ ルを消して (makeして)
kgdbセッションを繰り返してください.
これは必ずしもうまく動くと保証はできません.
しかしほとんどの場合でう まくいくでしょう.
DDBを使ったオンラインカーネルデバッグ
kgdb
は非常に高レベルのユーザインタフェースを提
供するオフラインデバッガですが, いくつかのことはできません.
(できないことの中で)
極めて重要なことはカーネルコードへのブレークポイ
ントの設定とシングルステップ実行です.
カーネルの低レベルデバッグが必要であれば, DDBと呼ばれる
on-lineデバッ ガが使えます. ブレークポイントの設定,
シングルステップのカーネルの実 行,
変数の検査と変更などができます.
ただし,これはカーネルのソースファ
イルにアクセスすることはできません.
kgdbのようにすべてのデ
バッグ情報にはアクセスできず, globalと
staticのシンボルにアクセス することができるだけです.
カーネルに DDB
を含めるためにはコンフィグファイルに次のようなオプショ
ンを加えて,
options DDB
再構築をおこないます. (
FreeBSDのカーネルの設定の詳細については FreeBSD
カーネルのコンフィグレーションを参照してくださ
い.
もしブートブロックが古いバージョンですと,
デバッガのシンボルが完
全にはロードされないかもしれませんので注意してください. DDB
シンボル がロードされるようにブートブロックを
最新の物にアップデートしてくださ い)
DDB カーネルの実行において,
DDBに入るいくつかの方法があります. 最初 の,
最も早い方法はブートプロンプトが出ている時に
のブート フラグをタイプすることです.
カーネルはデバッグモードで起動し, デバ イスのプローブ以前に
DDBに入ります. したがって, デバイスのプローブ/初期
設定ファンクションのデバッグができます.
2つ目のシナリオはキーボードのホットキーで, 通常は
Ctrl-Alt-ESCです. syscons ではホットキーは再設定することができ,
配付されているいくつかの キーマッピングでは別のキーに
再設定されていますので確認しておいてください. シリアルラインの
BREAKを使って シリアルコンソールから DDBへ入ることを可
能にするオプションもあります
(カーネルコンフィグレーションファイルの options
BREAK_TO_DEBUGGER). これは 多くのつまらないシリ
アルアダプタが, 例えばケーブルを引き抜いた時に
BREAK状態を意味もなく
作り出してしまうのでデフォルトでは無効になっています.
3つ目は, DDB
を使うようになっているカーネルがパニック状態になると DDB
へ入るというものです. このため,
無人運転するマシンのカーネルにDDBを
入れるのは賢明ではありません.
DDB のコマンドはおおまかには gdb
のいくつかのコマンドと似て
います. おそらく最初にブレークポイントを
設定する必要があるでしょう.
b function-name
b address
数値はデフォルトでは16進数で,
シンボル名とはまったく異ります. 16進数で a-f
の文字で始まる場合は, 先頭に 0x
をつける必要があります(それ以外の数字の場合はどちらでもか
まいません). function-name +
0x103のような単純な式を使うこ とができます.
割り込みされたカーネルから処理を続行するためには,
c
とタイプするだけです.
スタックのトレースには
trace
とします.
DDB にホットキーで入った場合は, カーネルはその
(ホットキーの) 割り込み
の処理を行っていますのでスタックトレースは
あまり役にたたないことに注 意してください.
ブレークポイントを削除したい場合は,
del
del address-expression
とします.
最初の形式はブレークポイントにヒットしたすぐ後で使うことが でき,
現在のブレークポイントを削除します. 2番目の形式では任意のブレー
クポイントを削除することができますが,
次の形式で得られるような正確な
アドレスを与えることが必要です.
show b
カーネルをシングルステップ実行させるには
s
としてみてください. これは関数呼出し先までステップ実行 (step
into function) するでしょう.
次のステートメントが終了するまでのDDBトレースは
n
によっておこなうことができます.
これは gdb の next
命令とは異ります. gdbの
finish命令と似ています.
メモリ上のデータを調べるには (例として) 次のようにします.
x/wx 0xf0133fe0,40
x/hd db_symtab_space
x/bc termbuf,10
x/s stringbuf
word/halfword/byte 単位でアクセスをおこない, hex (16進)
/dec (10進) /
char (文字) /string (文字列) で表示します.
カンマの後ろの数字はオブジェク
トカウントです. 次の 0x10個の要素を表示するには, 単純に
x ,10
とします. 同様に次のように使うことができます.
x/ia foofunc,10
foofunc
の最初の 0x10個の命令語をディスアセンブルし,
foofunc
の先頭からのオフセットとともに表示します.
メモリの内容を変更するには writeコマンドを使います.
w/b termbuf 0xa 0xb 0
w/w 0xf0010030 0 0
コマンドモディファイアの
(b/h/w)
はデータを 書くサイズを定義し,
これに続く最初の式は書き込むアドレス, 残りがこれ
に続く連続するメモリアドレスに書き込まれるデータになります.
現在のレジスタ群の内容を知りたい場合は
show reg
とします. また, 単一のレジスタの値を表示するには, 例えば
p $eax
とします. また値の変更は
set $eax new-value
とします.
DDBからカーネルの関数を呼び出す必要がある場合は, 単に
call func(arg1, arg2, ...)
とします. return 値が出力されます.
動いているプロセスの &man.ps.1; スタイルの概要は
ps
です.
カーネルの失敗の原因の調査が終わったらリブートすべきです.
それまでの 不具合によりカーネルのすべての部分が期待するような
動作をしているわけ ではないということを忘れないでください.
以下のうちいずれかの方法でシ
ステムのシャットダウンおよびリブートを行ってください.
panic
カーネルをコアダンプしてリブートしますので, 後で
kgdbによってコアの高 レベル解析をすることができます.
このコマンドは通常, 一度
continue命令を使った後に
使うことになるでしょう.
call boot(0)
は動いているシステムを `clean' に shut
downするよい方法です. すべて のディスクを
sync()して最後にリブートします.
ディスクとカー
ネルのファイルシステムインタフェースが破損していない限り,
ほぼ完全 に `clean'にシャットダウンするよい方法でしょう.
call cpu_reset()
は大惨事を防ぐための最後の手段で 「赤い大きなボタン」
を押すのとほとんど 同じです.(訳注:
リセットボタンを押すのとほぼ同じであるという意味です)
短いコマンドの要約は
help
をタイプします. ただし, デバッグセッションのために
&man.ddb.4; の
マニュアルページのプリントアウトを用意しておくことを
強くお奨めします.
カーネルのシングルステップ中にオンラインマニュアルを
読むことは難しい ということを覚えておいてください.
リモート GDB を使ったオンラインカーネルデバッグ
この機能は FreeBSD 2.2 からサポートされました.
これは本当にすばらし い機能です.
GDB はすでにかなり以前より
リモートデバッグ をサポートしてい ます.
これはシリアル回線を使い非常に単純なプロトコルで行ないます.
もちろん, この方法では今までに示した方法とは違い,
2台のマシンが必 要になります. 1台はデバッグ環境のためのホストで,
すべてのソースとす
べてのシンボルを含んだバイナリのコピーを持っています. もう 1台は
ターゲットマシンで, 同一のカーネルのコピー (ただしデバッグ情報は
取り除いてあるもの) を単に実行するためのものです.
この場合, カーネルのコンフィグレーションは config
-g で行な い,
を含めなくてはなりません. そうして通常通りコンパイルし ます.
こうして作ったバイナリファイルはデバッグ情報のために非常に大き
くなります. このカーネルをターゲットマシンにコピーして
strip -x でデバッグシンボルを取り除きます.
そして ブートオプションを使いブートします.
sio デバイスにフラグ 0x80 が設定されているターゲットマシンの
シリアル回線を, デバッグホストのいずれかのシリアル回線に
つないでください.
それからデバッグ(訳注:ホスト)マシン上で, ターゲットとなって
いるカーネルのコンパイルディレクトリで gdb を起動します:
&prompt.user; gdb -k kernel
GDB is free software and you are welcome to 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.
GDB 4.16 (i386-unknown-freebsd),
Copyright 1996 Free Software Foundation, Inc...
(kgdb)
リモートデバッグセッションの初期化
(1番目のシリアルポートを使用する ことの設定)
を以下のように行ないます.
(kgdb) target remote /dev/cuaa0
次にターゲットマシン (デバイスのプローブ直前で DDB
に入っています) で次のように入力します:
Debugger("Boot flags requested debugger")
Stopped at Debugger+0x35: movb $0, edata+0x51bc
db> gdb
DDB は次のような出力を返すでしょう.
Next trap will enter GDB remote protocol mode
gdbと入力するたびに リモート GDB
とローカル DDB が交互に切り替わ ります.
トラップをすぐに起こすために単に ``s'' (step) と入力して下 さい.
そうするとホストの GDB はターゲットのカーネルの制御を行なうよ
うになります.
Remote debugging using /dev/cuaa0
Debugger (msg=0xf01b0383 "Boot flags requested debugger")
at ../../i386/i386/db_interface.c:257
(kgdb)
このセッションではソースコードへのフルアクセスや Emacs の
window 上 の gud-mode (これは別の Emacs window
に自動的にソースコードを表示し ます) で動かすなど, 通常の GDB
セッションでできることのほとんどのこ とができます.
リモート GDB は LKM のデバッグも行なうことができます.
最初に LKM を デバッグシンボルを含めた形で作ります.
&prompt.root; cd /usr/src/lkm/linux
&prompt.root; make clean; make COPTS=-g
そしてターゲットマシン上で
モジュールのこのバージョンをインストールし ます.
これをロードしてから, modstat
を使ってロードされている ことを確認してください:
&prompt.root; linux
&prompt.root; modstat
Type Id Off Loadaddr Size Info Rev Module Name
EXEC 0 4 f5109000 001c f510f010 1 linux_mod
示されたロードアドレスに 0x20
(a.outのヘッダはおそらくこの大きさでしょ う) を加えます.
それがモジュールコードの再配置されるアドレスです. GDB の
add-symbol-file
コマンドを使ってデバッガにモジュールの 情報をつたえます.
(kgdb) add-symbol-file /usr/src/lkm/linux/linux_mod.o 0xf5109020
add symbol table from file "/usr/src/lkm/linux/linux_mod.o" at
text_addr = 0xf5109020?
(y or n) y
(kgdb)
これで LKM
のすべてのシンボルにアクセスできるようになります.
コンソールドライバのデバッグ
DDBを動かすためにはコンソールドライバが必要ですから,
コンソールドラ イバ自身に不具合のある場合は複雑になります.
シリアルコンソールを利 用する方法 (ブートブロックを変更するか
Boot:プロンプトで
と入力する) を思い出してください.
そして標準ター ミナルを最初のシリアルポートに設定します. DDBは,
もちろんシリアルコ ンソールを含むいずれの
コンソールドライバの設定でも動作します.
diff --git a/ja_JP.eucJP/books/handbook/kernelopts/chapter.sgml b/ja_JP.eucJP/books/handbook/kernelopts/chapter.sgml
index fa8f99ddde..6b3b94e6df 100644
--- a/ja_JP.eucJP/books/handbook/kernelopts/chapter.sgml
+++ b/ja_JP.eucJP/books/handbook/kernelopts/chapter.sgml
@@ -1,215 +1,214 @@
カーネルコンフィグレーションの
新しいオプションを追加する
原作: &a.joerg;
訳: &a.jp.yoshiaki;.
29 December 1996.
この章をお読みになる前に FreeBSD
カーネルのコンフィグレーション の章の内容を
理解しておいてください.
そもそもカーネル
オプションって何?
カーネルオプションの使い方は基本的には
FreeBSD
カーネルのコンフィグレーション
の章に書いてあります.
- そこには “伝統的な形式” と “新しい形式”
- のオプションの説明があります.
+ そこには伝統的な形式
と新しい形式のオプションの説明があります.
すべてのカーネルのオプションを新しい形式のものに置き換え,
コンフィグファイル
を修正して &man.config.8; を実行した後に
カーネルのコンパイルディレクトリで
make depend を実行すれば,
ビルドプロセスが自動的に変更された
オプションを検出し, 必要なファイルだけを
再コンパイルするようにすることが
最終的な目的です. &man.config.8;
を実行するたびに古いコンパイルディレクトリ
を消してしまう現在のやりかたは,
やがておこなわれなくなるでしょう.
基本的に, カーネルオプションはカーネルのコンパイルプロセスの
C プリプロセッサのマクロの定義にすぎません. 実際に選択的に make
できる ようにするためには, 対応する部分のカーネルソース
(またはカーネルの .h ファイル)
がオプションを使えるようにあらかじめ書かれていなければ
なりません.
つまりデフォルト値をコンフィグファイルのオプションで置き換え
られるようになっていなければなりません.
これは普通は次のようになっています.
#ifndef THIS_OPTION
#define THIS_OPTION (some_default_value)
#endif /* THIS_OPTION */
この場合,
管理者がコンフィグファイルのオプションに別の値を記述すれば,
デフォルトの設定を打ち消して新しい値に置き換えられます. 当然,
新しい値はプリプロセッサによってソースコード中で
置き換えられるため, デフォルトの値が使われていた場所において C
の式として有効な値でなければ なりません.
また, 単に特定のコードを有効にするか
無効にするかを設定するための
値を持たないオプションも作ることができます.
#ifdef THAT_OPTION
[あなたのコードが入ります]
#endif
コンフィグファイルに THAT_OPTION
と記述するだけで (値の有無 にかかわらず)
対応する部分のコードが組み込まれます.
C 言語にくわしい人であれば
- “コンフィグオプション” とされているもの
+ コンフィグオプション
とされているもの
は少なくとも一つの #ifdef
で参照されているということはすぐに理解 できるでしょう. ところで,
ごく一部の人たちは次のようなものを試して
みようとするかもしれません.
options notyet,notdef
このようにコンフィグファイルをしておくと,
カーネルのコンパイルは うまく行きません. :-)
(訳注: たとえば MATH_EMULATE のように
有効/無効のためのパラメタを 持たないオプションの場合,
無効とするためのパラメタをつけて, オプション
で「無効とする」と明示することはできないという意味です)
明らかに,
任意のオプション名がカーネルソースツリー全体でどのように
使われているかを追いかけることは非常に難しいことです. このことが
新しい形式
のオプションの機構を採り入れる理由の背景です.
ここではそれぞれのオプションは
カーネルコンパイルディレクトリにある別々の
.h ファイルとなり,
opt_foo.h
という名前に されます. この方法では, 通常の Makefile
の依存関係が適用され, make
プログラムはオプションが変更された時に再コンパイルが必要な
ものを見つけることができます.
古い形式のオプションの機構は,
局部的なオプションや実験的なオプション
のような一時的に利用されると考えられるオプションにおいては
有効です. つまり #ifdef
をカーネルのソースに追加するのは簡単であり,
それがそのままカーネルコンフィグオプションになります. この場合,
管理者はオプションの利用において
依存関係を把握しておく責任があります (また,
手動でカーネルの一部分を
強制的に再コンパイルする必要があるかもしれません).
サポートされている
オプションのすべてについて一つでも変更があると, &man.config.8;
は サポートされていないオプションがコンフィグファイルの中に
あるという警告 を出しますが, カーネルの Makefile
内にはそれを含めます.
ではどのようにして追加するのでしょう?
最初に sys/conf/options (または
sys/<arch>/conf/options.<arch>, たとえば sys/i386/conf/options.i386)
を編集し, 新しいオプション を含めるのに最適な
opt_foo.h
ファイルを選びます.
新しいオプションの必要がなくなったとしたら,
これを取り除きます. たとえば, SCSI
サブシステムに関するすべてのふるまいについてのオプション
の変更は opt_scsi.h に入れられます.
デフォルトでは, 適切 なオプションファイルに単に記述されます.
たとえば FOO であれば 値は対応するファイルの
opt_foo.h に格納されます. これは右端に別
のファイル名を書いて置き換えることができます.
新しいオプションを加えるのに使えそうな
opt_foo.h
がない場合は新しい名前を作ってください. 意味のある名前を作り
options[.<arch>]
ファイル に新しいセクションのコメントをつけてください.
&man.config.8; は自動的
に変更を検出して, 次の実行からは (訳注: 新しい
.h) ファイル を作ります.
ほとんどのオプションはヘッダファイルに入れられます.
大量のオプションを一つの
opt_foo.h
にまとめると
コンフィグファイルの一つのオプションを変更したときに
多くのファイルが 再コンパイルされる原因になります.
新しいオプションに依存するカーネルファイルは
最終的には見つけ出 されます. ただし,
オプションを作っただけで対応するソースがどこにも
ない場合は別です.
&prompt.user; find /usr/src/sys -type f | xargs fgrep NEW_OPTION
オプションに対応するソースを見つけるのに上記のコマンドは
便利です. 見つけたすべてのファイルで編集, 追加をおこないます.
#include "opt_foo.h"
ファイルの先頭の, すべての
#include <xxx.h> より前に入れます.
この場合, オプションによって次のようにしてデフォルト値
を持たせている標準のヘッダファイル内の値を置き換えるため,
順番は非常に 重要です.
#ifndef NEW_OPTION
#define NEW_OPTION (something)
#endif
システムヘッダファイル (たとえば
/usr/include/sys/ にある ファイル)
をオプションで置き換えることは, ほとんどの場合で失敗します.
そうすると, ヘッダファイルを深刻な状態に破壊してしまうので,
include しないとオプションの値によって
不整合が起きてしまう場合を除き, それらの ファイルに
opt_foo.h
を include しないでください.
そう, 現在このような例がいくつか存在していますが,
必ずしも正しい方法 ではありません.