9 スクリプト

dtraceコマンドを使用すると、Dプログラムから、シェル・スクリプトに類似したインタプリタ・ファイルを作成できます。このファイルは、再利用可能な対話型のDTraceツールとしてインストールできます。Dコンパイラとdtraceコマンドには、Dコンパイラによって拡張されている一連のマクロ変数が用意されており、マクロ変数を使用すると、DTraceスクリプトの作成が容易になります。この章では、マクロ変数の機能を紹介し、永続スクリプトを作成するためのヒントを示します。

インタプリタ・ファイル

シェルや、awkおよびperlなどのユーティリティと同様に、dtraceコマンドを使用して、実行可能なインタプリタ・ファイルを作成できます。

インタプリタ・ファイルの先頭には、次の形式の行が挿入されます。

#!pathname [arg]

pathnameはインタプリタのパス、argは単一の引数(オプション)です。インタプリタ・ファイルを実行すると、指定されたインタプリタがシステムによって呼び出されます。インタプリタ・ファイルで指定されたargは、引数としてインタプリタに渡されます。インタプリタ・ファイルのパスと、インタプリタ・ファイルの実行時に指定される引数は、インタプリタの引数リストに追加されます。したがって、DTraceインタプリタ・ファイルを作成するときは、少なくとも次の引数を指定する必要があります。

#!/usr/sbin/dtrace -s

インタプリタ・ファイルが実行される場合、-sオプションの引数は、インタプリタ・ファイルのパス名です。次に、dtraceコマンドが、シェルに次のコマンドを入力したかのように、このファイルを読み取ってコンパイルし、実行します。

# dtrace -s interpreter-file

次に、dtraceインタプリタ・ファイルの作成方法および実行方法の例を示します。まず、次のDソース・コードを入力し、interp.dという名前のファイルに保存します。

#!/usr/sbin/dtrace -s
BEGIN
{
  trace("hello");
  exit(0);
}

次に、interp.dファイルを実行可能にして、次のように実行します。

# chmod a+rx interp.d
# ./interp.d
dtrace: script './interp.d' matched 1 probe
CPU     ID                    FUNCTION:NAME
  0      1                           :BEGIN   hello                            
#

#!ディレクティブは、ファイルの先頭の2文字で構成する必要があります。また、間や先頭に空白文字を使用しないようにしてください。Dコンパイラで、インタプリタ・ファイルを処理するとき、この行は自動的に無視されます。

dtraceコマンドは、getopt()を使用してコマンドライン・オプションを処理するため、複数のオプションを単一のインタプリタ引数として指定できます。たとえば、前述の例に-qオプションを追加し、次のようにインタプリタ・ディレクティブを変更してみます。

#!/usr/sbin/dtrace -qs

ノート:

複数のオプションを指定する場合は、必ずオプションのリストの最後に-sオプションを指定します。これにより、次の引数(インタプリタ・ファイル名)が-sオプションの引数として正しく処理されます。

インタプリタ・ファイルで引数を必要とする複数のオプションを指定する必要がある場合には、#pragma D optionディレクティブを使用してオプションを設定します。いくつかのdtraceコマンドライン・オプションでは、#pragmaと同等のものを使用できます。「オプションおよびチューニング可能パラメータ」を参照してください。

マクロ変数

Dコンパイラには、Dプログラムやインタプリタ・ファイルを記述するときに使用できる組込みマクロ変数のセットが定義されています。マクロ変数は、接頭辞としてドル記号($)が付く識別子です。入力ファイルの処理時に、この変数が1回展開されます。次の表では、Dコンパイラに用意されているマクロ変数について説明します。

表9-1 Dのマクロ変数

名前 説明 参照先

$[0-9]+

マクロ引数

マクロ引数

$egid

実効グループID

getegid(2)のマニュアル・ページを参照してください

$euid

実効ユーザーID

geteuid(2)のマニュアル・ページを参照してください

$gid

実グループID

getgid(2)のマニュアル・ページを参照してください

$pid

プロセスID

getpid(2)のマニュアル・ページを参照してください

$pgid

プロセス・グループID

getpgid(2)のマニュアル・ページを参照してください

$ppid

親プロセスID

getppid(2)のマニュアル・ページを参照してください

$sid

セッションID

getsid(2)のマニュアル・ページを参照してください

$target

ターゲット・プロセスID

ターゲット・プロセスID

$uid

実ユーザーID

getuid(2)のマニュアル・ページを参照してください

マクロ引数$[0-9]+とマクロ変数$targetを除き、すべてのマクロ変数は展開後に、プロセスIDやユーザーIDなどのシステム属性に対応する整数になります。展開後の変数は、現在のdtraceプロセス、またはDコンパイラを実行しているプロセスに関連付けられた属性値になります。

インタプリタ・ファイル内でマクロ変数を使用すると、永続的なDプログラムを作成でき、使用するたびに編集を加える必要がありません。たとえば、dtraceコマンドによって実行される以外のすべてのシステム・コールをカウントする場合は、$pidを指定して次のようなDプログラム節を使用します。

syscall:::entry
/pid != $pid/
{
  @calls = count();
}

dtraceコマンドを呼び出すたびにプロセスIDは異なりますが、この節は常に所定の結果を返します。マクロ変数は、整数、識別子または文字列を使用できる場所であればどこでもDプログラムで使用できます。

マクロ変数は、入力ファイルの解析時に1回のみ(非再帰的に)展開されます。

展開された各マクロ変数は、プローブ記述以外では、独立した入力トークンになり、これらを他のテキストと連結して1つのトークンにすることはできません。

たとえば、$pidが値456に展開される場合、次の例のDコードは、1つの整数トークン123456ではなく、2つの隣接するトークン123および456に展開され、構文エラーになります。

