この章では、MDB 言語構文、演算子、コマンドの規則、およびシンボルの名前解決について説明します。
デバッガは、標準入力からコマンドを処理します。端末からの標準入力の場合、MDB では端末編集機能が使用できます。また、MDB は、マクロファイルからのコマンドや dcmd パイプラインからのコマンドも処理できます。これについては後述します。言語構文は、ターゲット内のメモリーアドレスに代表されるような、式の値を計算し、dcmd をそのアドレスに適用するという構想に基づいて設計されています。現在のアドレスの位置はドットと呼ばれ、" . " は該当する値の参照に使用されます。
メタキャラクタには、次のような文字があります。
[ ] | ! / ¥ ? = > $ : ; 復帰改行文字、空白文字、タブ
空白とは、タブや空白文字のことです。ワード (word) とは、1 つまたは複数の引用符なしのメタキャラクタで区切られた文字列のことです。ただし、コンテキストによっては単なる区切り記号として機能するメタキャラクタもあるので、これについては後述します。識別子とは、文字列、数字、下線、ピリオド、または冒頭に文字、下線、ピリオドのどれかを持つ逆引用符のことです。識別子は、シンボル名、変数、dcmd、および walker として使用されます。コマンドは、復帰改行文字やセミコロン (;) で区切ります。
dcmd は、次のようなワードまたはメタキャラクタで表されます。
/ ¥ ? = > $character :character ::identifier
メタキャラクタで指定された dcmd や接頭辞 $ か : を 1 つ持つ dcmd は、組み込み演算子として提供されます。また、これらの dcmd は、従来の adb(1) ユーティリティのコマンドセットとの互換性を備えています。dcmd が構文解析されると、/、¥、?、=、>、$、および : は、引数リストが終了するまでメタキャラクタとして認識されなくなります。
単純コマンドとは、後に一連の文字列やワードが続く dcmd のことです。このワードは空白文字で区切られている場合もあります。これらのワードは、呼び出される dcmd に引数として渡されます。ただし、「演算機能の拡張」と 「引用」で特に指定されているワードは例外です。各 dcmd は、処理の成功、失敗、または無効な引数を受け取ったことを示す終了ステータスを返します。
パイプライン (pipeline) とは、| で区切られた 1 つまたは複数の単純コマンドのことです。シェルの場合とは異なり、MDB パイプライン内の dcmd は分割プロセスとしては実行されません。MDB では、パイプラインが構文解析された後に、それぞれの dcmd が左から右へと順に呼び出されます。各 dcmd の出力は、処理された後に格納されます (「dcmd パイプライン」を参照)。左側の dcmd 処理が終了すると、その出力はパイプライン内の次の dcmd への入力として使用されます。どの dcmd も終了ステータスとして正常終了を返さない場合、そのパイプラインは強制終了します。
式 (expression) は一連のワードで表され、64 ビットの符号なし整数を計算するために評価されます。ワードは、「演算機能の拡張」に示す規則を用いて評価されます。
コマンドは、次のうちのどれかです。
パイプライン (pipeline) は単純コマンドですが、接尾辞として感嘆符 (!) 文字を付けることもできます。この場合、デバッガは、pipe(2) を開いた後、MDB パイプライン内の最後の dcmd の標準出力を、$SHELL -c の実行により形成された外部プロセスへ送ります。c オプションの後には、感嘆符 (!) で始まる文字列が続きます。詳細については、「シェルエスケープ」を参照してください。
パイプラインは単純コマンドですが、先頭に式 (expression) を付けることもできます。この場合、パイプラインの実行前に、ドット値 (" . " で表される変数) が式の値に設定されます。
パイプラインは単純コマンドですが、先頭に式を 2 つ付けることもできます。最初の式は新しいドット値を判定するために評価され、2 番目の式はパイプライン内の最初の dcmd の繰り返し回数を判定するために評価されます。この場合、dcmd は、判定された回数繰り返し実行し、その後にパイプライン内の次の dcmd を実行します。繰り返し回数は、パイプライン内の最初の dcmd にだけ適用されます。
式の値に応じて、パイプライン内の最初の dcmd が繰り返されます。ただし、先頭の式が省略されている場合は、ドットは変更されません。
コマンドは、算術式だけで構成される場合があります。この場合、式が評価された後、その値にドット変数が設定されます。次に、直前の dcmd と引数が新しいドット値を使用して実行されます。
コマンドは、ドット式と繰り返し回数式だけで構成される場合があります。この場合、最初の式の値がドットに設定された後、2 番目の式で指定された回数、直前の dcmd と引数が繰り返し実行されます。
直前の dcmd と引数が、繰り返し回数式の値で指定された回数、繰り返し実行されます。ただし、先頭の式が省略されている場合は、ドットは変更されません。
コマンドが感嘆符 (!) で始まっている場合は、どの dcmd も実行されず、$SHELL -c がデバッガによって実行されます。c オプションの後には、感嘆符 (!) で始まる文字列が続きます。
// を付けると、その後の復帰改行文字まで、ワードや文字列がすべて無視されます。
MDB コマンドの前に、開始アドレスを表すオプション式や、開始アドレスと繰り返し回数を表すオプション式がある場合は、演算機能が拡張されます。また、dcmd に使用する数値引数を計算する場合にも、演算機能が拡張されます。演算式は、ドル記号の後に角括弧で囲んだ引数リスト ($[ expression ]) で表され、その式の値に置き換えられます。
式には、次の特殊ワードのどれかを使用できます。
特定の整数値。デフォルトでは、整数値は、接頭辞として 0i または 0I を付けると 2 進数値、0o または 0O を付けると 8 進数値、0t または 0T を付けると 10 進数値、0x または 0X を付けると 16 進数値を表します。
指定された 10 進数の浮動小数点値。IEEE 倍精度浮動小数点表示に変換されます。
各文字を ASCII 値に等しいバイトに変換することによって計算された整数値。最大 8 文字までを文字定数に指定できます。文字列は、最下位のバイトから始まって、右から左へと逆方向に整数の中へ格納されます。
識別子 (identifier) によって指定される変数値
識別子 (identifier) によって指定されるシンボル値
式 (expression) の値
ドット値
dcmd を実行するために使用される最新のドット値
現在のインクリメントによって増分されるドット値
現在のインクリメントによって減分されるドット値
インクリメントとは、最後にフォーマットされた dcmd によって読み込まれる合計バイトを格納する大域変数のことです。インクリメントの詳細については、「dcmd のフォーマット」を参照してください。
単項演算子は右結合で、2 項演算子よりも高い優先度を持っています。以下で、単項演算子について説明します。
論理否定
ビット単位の補数
整数否定
ターゲットの仮想アドレス空間内の仮想アドレス式に対応するオブジェクトファイル位置でのポインタサイズの数量値
ターゲットの仮想アドレス空間内の仮想アドレス式に対応するオブジェクトファイル位置での char サイズ、short サイズ、int サイズ、または long サイズの数量値
ターゲットの仮想アドレス空間内の仮想アドレス式に対応するオブジェクトファイル位置での 1 バイト、2 バイト、4 バイト、または 8 バイトの数量値
ターゲットの仮想アドレス空間内の仮想アドレス式でのポインタサイズの数量値
ターゲットの仮想アドレス空間内の仮想アドレス式での char サイズ、short サイズ、int サイズ、または long サイズの数量値
ターゲットの仮想アドレス空間内の仮想アドレス式での 1 バイト、2 バイト、4 バイト、または 8 バイトの数量値
2 項演算子は左結合で、単項演算子よりも優先度は低くなります。以下に 2 項演算子を、優先度の高いものから順に示します。
整数の乗算
整数の除算
左辺を右辺の最小の倍数に切り上げる
整数の加算
整数の減算
ビット単位で左へシフト
ビット単位で右へシフト
等しい
異なる
ビット単位の論理積
ビット単位の排他的論理和
ビット単位の論理和
上述のように (第 3 章「言語構文」を参照)、各メタキャラクタは、引用符で囲まないとワードを終了します。MDB を使用して各文字を特別な意味のない文字そのものとして解釈させるには、それらを単一引用符 (') または二重引用符 (") で囲めば、文字列として引用できます。単一引用符を、単一引用符で囲んで表示させることはできません。二重引用符内では、MDB は C プログラミング言語の文字エスケープシーケンスを認識します。
! 文字を使用して、MDB コマンドとユーザーのシェル間のパイプラインを作成できます。$SHELL 環境変数が設定されている場合、MDB は、そのプログラムをシェルエスケープのためにフォーク (fork) したり、実行 (exec) したりします。変数が設定されていない場合は、/bin/sh コマンドが使用されます。シェルは、-c オプション付きで呼び出されます。c オプションの後には、感嘆符 (!) で始まる文字列が続きます。
! 文字は、他のどのメタキャラクタよりも高い優先度を持っています。ただし、セミコロン (;) と復帰改行文字は例外です。シェルエスケープが検出された後、次のセミコロンまたは復帰改行文字までの残りの文字列は、そのままシェルへ渡されます。シェルの出力コマンドを MDB dcmd へパイプすることはできません。シェルエスケープによって実行されたコマンドは、その出力を MDB へは送らずに、直接端末へ送ります。
変数とは、対応する整数値と一連の属性を持つ変数名のことです。変数名は、一連の文字列、数字、下線、ピリオドなどで表されます。変数には、> dcmd や ::typeset dcmd を使用して値を割り当てることができます。また、その属性は、::typeset dcmd を使用して変更できます。各変数の値は、64 ビットの符号なし整数として表されます。変数は、1 つまたは複数の属性を持つことができます。たとえば、読み取り専用 (ユーザーによって変更されない)、固定表示 (ユーザーによって設定解除されない)、タグ (ユーザー定義のインジケータ) などです。
/、¥、?、= の dcmd を使用して出力された最新の値
$< dcmd とともに使用された最新のカウント
データセクションの基底仮想アドレス
データセクションのバイトサイズ
エントリポイントの仮想アドレス
ターゲットの一次オブジェクトファイルの初期バイト (マジックナンバー)。オブジェクトファイルがまだ読み出されていない場合はゼロ
テキストセクションのバイトサイズ
さらに、MDB カーネルとプロセスターゲットは、代表スレッドのレジスタセットの現在値を指定変数としてエクスポートします。これらの変数の名前は、ターゲットのプラットフォームや命令セットのアーキテクチャによって決まります。
「構文」で前述したように、式のコンテキスト内のシンボル識別子は、このシンボルの値を求めるために評価します。一般的に、この値は、ターゲットの仮想アドレス空間内のシンボルと関連付けられる、記憶領域の仮想アドレスを表します。ターゲットは複数のシンボルテーブルをサポートできます。そのうちのいくつかを次に示します。
一次実行可能シンボルテーブル
一次動的シンボルテーブル
実行時リンカーシンボルテーブル
多数のロードオブジェクトそれぞれのための、標準的で動的なシンボルテーブル (ユーザープロセスでは共用ライブラリ、Solaris カーネルではカーネルモジュール)
一般的に、ターゲットは、最初に一次実行可能シンボルテーブルを検索し、次にほかの 1 つまたは複数のシンボルテーブルを検索します。ELF シンボルテーブルには、外部シンボル、大域シンボル、静的シンボルなどへのエントリだけが含まれます。自動シンボルは、mdb によって処理されるシンボルテーブルにはありません。
さらに、mdb は、専用のユーザー定義シンボルテーブルを提供し、このシンボルテーブルを他のどのターゲットシンボルテーブルよりも先に検索します。専用シンボルテーブルは、最初は空の状態ですが、::nmadd や ::nmdel dcmd を使用して操作できます。
::nm -P オプションは、専用のシンボルテーブルの内容を表示するために使用されます。専用のシンボルテーブルによって、元のプログラムでは抜け落ちていたプログラム機能やデータのシンボル定義を作成できます。次からは、MDB がシンボル名をアドレスに変換したり、アドレスを最も近くのシンボルへ変換したりするときにはいつでも、これらの定義が使用可能となります。
ターゲットには複数のシンボルテーブルが含まれていて、各シンボルテーブルには複数のオブジェクトファイルからシンボルを入れることができるので、同じ名前で異なるシンボルが存在することもあります。このような場合に、プログラマが希望するシンボル値を得られるように、MDB はシンボル名適用範囲演算子として、逆引用符 " ` " を使用します。
ユーザーは、object`name、file`name、object`file`name などのように、シンボル名の解釈に使用する範囲を指定できます。オブジェクトの識別子は、ロードオブジェクトの名前を参照します。ファイル識別子は、ソースファイルのベース名を参照します。ソースファイルは、指定されたオブジェクトのシンボルテーブル内に STT_FILE 型のシンボルを持っています。オブジェクト識別子の解釈は、ターゲットタイプによって決まります。
MDB カーネルターゲットでは、オブジェクトが、読み込まれたカーネルモジュールのベース名を指定すると考えられます。たとえば、シンボル名 specfs`_init は、specfs カーネルモジュール内の _init シンボルの値を求めるために評価します。
mdb プロセスターゲットでは、オブジェクトが、実行可能な名前、または読み込まれた共用ライブラリの名前を指定すると考えられます。この場合、次の形式のどれかが使用されます。
完全な一致 (つまり、完全なパス名) : /usr/lib/libc.so.1
ベース名に完全に一致 : libc.so.1
ベース名の冒頭から接尾辞の "." まで一致 : libc.so または libc
実行可能な名前の別名として受け入れられるリテラル文字列 a.out
シンボルと 16 進整数値で名前が重複した場合、MDB は、最初にあいまいなトークンをシンボルとして評価し、次に整数値として評価しようとします。たとえば、f というトークンが、デフォルトの 16 進数では 10 進整数の 15 を表し、同時にターゲットのシンボルテーブル内の f という名前の大域変数を表す場合もあります。あいまいな名前を持つシンボルが存在するときには、明示的な 0x または 0X の接頭辞を用いることによって、整数値を明確に指定できます。
前述のように、MDB の各 dmod は、一連の dcmd と walker を提供します。dcmd と walker は、2 つの異なる広域名前空間でトラックされます。また、MDB も、各 dmod に関連付けられた dcmd と walker の名前空間をトラックし続けます。与えられた dmod 内で、dcmd や walker に同じ名前を付けることはできません。このような名前の重複がある dmod は、読み込みに失敗します。
異なる dmod から提供された dcmd や walker 間での名前の重複は、広域名前空間では許されます。名前の重複がある場合、その特定の読み込まれる名前を持つ dcmd または walker のうち、最初のものが広域名前空間で優先権を与えられます。ほかの定義は、読み取り順にリストに保存されます。
逆引用符 " ` " は、ほかの定義を選択するための参照範囲演算子として、dcmd や walker の名前に使用されます。たとえば、dmod m1 と m2 が、それぞれ dcmd d を提供する場合に、m1 の方が m2 よりも先に読み込まれたときには、次のようになります。
m1 の d 定義を実行する
m1 の d 定義を実行する
m2 の d 定義を実行する
現時点で m1 モジュールが読み込まれていない場合は、広域定義リスト上の次の dcmd である m2`d が、広域定義として使用されます。dcmd や walker の現在の定義は、以下に示すように、::which dcmd を使用して定義できます。広域定義リストは、::which -v を使用して表示できます。
dcmd は、縦棒演算子 (|) を使ってパイプラインの中へ入れることができます。パイプラインの目的は、一般的に仮想アドレスのような値のリストを、1 つの dcmd や walker から次の dcmd や walker へと渡していくことです。パイプラインステージは、あるデータ構造体タイプのポインタを、それに対応するデータ構造体のポインタへと対応付けるために使用します。その目的は、アドレスリストをソートしたり、あるプロパティを持つ構造体のアドレスを選択したりすることです。
MDB は、パイプライン内の各 dcmd を左から右へと順番に実行します。現在のドット値、またはコマンドの開始時に明示的な式によって指定された値を使って、最も左にある dcmd が実行されます。縦棒演算子 (|) を見つけると、MDB は、その左側までの dcmd 出力、MDB 構文解析部、および空の値リストとの間に、パイプすなわち共用バッファを作成します。
dcmd を実行するにしたがって、その標準出力はパイプの中に配置され、次に構文解析部によって使用され、評価されます。それは、あたかも MDB が標準出力からデータを読み込んでいるように見えます。各行には、終端に復帰改行文字またはセミコロン (;) を持つ算術式が含まれます。その算術式の値は、パイプに関連付けられた値のリストに追加されます。構文エラーが発見されると、そのパイプラインは異常終了します。
縦棒演算子 (|) の左側までの dcmd が完了すると、そのパイプに関連付けられた値のリストは、縦棒演算子 (|) の右側の dcmd を呼び出すために使用されます。リストの各値については、ドットにその値が設定された後、右側の dcmd が実行されます。パイプラインの最も右にある dcmd だけが、その出力を標準出力に表示します。パイプライン内のいずれかの dcmd が標準エラー出力を生じた場合は、それらのメッセージを直接標準エラーに出力するので、パイプラインの一部としては処理されません。
/、¥、?、= などのメタキャラクタを使用して、特別な出力書式の dcmd を表します。各 dcmd では、1 つまたは複数の書式制御文字を含む引数リスト、繰り返し回数、または引用文字列を使用できます。書式制御文字は、以下の表に示すように、ASCII 文字の一種です。
書式制御文字を使用して、ターゲットからデータを読み取り、フォーマットします。繰り返し回数は、書式制御文字の前に位置する正の整数で、基数は、常に 10 進数として解釈されます。また、繰り返し回数は、先頭にドル記号を付けた角括弧で囲まれた式 ($[ ]) として指定される場合もあります。文字列の引数は、二重引用符 (" ") で囲みます。フォーマット引数の間には、空白は不要です。
dcmd のフォーマットは、次のとおりです。
ドットで指定される仮想アドレスで始まるターゲットの仮想アドレス空間からデータを表示する
ドットで指定される物理アドレスで始まるターゲットの物理アドレス空間からデータを表示する
ドットで指定される仮想アドレスに対応するオブジェクトファイル位置で始まるターゲットの一次オブジェクトファイルからデータを表示する
指定されたデータ書式のそれぞれにおいて、ドット値そのものを表示する。したがって、= dcmd は、基底間の変換と計算を行うときに便利である
また、MDB は、ドットのほかに、インクリメントと呼ばれる広域値も絶えずトラックしています。インクリメントは、ドットと、最後のフォーマット dcmd によって読み込まれるすべてのデータが後に続くアドレスとの距離を表します。
たとえば、フォーマット dcmd を、A というアドレスに等しいドットで実行した結果、4 バイトの整数が出力された場合、この dcmd が終了した後には、ドットはまだ A ですが、インクリメントは 4 に設定されています。「演算機能の拡張」で説明したように、ここでは、正符号 (+) は、A + 4 の値を出すための評価をします。その後、正符号は、次に続く dcmd 用のデータオブジェクトのアドレスにドットを設定し直します。
以下の表に示すように、ほとんどの書式制御文字は、データ書式のサイズに対応するバイトの数だけ、インクリメントの値を増分します。書式制御文字表は、::formats dcmd を使用して、MDB の内部から表示できます。書式制御文字は、次のとおりです。
カウントの数だけドットを増分する (変数サイズ)
カウントの数だけドットを減分する (変数サイズ)
l6 進数 int (1 バイト)
C の文字表記法を使う文字 (1 バイト)
10 進数の符号付き int (4 バイト)
10 進数の符号なし long long (8 バイト)
double (8 バイト)
8 進数の符号なし long long (8 バイト)
スワップバイトと short (4 バイト)
アドレスと分解命令 (変数サイズ)
16 進数 long long (8 バイト)
16 進数 uintptr_t (4 または 8 バイト)
8 進数の符号なし int (4 バイト)
シンボル (4 または 8 バイト)
8 進数の符号付き int (4 バイト)
C の文字列表記法を使った文字列 (変数サイズ)
10 進数の符号なし int (4 バイト)
10 進数の符号なし int (1 バイト)
デフォルト基数の符号なし int (4 バイト)
16 進数 int (4 バイト)
復号化される time32_t (4 バイト)
16 進数 long long (8 バイト)
インクリメント * カウントの数だけドットを減分する (変数サイズ)
symbol+offset としてのドット
8 進数の符号なし int (1 バイト)
文字 (1 バイト)
10 進数の符号付き short (2 バイト)
10 進数の符号付き long long (8 バイト)
float (4 バイト)
8 進数の符号付き long long (8 バイト)
スワップバイト (2 バイト)
命令の分解 (変数サイズ)
復帰改行
8 進数の符号なし short (2 バイト)
シンボル (4 または 8 バイト)
8 進数の符号付き short (2バイト)
余白
raw 文字列 (変数サイズ)
水平タブ
10 進数の符号なし short (2 バイト)
10 進数の符号付き int (1 バイト)
符号なしのデフォルト基数 short (2 バイト)
16 進数 short (2 バイト)
復号化される time64_t (8 バイト)
/、¥、および ? のフォーマット dcmd を使用して、ターゲットの仮想アドレス空間、物理アドレス空間、またはオブジェクトファイルに書き込みを行うことができます。この場合には、以下の修飾子の 1 つを最初の書式制御文字として指定し、次に、即値またはドル記号の後の角括弧に囲まれた式 ($[ ]) で表されるワードのリストを指定します。
書き込み修飾子は、次のとおりです。
各式の値の最下位 2 バイトを、ドットで指定された位置から始まるターゲットに書き込む
各式の値の最下位 4 バイトを、ドットで指定された位置から始まるターゲットに書き込む
各式の値の 8 バイトすべてを、ドットで指定された位置から始まるターゲットに書き込む
/、¥、および ? のフォーマット dcmd を使用して、ターゲットの仮想アドレス空間、物理アドレス空間、およびオブジェクトファイル内の特定の整数値を検索できます。この場合には、以下の修飾子の 1 つを最初の書式制御文字として指定し、次に、値とオプションマスクを指定します。各値とマスクは、即値またはドル記号の後の角括弧に囲まれた式として指定されます。
値だけが指定されている場合、MDB は、適当なサイズの整数値を読み取り、一致する値が含まれるアドレスのところで終了します。また、V という値と、M というマスクが指定されている場合、MDB は、適当なサイズの整数値を読み取り、(X & M) == V が存在する X という値が含まれるアドレスのところで終了します。dcmd が終了すると、ドットは、一致した値が含まれるアドレスに更新されます。一致する値が見つからなかった場合、ドットは、最後に読み込まれたアドレスに残されます。
検索修飾子は、次のとおりです。
指定された 2 バイトの値を検索する
指定された 4 バイトの値を検索する
指定された 8 バイトの値を検索する
ユーザーターゲットでも、カーネルターゲットでも、アドレス空間は、一般的に不連続セグメントセットで構成されています。対応するセグメントを持たないアドレスから読み込むことはできません。セグメント内で一致するものが検索されない場合には、検索は強制的に終了します。