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

第6回 独自プロバイダの定義[1]

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

実行可能ファイルの生成

Cプログラムのコンパイル

プローブ埋め込み対象のCプログラム(前ページのリスト4)は,以下の要領でコンパイルします。

図2 プローブ埋め込み対象プログラムのコンパイル

$ cc -c  branch_by_arg.c

ここでのコンパイルにはDTraceの独自プローブ埋め込みの影響はありませんから,必要に応じて適宜オプション等を指定してください。

Cプログラムのリンク

コンパイルによって生成された,プローブ埋め込み対象のオブジェクトファイル(*.o ファイル)をリンクしようとすると,以下のようなエラーが発生します。

図3 プローブ埋め込み対象プログラムのリンク(失敗例)

$ cc -o branch_by_arg branch_by_arg.o
Undefined                       first referenced
 symbol                             in file
__dtrace_checkpoint___pass          branch_by_arg.o
ld: fatal: symbol referencing errors. \
    No output written to branch_by_arg
$

上記実行例で,⁠シンボル未定義」と判定された関数の呼び出しは,プローブ埋め込み用マクロcheckpoint.hにおけるCHECKPOINT_PASSマクロ)の展開によるものです(前ページのリスト2参照)⁠

dtraceコマンドにより生成されたのはヘッダファイルのみですし,別途プローブ用に何かを実装したわけでもなければ,特別なライブラリをリンクしたわけでもありませんから,シンボル未定義となるのは至極当然の成り行きですね。

実はユーザプログラムに独自プローブを埋め込む場合,リンクに先立ってdtraceコマンドによる前処理を行う必要があります。

dtraceコマンドによるリンク前処理は,図4の要領で,"-G"オプションと,プローブが埋め込まれている全てのオブジェクトファイルを指定します。

図4 dtraceコマンドによるリンク前処理

$ dtrace -s checkpoint.d -G branch_by_arg.o

"-G"オプションが指定された場合,dtraceコマンドは以下の処理を実施します。

  1. 列挙されたオブジェクトファイルから,プローブ(="__dtrace_*"関数)呼び出しを除去
  2. 除去したプローブ呼び出しに関する情報をまとめ,それを格納したオブジェクトファイル(この場合はcheckpoint.oを生成

前処理が完了したなら,dtraceコマンドにより生成されたオブジェクトファイルを含めて,必要なオブジェクトファイルをリンクしてください。

図5 プローブ埋め込み対象プログラムのリンク(成功例)

$ cc -o branch_by_arg branch_by_arg.o checkpoint.o

リンク時オプションに関しても,DTraceの独自プローブ埋め込みの影響はありませんから,必要に応じて適宜オプション等を指定してください。

なお,dtrace コマンド+"-G"オプションによる前処理は,関連するオブジェクトファイル群の内容を改変してしまう点に注意してください。

一部のソースファイルを改変してから再度リンクを行う場合,ソースファイルを改変していないオブジェクトファイルに関しても,コンパイルによる再生成が必要となります。コンパイル~リンクまでの作業をmakeコマンド等で自動化する場合には,特に注意が必要です。

プローブからの情報採取

独自に定義したプロバイダからの情報採取の要領は,pidプロバイダの場合と同じ(※1)です。

リスト5に,checkpointプロバイダのpassプローブを使用するDスクリプトの例を示します。

リスト5 passプローブを使用するDスクリプト

checkpoint$target:$1::pass
{
    printf("%s:%d:%s\n", 
           copyinstr(arg0), arg1, probefunc);
}

それでは,さっそく情報採取をしてみましょう。

図6 passプローブからの情報採取

$ dtrace -s watch_checkpoint.d \
    -q \
    -c './branch_by_arg 13'
branch_by_arg.c:15:main
branch_by_arg.c:21:main
branch_by_arg.c:25:main

$

引数によって分岐した先でDTRACE_CHECKPOINT_PASS()マクロを通過するつど,ファイル名/行番号情報が出力されているのがわかります。

Emacsやviのエラー行ジャンプ機能と併用すれば,DTraceで採取した情報を元に処理経路順にソースを参照する,といったことも可能になります。

※1)
「プロバイダ名」以外に「プロセスID」指定が必要な点も同じです。

次回予告

今回は独自プロバイダの定義を行いましたが,いかがだったでしょうか?

定義/利用共に非常に簡単ですから,ぜひ実際のプログラミングに取り入れてみてください。

次回は,独自プロバイダ定義の後編ということで,プローブに指定された値から,より詳細な情報を得る方法を説明したいと思います。

著者プロフィール

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

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