彷徨えるフジワラ

年がら年中さまよってます

DTrace VM 内部コード

DTrace は実際の情報採取処理がカーネルモジュールで実施されていて、その際の処理は一種の VM 上で稼動するイメージとなっている。

で、DTrace の内部処理に関して調べるついでに、内部コードに関して色々試してみた。

とりあえず、vn_open(= open(2) システムコールの下請けみたいなもの)実行時のスレッド状態フラグを表示させる、というありがちな D スクリプトから、内部コードを生成してみる。

$ cat show_t_flag.d
fbt::vn_open:entry
{ printf("%p", curthread->t_flag); }
$ dtrace -S -s show_t_flag.d

DIFO 0x6eab40 returns D type (integer) (size 2)
OFF OPCODE      INSTRUCTION
00: 29010001    ldgs DT_VAR(256), %r1		! DT_VAR(256) = "curthread"
01: 25000002    setx DT_INTEGER[0], %r2		! 0x24
02: 07010201    add  %r1, %r2, %r1
03: 20010001    lduh [%r1], %r1
04: 23000001    ret  %r1

NAME             ID   KND SCP FLAG TYPE
curthread        100  scl glb r    D type (pointer) (size 8)
$

やぁ、まんま SPARC アセンブラだなぁ。curthread の保持するアドレスに、t_flag オフセット分の 0x24 を足した値で間接アドレッシングして値を取得、といったところか。コレなら読める。
シンボルテーブル(勝手にそう呼んじゃうけど、要するに DT_VAR() 参照先)は表示されるのに、整数値テーブル(これまた勝手にそう呼んじゃうけど DT_INTEGER[] 参照先)は表示されないのね。まぁ、コメントがあるから良いか。

そういう意味では、DT_VAR() の添え字は 10 進数なのに、シンボルテーブル側の表示は 16 進数、ってのも何か変だけどね。

で、気になるのが、printf() 部分の内部コードが生成されないこと。フォーマッティングとかはどうなるんだ?

ということで、もうちょっと複雑なスクリプトを食わせてみる。

$ cat show_t_flag2.d
fbt::vn_open:entry
{
    printf("%p->t_flags=%d",
           curthread, curthread->t_flag);
}
$ dtrace -S -s show_t_flag2.d

DIFO 0x6eab40 returns D type (pointer) (size 8)
OFF OPCODE      INSTRUCTION
00: 29010001    ldgs DT_VAR(256), %r1		! DT_VAR(256) = "curthread"
01: 23000001    ret  %r1

NAME             ID   KND SCP FLAG TYPE
curthread        100  scl glb r    D type (pointer) (size 8)

DIFO 0x75dae0 returns D type (integer) (size 2)
OFF OPCODE      INSTRUCTION
00: 29010001    ldgs DT_VAR(256), %r1		! DT_VAR(256) = "curthread"
01: 25000002    setx DT_INTEGER[0], %r2		! 0x24
02: 07010201    add  %r1, %r2, %r1
03: 20010001    lduh [%r1], %r1
04: 23000001    ret  %r1

NAME             ID   KND SCP FLAG TYPE
curthread        100  scl glb r    D type (pointer) (size 8)
$

あぁ、そういうことか。

この結果を元に他にも色々試してみた結果、結局内部コードが生成されるのは:

に限定されていることがわかった。つまり、printf() 等のフォーマッティング部分は、カーネル内部では実施せずに、ユーザ空間= dtrace コマンド側に持ち越している模様。

結局試し損ねたけど、多分「条件指定」も内部コードを生成しているのじゃないかな?

VM 内部コード処理ループに相当する関数が、usr/src/uts/common/dtrace/dtrace.c で定義されている dtrace_probe() なのだが、これを見ても printf() 類は別処理扱いになっているので、多分合っている筈。