C/C++プログラマのためのDTrace入門

第2回 関数引数/戻り値の採取

この記事を読むのに必要な時間:およそ 5 分

前回はDTraceを用いて関数呼び出しフローを採取しました。今回は,関数呼び出しにおける,より詳細な情報の採取を行います。

引数値の採取

関数呼び出しにおいて採取したい情報の筆頭は,何と言っても引数に関する情報でしょう。

引数値の表示

まずは,以下の様な関数 multiply() を持つプログラムshow_args を想定します。

リスト1 採取対象関数multiply()

int
multiply(int x, int y)
{
    return (x * y);
}

この関数が呼び出された際の引数を表示するDスクリプトは,以下のように記述します(自前のプログラムに対して試す場合は,show_argsおよびmultiply部分を適宜書き換えてください)⁠

リスト2 引数値採取Dスクリプト

pid$target:show_args:multiply:entry
{
    printf("multiply(%d, %d)\n", arg0, arg1);
}

上記Dスクリプトの各要素は,以下の様な意味を持ちます("pid$target:show_args" および"entry"部分に関しては,前回で解説済みですので割愛します)⁠

表1 Dスクリプトの構成要素

multiply この位置には情報採取対象の関数名を記述します。
この例では,multiply関数が採取対象となります。
printf() C 標準ライブラリの printf() 関数に相当する処理を行う DTraceアクションを呼び出します。
標準Cライブラリで既定されているフォーマット指定は概ね使用可能です。
arg0, arg1 (この例では)関数呼び出しにおける引数を参照するのに使用します。
最初の引数が arg0以降の引数が順に arg1arg2 ...で参照可能です。
範囲外の引数を参照した場合の値は不定となります。

dtrace コマンドの起動方法は前回と同様です。

図1 引数値の採取

$ dtrace -s watch_arg_val.d \
         -q \
         -c './show_args 13 17'
multiply(13, 17) ← 採取結果
$ 

今回は関数フローの必要が無いので,-F 指定を省略しています。

また -q 指定により,DTraceによる関数名やCPU ID等の付加情報表示を抑止して,D スクリプトのprintf() アクションによる)明示的な出力指定のみを表示するようにしています。

D スクリプトの文法詳細

これまでは,個々の状況におけるDスクリプトの説明をしてきましたが,ここで改めてDスクリプトの文法について説明したいと思います。

D スクリプトは,以下の構造を1つ,ないし複数記述したものです(※1)⁠

リスト3 Dスクリプト文法

<Probe-Description> [, ....]
{
    [<Action> ....]
}

<Action> 部分は,先の例で記述した printf() のような処理を,セミコロン区切りで複数列挙することができます。

<Probe-Description>は以下の形式で構成されます。

リスト4 <Probe-Description> の構成

<Provider>:<ProbeModule>:<ProbeFunc>:<ProbeName>

各要素は以下の意味を持ちます。

表2 <Probe-Description> の構成要素

<Provider> 情報採取機能の種類を指定します。この機能種別を DTrace ではプロバイダ(provider)と呼びます。
ユーザプログラムからの情報採取の場合は,専ら pidプロバイダの使用がメインになると思いますが,DTraceは他にも多数のプロバイダを用意しています。
<ProbeModule> 情報採取対象のバイナリファイル名を指定します。
現状は採取対象コマンド名と同一とみなして構いません(応用方法に関しては,第3回で説明する予定です)⁠
<ProbeFunc> 情報採取対象となる関数名を指定します。
<ProbeName> どの時点で情報を採取するかを指定します。
pid プロバイダを使用する場合,entry(関数の開始)およびreturn(関数の終了)を指定可能です。

上記の各要素の組み合わせによって特定される「情報採取対象」のことを,DTrace ではプローブ(probe)と呼びます。

<ProbeModule><ProbeFunc> が採取対象となる関数(=範囲)を,<Provider><ProbeName> が採取対象となる情報(=種別)を絞り込みます。

<Probe-Description> 中の各要素は省略可能で,省略された場合は「選択可能な全て」が指定されたものとみなされます。

ただし,pidプロバイダを使用してユーザプログラムから情報採取する場合,実質的に省略可能な要素は<ProbeFunc>ぐらいだと思ってください(※2)⁠

<Action> が実行される際の採取対象プローブに関する<Probe-Description> 中の各要素は,Dスクリプト中からそれぞれprobeprovprobemodprobefunc および probenameという組み込み変数を使って参照することができます。

そのため,(1) <Probe-Description>はカンマで区切って複数列挙できることと,(2) 現時点で <Action> の対象となっている関数名をprobefunc参照できることを利用して:

リスト5 <Action>共有例

pid$target:show_args:add:entry,
pid$target:show_args:subtract:entry,
pid$target:show_args:multiply:entry,
pid$target:show_args:divide:entry
{
    printf("%s(%d, %d)\n", probefunc, arg0, arg1);
}

上記のように,1つの<Action>を,複数の関数に対する<Probe-Description>で共有しつつ,実際に呼び出された関数の名前を表示内容に含めることが可能です。

上記以外の組み込み変数に関しては,Solaris動的トレースガイドの組み込み変数の解説を参照してください。

※1)
厳密には,これでもまだ完全な定義ではありませんが,今回省略した要素に関しては,連載中の各回で必要に応じて補足します。
※2)
pid プロバイダで<ProbeName> を省略した場合,理屈上は暗黙で entry および return が指定されたもの,とみなされるはずなのですが,このような省略指定をすると何故か-Fによる関数フローが綺麗に表示されません(各関数が重複して表示されてしまいます)⁠

著者プロフィール

藤原克則(ふじわらかつのり)

Mercurial三昧の日々が嵩じて, いつの間にやら『入門Mercurial Linux/Windows対応』を上梓。凝り性なのが災いして,年がら年中アップアップな一介の実装屋。最近は仕事の縁が元で,OpenSolarisに入れ込む毎日。

コメント

コメントの記入