DTrace ユーザーガイド

サブルーチン copyin()copyinstr() を使用する

DTrace プローブは、Solaris カーネル内で実行されます。プローブは、サブルーチン copyin() または copyinstr() を使って、ユーザープロセスのデータをカーネルのアドレス空間へコピーします。

たとえば、次のような write() システムコールがあるとします。

ssize_t write(int fd, const void *buf, size_t nbytes);

では、write システムコールに渡される文字列の内容を出力するには、どうしたらよいでしょうか。次に、正しくない D プログラムの例を示します。

syscall::write:entry
{
	printf("%s", stringof(arg1)); /* incorrect use of arg1 */
}

このスクリプトを実行すると、次のようなエラーメッセージが出力されます。


dtrace: error on enabled probe ID 1 (ID 37: syscall::write:entry): \
    invalid address (0x10038a000) in action #1

arg1 変数には、システムコールを実行しているプロセス内のメモリーを参照するアドレスを指定します。サブルーチン copyinstr() を使って、このアドレスの文字列を読み取ります。printf() アクションを使って、結果を記録します。

syscall::write:entry
{
	printf("%s", copyinstr(arg1)); /* correct use of arg1 */

このスクリプトの出力から、write システムコールに渡されるすべての文字列を確認できます。

エラーの回避

サブルーチン copyin()copyinstr() では、一度も使ったことがないユーザーアドレスからの読み取りは実行できません。アドレスが含まれているページが、過去に一度もアクセスされたことがないと、たとえそのアドレスが有効であっても、エラーが起きる可能性があります。次の例で考えてみてください。


# dtrace -n syscall::open:entry'{ trace(copyinstr(arg0)); }'
dtrace: description 'syscall::open:entry' matched 1 probe
CPU     ID                    FUNCTION:NAME
dtrace: error on enabled probe ID 2 (ID 50: syscall::open:entry): invalid address
(0x9af1b) in action #1 at DIF offset 52

前の例の出力では、このアプリケーションが正常に動作していて、arg0 に指定されたアドレスは有効です。しかし、arg0 に指定されたアドレスは、対応するプロセスがまだ一度もアクセスしたことのないページを参照しています。この問題を解決するには、カーネルまたはアプリケーションでデータが使用されるのを待ってから、データのトレースを開始する必要があります。たとえば、システムコールが復帰して、copyinstr() が適用されるまで待ちます。次の例を参照してください。


# dtrace -n syscall::open:entry'{ self->file = arg0; }' \
-n syscall::open:return'{ trace(copyinstr(self->file)); self->file = 0; }'
dtrace: description 'syscall::open:entry' matched 1 probe
CPU     ID                    FUNCTION:NAME
  2     51                      open:return   /dev/null