間接参照先の取得
間接参照先の内容を知りたいケースの最も典型的な例は,main()
関数のargv
引数から文字列を取得したい,
DTrace動作原理に由来する制限
第2回で触れたように,
そのため,copyinstr()
サブルーチンを使用する必要がありました。
間接参照先の情報を取得する場合も,
例として使用するmain()
関数のargv
引数の場合,char*
" の配列」
つまり argv
の値を直接使用した参照ができないのは勿論,argv
の値を元にchar*
" の配列」copyinto
しても,char*
"」,
間接参照先の取得
main()
関数のargv[0]
が参照する文字列の取得を例に,
リスト 6 argv[0]
文字列取得スクリプト
(watch_
)
self uintptr_t* buf;
pid$target:$1:main:entry
{
self->buf = alloca(sizeof(uintptr_t));
copyinto(arg1, sizeof(uintptr_t), self->buf);
printf("argv[0]='%s'", copyinstr(*(self->buf)));
}
copyinto()
サブルーチンでカーネル空間に取り込んだアドレス情報self->buf
に格納)copyinstr()
サブルーチンを実施することで,argv[0]
に相当)
Dスクリプト冒頭における"self uintptr_
" 記述は,self->buf
の型を宣言しておくことで,
DTraceは概ね自動的に型を判定してくれますが,
それでは実際に動かしてみましょう。
図3 argv[0]
文字列の採取
$ dtrace -s watch_argv0.d \ -32 \ -c '/usr/bin/true' \ true dtrace: script 'watch_argv0.d' matched 1 probe dtrace: pid 911 has exited CPU ID FUNCTION:NAME 0 60346 main:entry argv[0]='/usr/bin/true' $
採取対象に/usr/
コマンドを用いているのは,
ポインタ値ビット幅の問題
先ほどの実行例dtrace
コマンド実行の際に,-32
"オプションを使用しました。
実はこのオプションは,
間接参照先の取得を行う場合,
Dスクリプトにおけるポインタ値のビット幅は,sizeof(intptr_
" といった式を元に算出されますが,sizeof(intptr_
" 値と,sizeof(intptr_
" 値が異なります。
そして,
そこで,-32
"オプションによって指定するわけです。
なお,isainfo -b
"などによりカーネルの動作モードを確認することをお勧めします。
- ※2)
- 32bitアプリケーションを32bitカーネル上で,
あるいは64bitアプリケーションを64bitカーネル上で稼動させている場合は, 特に問題はありません。
しかし,64bitカーネル環境であっても, OSに同梱されているアプリケーションや, コンパイル時にデフォルトで生成される実行可能形式は, 32bitアプリケーションであることが殆どです。
可変長間接参照への応用
main()
関数のargv[]
引数から任意の要素文字列を取得するような,
リスト7 argv[]
引数の任意個表示
self uintptr_t* argv;
pid$target:$1:main:entry
{
self->index = -1;
}
pid$target:$1:main:entry
/(self->index += 1) < arg0/
{
self->argv = alloca(sizeof(uintptr_t));
copyinto(arg1 + (sizeof(uintptr_t) * self->index),
sizeof(uintptr_t),
self->argv);
printf("argv[%d]='%s'",
self->index, copyinstr(*(self->argv)));
}
:
(以下,同じ記述の繰り返し)
:
argv
引数(=arg1
)に対してsizeof(uintptr_
をself->index
倍した値を加算することで,argv[self->index]
に相当するアドレス値を算出しているため,copyinto()
サブルーチンを使用する箇所が,
次回予告
次回は,