123$pid

ただし、プローブ記述では、マクロ変数は展開されて、隣接するテキストと連結されます。たとえば、次の節は、DTraceのpidプロバイダを使用して、dtraceコマンドをインストゥルメントします。

# dtrace -c ./a.out -n 'pid$target:libc.so::entry'

マクロ変数は、各プローブ記述フィールドで1回しか展開されないので、プローブ記述のデリミタ(:)は含まれません。

マクロ引数

Dコンパイラには、dtraceコマンド呼出しの一部として指定される追加の引数オペランドに対応する、一連のマクロ変数も用意されています。これらのマクロ引数にアクセスするには、Dプログラム・ファイル名やdtraceコマンドは$0、最初の追加オペランドは$1、2番目の追加オペランドは$2など(以降同様)の組込み名を使用します。-sオプションを指定した場合、$0は、このオプションで使用される入力ファイルの名前の値に展開されます。Dプログラムをコマンドラインに指定した場合、$0は、dtraceコマンド自体の実行に使用するargv[0]の値に展開されます。

マクロ引数は、対応するテキストの形式に応じて、整数、識別子または文字列に展開されます。すべてのマクロ変数と同じように、マクロ引数もDプログラムの整数、識別子、文字列トークンのかわりに使用できます。

次に示す例はいずれも、適切なマクロ引数の値を指定すれば、有効なD式になります。

execname == $1  /* with a string macro argument */

x += $1         /* with an integer macro argument */

trace(x->$1)    /* with an identifier macro argument */

マクロ引数を使用して作成したDTraceインタプリタ・ファイルは、実際のLinuxコマンドと同じように機能し、ユーザーや他のツールによって指定された情報を使用してその動作を変更します。

たとえば次のDインタプリタ・ファイルは、特定のプロセスIDで実行され、tracewriteという名前のファイルに保存されるwrite()システム・コールをトレースします。

#!/usr/sbin/dtrace -s 
syscall::write:entry
/pid == $1/
{
}

このインタプリタ・ファイルを実行可能ファイルにする場合は、次のように、コマンドライン引数をインタプリタ・ファイルに追加して、$1の値を指定できます。

# chmod a+rx ./tracewrite
# ./tracewrite 12345

生成されるコマンド呼出しは、プロセスID 12345で実行される各write()システム・コールをカウントします。

Dプログラムが参照するマクロ引数がコマンドラインで指定されていない場合は、次の例に示すように、該当するエラー・メッセージが出力され、プログラムを正常にコンパイルできません。

# ./tracewrite
dtrace: failed to compile script ./tracewrite: line 4: 
  macro argument $1 is not defined

defaultargsオプションを設定すると、Dプログラムで未指定のマクロ引数を参照できます。defaultargsオプションを設定した場合、未指定の引数の値は0になります。Dコンパイラのオプションの詳細は、「オプションおよびチューニング可能パラメータ」を参照してください。Dプログラムで参照されない追加の引数をコマンドラインで指定した場合も、Dコンパイラはエラー・メッセージを生成します。

マクロ引数の値は、整数、識別子または文字列の形式に一致する必要があります。引数がこれらの形式に一致しない場合、Dコンパイラは該当するエラー・メッセージを出力します。DTraceインタプリタ・ファイルに文字列のマクロ引数を指定するときは、シェルで二重引用符や文字列の内容が解釈されないように、引数をさらに一対の一重引用符で囲む必要があります。

# ./foo '"a string argument"'

Dのマクロ引数が整数または識別子の形式に一致する場合でも、あえて文字列トークンとして解釈させる場合は、マクロ変数またはマクロ引数の名前の前に、ドル記号を2つ追加します(たとえば、$$1)。こうすれば、Dコンパイラはこの引数の値を二重引用符で囲まれた文字列とみなすようになります。通常のD文字列エスケープ・シーケンス(表2-6を参照)はすべて、文字列形式のマクロ引数の内部で展開されます。これは、$argまたは$$arg形式のマクロで参照されている場合でも変わりません。defaultargsオプションを設定している場合、$$argの形式で参照される未指定の引数は、値が空の文字列("")になります。

ターゲット・プロセスID

-pオプションを使用して指定するか、dtraceコマンドで-cオプションを使用して作成した、特定のユーザー・プロセスに適用されるスクリプトを作成する場合は、$targetマクロ変数を使用します。コマンドラインで指定した、または-sオプションで指定したDプログラムは、プロセスの作成後または取込み後に、$target変数がこれらの最初のプロセスのプロセスIDを表す整数に展開された後でコンパイルされます。

たとえば次のDスクリプトでは、特定の従属プロセスによって実行されるシステム・コールの内訳がわかります。syscall.dという名前のファイルに保存します。

syscall:::entry
/pid == $target/
{
  @[probefunc] = count();
}

dateコマンドによって実行されるシステム・コール数を特定するには、このスクリプトをsyscall.dという名前のファイルに保存して、次のコマンドを実行します。

# dtrace -s syscall.d -c date
dtrace: script 'syscall.d' matched 296 probes
Tue Oct 16 15:12:07 BST 2012

  access                                                            1
  arch_prctl                                                        1
  clock_gettime                                                     1
  exit_group                                                        1
  getrlimit                                                         1
  lseek                                                             1
  rt_sigprocmask                                                    1
  set_robust_list                                                   1
  set_tid_address                                                   1
  write                                                             1
  futex                                                             2
  rt_sigaction                                                      2
  brk                                                               3
  munmap                                                            3
  read                                                              5
  open                                                              6
  mprotect                                                          7
  close                                                             8
  newfstat                                                          8
  mmap                                                             16