dtrace機能を有効にしたNetBSDインストールCDを作成してみた
dtrace機能を有効にしたNetBSDインストールCDを作成してみた
NetBSDのdtrace機能を試してみようと思い立ち、@akachochinさんのNetBSD dtrace格闘記その2を元にdtrace機能を有効にしたインストールCDの作成手順をまとめてみました。
インストールCD作成準備
@akachochinさんのblogでは、インストール済みのNetBSD環境に直接dtraceまわりのカーネルモジュールをインストールしています。私の環境ではdtraceを有効にしたNetBSDのインストールCDを作成したいため、まずはインストールCD作成用のNetBSD環境を準備します。
ソースコードを展開する
NetBSD-6.1.3-i386を仮想マシンにインストールした後、ソースコードを展開します。
# mount /dev/cd0a /cdrom # cd /cdrom/source/sets/ # ls -l *.tgz -r--r--r-- 1 root wheel 43069713 Jan 19 20:15 gnusrc.tgz -r--r--r-- 1 root wheel 7661899 Jan 19 20:16 sharesrc.tgz -r--r--r-- 1 root wheel 203542266 Jan 19 20:14 src.tgz -r--r--r-- 1 root wheel 40189162 Jan 19 20:15 syssrc.tgz -r--r--r-- 1 root wheel 158393066 Jan 19 20:18 xsrc.tgz
ソースコードは/usr/src以下に展開します。
# for i in *.tgz; do tar zxvf $i -C /; done
カーネルコンフィグを修正してdtrace機能を有効化する
dtrace機能を有効にするためのカーネルコンフィグを追加します。INSECURE,KDTRACE_HOOKS,MODULARを有効にする必要がありますが、GENERICコンフィグではINSECURE,MODULARは既に有効になっていたため、KDTRACE_HOOKSのみ追加します。
# cd /usr/src/sys/ # diff -u arch/i386/conf/GENERIC.orig arch/i386/conf/GENERIC --- arch/i386/conf/GENERIC.orig 2012-08-16 00:33:00.000000000 +0900 +++ arch/i386/conf/GENERIC 2014-04-13 02:23:38.000000000 +0900 @@ -74,6 +74,7 @@ # Standard system options options INSECURE # disable kernel security levels - X needs this +options KDTRACE_HOOKS options RTC_OFFSET=0 # hardware clock is this many mins. west of GMT options NTP # NTP phase/frequency locked loop
build.shを実行する
build.shを使用して一通りのビルドを行います。ビルドは時間がかかるので、以下のスクリプトを作成し、バッチ処理的にビルドを行うようにしました。
上記のスクリプトをMac mini(2.4GHz Intel Core 2 Duo,メモリ 8GB)のVirtualBox上のNetBSDで走らせたところ、全てのビルドが完了するまで15時間程度かかりました。
ビルドが完了すると、以下の場所にdtrace機能が有効になったインストールCDが生成されます。
/usr/obj/distrib/i386/cdroms/installcd/NetBSD-6.1.3-i386.iso
OSインストール後のdtrace機能を利用するための設定投入
インストールCDが作成できたので、このCDを使用してNetBSDを再度インストールします。インストール後、dtrace用にデバイスファイルを作成します(OSインストール後に一度行うだけで良い)。
# mkdir /dev/dtrace # mknod /dev/dtrace/dtrace c dtrace 0
そして、OS起動時にdtraceに必要なカーネルモジュールをロードするよう設定します。もっとスマートな方法があると思うのですが、今回は/etc/rc.localに以下の処理を追加しました。
_MODULE=" solaris dtrace sdt fbt " for i in ${_MODULE} do echo "modload ${i}" modload ${i} done
OSを再起動するとdtrace機能が利用可能になっています。
# dtrace -l | wc -l 45326
dtrace機能を試してみる
NetBSDでdtraceが利用できるようになったので、例としてgetpid()システムコールをフックさせてみます。
"getpid"というキーワードにマッチする関数は、sys_getpid(),sys_getpid_with_ppid()の2つがあるようです。
# dtrace -l | grep getpid 21001 fbt netbsd sys_getpid entry 21002 fbt netbsd sys_getpid return 21003 fbt netbsd sys_getpid_with_ppid entry 21004 fbt netbsd sys_getpid_with_ppid return
どちらがgetpid()システムコールの実体か分からないので、"getpid"でマッチするようにしてみます。dtrace -nを実行すると、その端末内で出力待ちの状態になります。
# dtrace -n fbt:netbsd:*getpid*:entry dtrace: description 'fbt:netbsd:*getpid*:entry' matched 2 probes
別の端末にて、getpid()を実行するサンプルプログラムを用意します。
# cat _getpid.c #include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { printf("%d\n", getpid()); return 0; } # gcc -Wall -Werror -g -o _getpid _getpid.c
サンプルプログラムを実行すると、dtraceを実行している端末に以下が出力されます。
# dtrace -n fbt:netbsd:*getpid*:entry dtrace: description 'fbt:netbsd:*getpid*:entry' matched 2 probes CPU ID FUNCTION:NAME 0 21003 sys_getpid_with_ppid:entry 0 21003 sys_getpid_with_ppid:entry
getpid()の実体はsys_getpid_with_ppid()のようです。プロセスの生成時にもsys_getpid_with_ppid()は呼ばれるようで、出力が2回になっています。
# cat -n /usr/src/sys/kern/kern_prot.c 81 /* ARGSUSED */ 82 int 83 sys_getpid_with_ppid(struct lwp *l, const void *v, register_t *retval) 84 { 85 struct proc *p = l->l_proc; 86 87 retval[0] = p->p_pid; 88 retval[1] = p->p_ppid; 89 return (0); 90 }
まとめ
NetBSDでdtrace機能を試してみました。デフォルトインストールではdtrace機能が有効で無いため、カーネルとカーネルモジュールの構築が必要です。インストールCDが欲しかったので、備忘録を兼ねた一通りのビルド手順についてもまとめてみました。