D プログラムは、有効にするプローブ、およびプローブに結合する述語とアクションについて説明する、一連の節で構成されています。D プログラムには、第 3 章変数で説明した変数宣言や、第 8 章型と定数の定義で説明する新しい型の定義も含めることができます。この章では、D プログラムの全体構造と、複数のプローブを表すプローブ記述の作成機能について説明します。また、D プログラムでの C プリプロセッサ cpp の使用についても説明します。
これまでの例からわかるように、D プログラムのソースファイルは、DTrace によって有効化される計測機能について記述した 1 つ以上のプローブ節で構成されます。各プローブ節の標準形式は、次のとおりです。
probe descriptions / predicate / { action statements }
述語とアクション文のリストは省略可能です。プローブ節の外側に置かれた指令を「宣言」と呼びます。宣言は、必ずプローブ節の外側に挿入します。宣言を中括弧 ({ }) 内に記述することはできません。また、宣言を上記のプローブ節の要素と要素の間に配置することはできません。D プログラムの要素間の区切りと、アクション文のインデントには、空白を使用します。
宣言では、D 変数や外部 C シンボルを宣言したり (第 3 章変数を参照)、D プログラムで使用する新しい型を定義したり (第 8 章型と定数の定義を参照) できます。D プログラムでは、「プラグマ」と呼ばれる特殊な D コンパイラ指令も使用できます。プローブ節の外側も含めた任意の場所で使用できます。D プラグマは、先頭文字が # の行に指定されます。D プラグマは、実行時 DTrace オプションの設定などに使用されます。詳細は、第 16 章オプションとチューニング可能パラメータを参照してください。
D プログラム節は、1 つ以上のプローブ記述で始まります。プローブ記述は、通常、以下の形式をとります。
provider:module:function:name
プローブ記述の一部のフィールドを省略した場合、D コンパイラは、指定されたフィールドだけを右から左の順で解釈します。たとえば、foo:bar というプローブ記述は、関数 foo を持つ bar という名前のプローブを表します。プローブのプロバイダとモジュールのフィールドの値は無視されます。このため、プローブ記述は、名前に基づいて 1 つ以上のプローブと照合される「パターン」と見なすことができます。
D プローブ記述を作成するときは、左側に適切な「プロバイダ」を指定できるように、4 つのフィールドの区切り記号をすべて指定してください。プロバイダを指定しないと、複数のプロバイダが同じ名前のプローブを発行している場合に、予想外の結果になる可能性があります。同様に、プローブ記述の一部を省略していると、将来のバージョンの DTrace で追加された新しいプロバイダのプローブが、予期せずして照合されてしまう可能性もあります。プロバイダを指定して、モジュール、関数、名前のフィールドを未指定にした場合、このプロバイダのすべてのプローブが照合されます。たとえば、DTrace の syscall プロバイダから発行されたすべてのプローブを表現するには、syscall::: のように記述します。
プローブ記述では、シェルの「展開」パターンマッチング構文 (sh(1) を参照) とよく似たパターンマッチング構文も使用できます。記述からプローブを照合する前に、DTrace により、各記述フィールドに *、?、および [ の文字がないか検査されます。プローブ記述フィールドに、このうちいずれかの文字が含まれていて、その直前の文字が \ でない場合、このフィールドはパターンと見なされます。記述パターンは、プローブの対応するフィールド全体と一致する必要があります。完全な形のプローブ記述では、プローブ記述のすべてのフィールドが一致して初めて、プローブが照合され有効化されます。パターンが使用されていないプローブ記述フィールドは、対応するプローブのフィールドに完全に一致する必要があります。空の記述フィールドは、すべてのプローブを表します。
以下の表に、プローブ名のパターン内で認識される特殊文字を示します。
表 4–1 プローブ名のパターンマッチング文字
記号 |
説明 |
---|---|
* |
NULL 文字列を含むすべての文字列を表します。 |
? |
任意の 1 文字を表します。 |
[ ... ] |
括弧内のいずれか 1 文字を表します。2 つの文字の間に - を入力すると、その範囲 (両端の文字を含む) の任意の文字を表します。[ に続く最初の文字を ! にすると、括弧内に含まれない任意の文字を表します。 |
\ |
次の 1 文字に特別な意味を持たせず、文字どおりに解釈します。 |
パターンマッチング文字は、プローブ記述の 4 つのフィールド全部、またはそのいずれかで使用できます。dtrace -l とともにコマンド行にパターンを入力して、条件に一致するプローブを一覧することもできます。たとえば、dtrace -l -f kmem_* というコマンドでは、DTrace プローブのうち、関数の名前が kmem_ で始まるものすべてが一覧されます。
複数のプローブ記述または記述パターンで同じ述語とアクションを指定したい場合は、コンマで区切ったリストの形式で記述します。たとえば次の D プログラムでは、「lwp」または「sock」という語を含むシステムコールの開始に関連付けられたプローブが起動するたびに、タイムスタンプがトレースされます。
syscall::*lwp*:entry, syscall::*sock*:entry { trace(timestamp); }
プローブ記述では、整数のプローブ ID を使って、プローブを指定することもできます。たとえば、次の節を参照してください。
12345 { trace(timestamp); }
この節では、dtrace -l -i 12345 で報告される、プローブ ID 12345 を有効にすることができます。D プログラムを作成するときは、常に、人間が読める形式のプローブ記述を使用する必要があります。整数のプローブ ID は、DTrace プロバイダカーネルモジュールのロード後、アンロード後、または再起動後に変更される可能性があります。
述語は、スラッシュ (//) で囲まれた式であり、プローブ起動時に評価され、関連アクションを実行するかどうかを決定します。述語は、D プログラムでより複雑な制御フローを構築するために使用する主要な条件構文です。プローブ節の述語部分を完全に省略することもできます。この場合、プローブの起動時に常にアクションが実行されることになります。
述語式では、これまでに紹介したすべての D 演算子を使用できます。また、変数や定数を含むあらゆる D データオブジェクトを参照できます。述語式は、真または偽の結果を導き出すため、整数型またはポインタ型の値を評価する必要があります。すべての D 式と同じく、ゼロ値は偽、ゼロ以外の値は真と解釈されます。
プローブのアクションは、セミコロン (;) で区切られた文のリストを中括弧 ({ }) で囲んだ形式で記述します。データのトレースなどのアクションの実行を省略して、特定の CPU 上で特定のプローブが起動したという事実だけを記録したい場合は、中に何も文が記述されていない、空の中括弧を指定します。
Solaris システムインタフェースの定義に使用されている C プログラミング言語には、C プログラムのコンパイルの一連の初期手順を実行する「プリプロセッサ」が用意されています。C プリプロセッサは、一般に、マクロ置換 (C プログラム内のあるトークンを別の事前定義済みトークンセットで置き換える) の定義や、システムヘッダーファイルのコピーの挿入に利用されます。dtrace コマンドに -C オプションを指定すると、D プログラムで C プリプロセッサを使用することができます。このオプションが指定された場合、dtrace はまず、プログラムソースファイルに対して cpp(1) プリプロセッサを実行します。そして、その結果を D コンパイラに渡します。C プリプロセッサの詳細は、『プログラミング言語 C』を参照してください。
D コンパイラには、オペレーティングシステム実装に関連付けられている C の型記述のセットが自動的にロードされます。しかし、プリプロセッサを使用すると、独自の C プログラムで使用している型定義などもロードできます。プリプロセッサではこのほかに、D コードのチャンクに拡張されるマクロやその他のプログラム要素を作成するなどのタスクも実行できます。D プログラムでプリプロセッサを使用するときは、有効な D 宣言を含むファイルだけを使用してください。型とシンボルの外部宣言だけを含む通常の C ヘッダーファイルは、D コンパイラで正しく解釈されます。C 関数ソースコードのような追加プログラム要素を含む C ヘッダーファイルは、D コンパイラでは構文解析できません。このようなファイルを使用した場合、D コンパイラからエラーメッセージが返されます。