引数文字列の採取
文字列表示に関する制限
関数呼び出しにおける引数値表示の次は,
show_
コマンドは,main()
関数のargv[0]
引数,showname
を呼び出すものと仮定します。
リスト6 採取対象関数showname
)
static void
showname(const char* name)
{
.....
}
先ほどの例ですでに,%s
" フォーマットとprobefunc
組み込み変数を用いたprintf()
による文字列表示を行いましたので,showname()
関数呼び出しにおける文字列引数を表示してみましょう。
リスト7 文字列引数採取Dスクリプト~その1
pid$target:show_args:showname:entry
{
printf("(%s)\n", arg0);
}
しかし,dtrace
コマンドを実行してみると……
図2 文字列引数の採取~その1
$ dtrace -s watch_arg_val.d \ -q \ -c './show_args' dtrace: failed to compile script watch_args_str_bad.d: line 3: \ printf( ) argument #2 is incompatible with conversion #1 prototype: conversion: %s prototype: char [] or string (or use stringof) argument: int64_t $
何やらエラーが表示されてしまいました。
まず第1の問題は,int64_
)%s
"が期待する型と一致していない点にあります。
もうひとつの問題は,
実はDTraceは,
「文字列」
- 妥当な長さであるか不明
- 本当に "\0" で終端しているか不明
- 当該メモリ領域が使用可能であるか不明
といった点でprintf("%s")
による出力が直接は実施できないように,
先の例で使用した probefunc
がprintf("%s")
で表示できたのは,probefunc
の値が
stringof
サブルーチンstring
型オブジェクトを返却します。
リスト8 文字列引数採取Dスクリプト~その2
pid$target:show_args:showname:entry
{
printf("(%s)\n", stringof(arg0));
}
それではエラーメッセージの指示に従い,stringof
を使ったDスクリプトを実行してみると……
図3 文字列引数の採取~その2
$ dtrace -s watch_arg_val.d \ -q \ -c './show_args' dtrace: error on enabled probe ID 1 \ (ID 60308: pid11310:show_args:showname:entry): \ invalid address (0x8047d40) in action #1 $
またもやエラーが出てしまいました
実はこのエラーも,
表示しようとしている文字列の格納先arg0
の値)invalid address
")
- ※3)
- DTrace では,
採取データを外部に出力する機能を 「アクション」, スクリプト実行に閉じた機能を 「サブルーチン」 と呼び分けていますが, あまり気にする必要はないでしょう。
文字列引数の表示
前述したように,
安心してください。以下のようなDスクリプトにより,
リスト 9 文字列引数採取Dスクリプト~その3
pid$target:show_args:showname:entry
{
printf("show_args(%s)", copyinstr(arg0));
}
copyinstr
サブルーチンは,
- 文字列データを,
ユーザ空間からカーネル空間に複製 (有限長) string
(安全な文字列)型オブジェクトに変換
上記のDスクリプトを実行してみると……
図4 文字列引数の採取~その3
$ dtrace -s watch_arg_val.d \
-q \
-c './show_args'
showname(./show_args) ← 採取結果
$
今度は無事に文字列引数の内容を採取することができました。
もしも,
(1) 固定長領域に格納されていて,
(2) 必ずしも "\0" 終端していない文字列を扱う場合は,
以下の方法で文字列表示が可能です。
リスト10 固定長文字列引数採取
pid$target:show_args:showname:entry
{
printf("show_args(%s)", stringof(copyin(arg0), 64));
}
上記のDスクリプトでは,copyin
によりユーザ空間からカーネル空間に64バイト分のデータが転送され,stringof
により当該データがstring
型へと変換されます