ここでは以下のトピックで、Debug Tool を使用して C および C++ プログラムを デバッグする方法を説明します。
例: C および C++ ブロックでの変数の参照とブレークポイントの設定
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
Debug Tool のコマンド言語は、C および C++ コマンドのサブセットであり、構文上の要件は同じです。Debug Tool では慣れている言語によって作業ができるため、新しいコマンド・セットを学習する必要はありません。
下の表では、Debug Tool 認識される C および C++ コマンドの解釈サブセットを示します。
| コマンド | 説明 |
|---|---|
| block ({}) | 複合コマンド・グループ |
| break | ループまたは switch コマンドの終了 |
| declarations | セッション変数の宣言 |
| do/while | 繰り返しループ |
| expression | 条件 (?) 演算子を除くすべての C の式 |
| for | 繰り返しループ |
| if | 条件付きの実行 |
| switch | 条件付きの実行 |
このコマンドのサブセットは、現行のプログラム言語が C または C++ の場合にのみ有効です。
使用できる C および C++ コマンドのサブセットに加え、C および C++ が使用し認識する一連の予約されたキーワードがありますが、これらのキーワードは省略したり、変数名として使用したり、あるいはその他の ID として使用することはできません。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
Debug Tool は、C または C++ で有効なすべてのプログラム変数を 処理することができます。その結果、セッション中の変数の値の割り当ておよび表示が可能になります。また、認識されている C の宣言でセッション変数を宣言して、テストの必要性に 合わせることもできます。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
Debug Tool は、コンパイラーによって作成されたシンボル・テーブルを使用して、名前からプログラム変数に関する情報を入手します。コンパイル時に TEST(SYM) の指定を行っておけば、コンパイラーがシンボル・テーブルを作成するので、プログラム 内のすべての変数の参照ができるようになります。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
変数または式の値を表示するには、LIST コマンドを使用 します。LIST コマンドを使用すると、Debug Tool は変数の現行値 (必要な場合は名前も) を、式の評価結果とともに記録して表示します。
例えば、プログラム変数 X、row[X]、および col[X]、および行 25 でのその値を表示したいとします。 そこで、次のコマンドを出したとします。
AT 25 LIST ( X, row[X], col[X] ); GO;
Debug Tool は、行 25 にブレークポイントを設定し (AT)、プログラムの実行を開始し (GO)、行 25 で停止して、変数名とその値を表示します。
これらの値の加算結果を見るには、次のように入力してください。
AT 25 LIST ( X + row[X] + col[X] ); GO;
Debug Tool は、行 25 にブレークポイントを設定し (AT)、プログラムの実行を開始し (GO)、行 25 で停止して、式の結果を表示します。
複数のリストを出すときには、変数の間にコンマを置いてください。LIST コマンドを出すときに、変数名を表示したくない場合は、LIST UNTITLED と入力します。
次のようにして、printf 関数呼び出しによって 変数をリストすることもできます。
printf ("X=%d, row=%d, col=%d\n", X, row[X], col[X]);ただし、SET INTERCEPT ON FILE stdout を設定しないかぎり、printf からの出力はログ・ウィンドウには表示されず、ログ・ファイルにも記録されません。
C および C++ 変数に値を割り当てるには、代入式を使用します。代入式は、値を左辺オペランドに代入します。左辺オペランドは、更新可能な左辺値でなければなりません。左辺値は、検査して変更できるデータ・オブジェクトを表す式です。
C には、単純および複合の 2 つのタイプの代入演算子があります。単純代入演算子は、右辺オペランドの値を左辺オペランドに代入します。
次の例は、number の値を、構造 payroll のメンバー employee に代入する方法を示しています。
payroll.employee = number;
複合代入演算子は、両方のオペランドで演算を実行してから、その演算結果を 左辺オペランドに代入します。例えば、次の式は、index plus 2 の値を変数 index に代入します。
index += 2
Debug Tool は、tenary 演算子以外のすべての C 演算子をサポートし、また 他のすべての C 言語の代入、およびユーザー・ライブラリー または C ライブラリー関数への関数呼び出しをサポートします。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
下の表は、現行プログラム言語が C および C++ のときの、Debug Tool の 変数 %PATHCODE に使用可能な値を示しています。
| -1 | Debug Tool は、パスまたはアテンション状態の結果、制御をもっていません。 |
| 0 | アテンション関数 (ATTENTION 条件ではありません)。 |
| 1 | ブロックに入っています。 |
| 2 | ブロックから出ようとしています。 |
| 3 | 制御がユーザー・ラベルに達しました。 |
| 4 | 関数参照の結果、制御が渡されています。呼び出されたルーチンのパラメーターがあれば、それは準備ができています。 |
| 5 | 関数参照から制御が戻されました。レジスター 15 に含まれる戻りコードはまだ記憶されていません。 |
| 6 | 条件ステートメントの do/while、for、または while に含まれるロジックが実行されようとしています。これは、単一ステートメントかヌル・ステートメントであり、ブロック・ステートメントではありません。 |
| 7 | if(...) に続くロジックが 実行されようとしています。 |
| 8 | else に続くロジックが実行されようとしています。 |
| 9 | switch 内の case に続くロジックが実行されようとしています。 |
| 10 | switch 内のデフォルトに続くロジックが実行されようとしています。 |
| 13 | switch、do、while、if(...)、または for の終わりに続くロジックが実行されようとしています。 |
| 17 | goto、break、continue、または return が実行されようとしています。 |
プログラムがパス・フックをサポートするオプションでコンパイルされた場合、3 から 17 の範囲内の値だけを %PATHCODE に割り当てることができます。
セッション時に使用できるように、セッション変数を宣言してください。宣言でセッション変数を初期設定することはできません。ただし、セッション変数を初期設定するために、割り当てステートメントまたは関数呼び出しを使用することはできます。
C の場合と同様に、キーワードは任意の順序で指定することができます。変数名は、最高 255 文字の長さまで使用することができます。ID は、大文字と小文字の区別をしますが、現行のプログラム言語が C から別の HLL に変更するときにセッション変数を使用したい場合には、変数は、大文字の名前および互換性 のある属性をもたなければなりません。
maximum という 16 進 浮動小数点変数を宣言するには、次の C 宣言を入力します。
double maximum;
Debug Tool では、スカラー、スカラーの配列、構造体、および共用体だけを宣言することができます (これらに対するポインターも宣言することができます)。
プログラミング変数と同じ名前でセッション変数を宣言すると、セッション変数はプログラミング変数を隠します。プログラミング変数を参照するには、それを修飾しなければなりません。例えば、次のようになります。
main:>x for the program variable x x for the session variable x
セッション変数は、CLEAR コマンドを使用してクリアしないかぎり、デバッグ・セッション全体にわたって有効です。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
Debug Tool では、テスト・プログラム内で式の計算を行うことができます。C および C++ で使用できるすべての式は、条件式 (? :) を除き、Debug Tool 内でも使用できます。すなわち、+、-、%:、および += などの演算子はすべて、完全にサポートされます (条件演算子は例外です)。
C および C++ 言語の式は、含まれる演算子とその使い方にもとづいて、次のようなグループに分類されます。
左辺値は、検査して変更できるデータ・オブジェクトを表す式です。式および演算子の詳しい説明は、C および C++ のプログラムの手引きを 参照してください。
C および C++ 演算子のセマンティクスは、コンパイルされた C または C++ プログラムの 場合と同じです。オペランドは、定数 (整数、浮動小数点、文字、ストリング、および列挙型)、C および C++ 変数、Debug Tool 変数、または Debug Tool セッション時に宣言されたセッション変数を組み合わせて作ることができます。言語定数は、C および C++ の言語参照資料に説明されているとおりに 指定します。
Debug Tool コマンド DESCRIBE ATTRIBUTES を使用して、実際に式を計算しなくても、式の計算結果のタイプを表示することができます。
C および C++ 言語は、関数呼び出しの引数に対する計算順序は指定しません。したがって、式は、コンパイルされたコード内では、Debug Tool 内とは異なる実行 順序をもつことがあります。例えば、対話式セッションで次のように入力します。
int x;
int y;
x = y = 1;
printf ("%d %d %d%" x, y, x=y=0);この場合、結果は、C または C++ プログラム・セグメント内にある同じステートメントによる結果とは異なる場合があります。ANSI 規格によって定義されていない動作を含む式は、Debug Tool が評価するとき、コンパイラーが評価するときとは異なった結果を出す場合があります。
次の例は、Debug Tool がプログラム内の式の使用をサポートするさまざまな 方法を示しています。
a = (1,2/3,a++,b++,printf("hello world\n"));league[num].team[1].player[1]++; league[num].team[1].total += 1; ++(*pleague);
v.x = 3; a = b = c = d = 0; *(pointer++) -= 1;
*pointer_to_long = 3521L = 0x69a1; float_val = 3e-11 + 6.6E-10; char_val = '7';
intensity <<= 1, shade * increment, rotate(direction); alpha = (y>>3, omega % 4);
long_double_val = unsigned_short_val; long_double_val = (long double) 3;
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
Debug Tool 内で、ユーザー・ライブラリー関数 および C ライブラリー関数への呼び出しを実行できます。ただし、ご使用のプログラムを DEBUG コンパイラー・オプションの FORMAT(DWARF) サブオプションを用いてコンパイルした場合は除きます。
C ライブラリー関数にはいつでも呼び出しを行うことができます。さらに、関数呼び出しを含む式で、C ライブラリー変数 stdin、stdout、stderr、__amrc、および errno を使用することができます。
ライブラリー関数 ctdli は、プログラム main あるいは main にリンクされた関数のどちらかにおいてコンパイル単位に参照が設定されていない場合は、呼び出すことができません。
ユーザー関数への呼び出しは、Debug Tool が、関数に関する必要な定義を ユーザー・プログラムのシンボル情報の中から探し出すことで きれば可能です。これらの定義は、プログラムが TEST(SYM) (C の 場合) または TEST (C++ の場合) を使用してコンパイルされる時に作成されます。
Debug Tool は、可能な場合、パラメーター変換およびパラメーター・ミスマッチ検査を 実行します。パラメーター検査は、次のような場合に実行されます。
SET WARNING OFF を指定することによって、この検査をオフにすることができます。
呼び出しは、C または C++ コンパイラーがリンケージを サポートしているユーザー関数であれば、どれに対しても行うことができます。ただし、C++ の場合、ユーザー関数を呼び出す場合は、関数を次のように宣言しておく必要があります。
extern "C"
例えば、アプリケーションのシグナル・ハンドラーを デバッグしたい場合にこの宣言を使用します。条件が発生すると、制御が Debug Tool に渡り、次にシグナル・ハンドラーに渡されます。
Debug Tool は、リンケージ検査を行って、リンケージのミスマッチがあると 判断した場合には、関数呼び出しを実行しません。リンケージのミスマッチは、ターゲット・プログラムにリンケージの指定があるが、ソース・プログラムには別のリンケージが指定されていると思われる場合に発生します。
関数呼び出しに関しては次の点に注意することが大切です。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
次の表に、C 言語によって予約済みのキーワードをすべて リストします。現行プログラム言語が C か C++ の場合、これらのキーワードを省略して、変数名として使用したり、ほかのタイプの ID として使用したりすることはできません。
| auto | else | long | switch |
| break | enum | register | typedef |
| case | extern | return | union |
| char | float | short | unsigned |
| const | for | signed | void |
| continue | goto | sizeof | volatile |
| default | if | static | while |
| do | int | struct | _Packed |
| double |
次の表には、C 言語演算子を優先順位に基づいてリストし、各演算子の関連性の方向を示しています。1 次演算子が最も高い優先順位を持ちます。コンマ演算子が最も低い優先順位を持ちます。同じグループに属する演算子は、優先順位も同じです。
| 優先順位 | 関連性 | 演算子 |
|---|---|---|
| 1 次 | 左から右へ | () [ ] . -> |
| 単項 | 右から左へ | ++ -- - + ! ~ & * (typename) sizeof |
| 乗除 | 左から右へ | * / % |
| 加減 | 左から右へ | + - |
| ビット単位のシフト | 左から右へ | << >> |
| 関係 | 左から右へ | < > <= >= |
| 等価 | 左から右へ | ++ != |
| ビット単位の論理 AND | 左から右へ | & |
| ビット単位の排他的 OR | 左から右へ | ^ または ¬ |
| ビット単位の包含 OR | 左から右へ | | |
| 論理 AND | 左から右へ | && |
| 論理 OR | 左から右へ | || |
| 割り当て | 右から左へ | = += -= *= /= <<= >>= %= &= ^= |= |
| コンマ | 左から右へ | , |
言語環境プログラム条件名 (シンボリック・フィードバック・コード CEExxx) は、次の表 にリストされている同等機能の C および C++ 条件と、相互に置き換えることが 可能です。例えば、AT OCCURRENCE CEE341 は AT OCCURRENCE SIGILL と 同等です。CEE341 条件の発生で、AT OCCURRENCE SIGILL ブレークポイントが起動され、その逆も成り立ちます。
| 言語環境プログラム条件 | 説明 | 同等の C/C++ 条件 |
|---|---|---|
| CEE341 | 演算例外 | SIGILL |
| CEE342 | 特権命令例外 | SIGILL |
| CEE343 | 実行例外 | SIGILL |
| CEE344 | 記憶保護例外 | SIGSEGV |
| CEE345 | アドレッシング例外 | SIGSEGV |
| CEE346 | 指定例外 | SIGILL |
| CEE347 | データ例外 | SIGFPE |
| CEE348 | 固定小数点オーバーフロー例外 | SIGFPE |
| CEE349 | 固定小数点除算例外 | SIGFPE |
| CEE34A | 10 進オーバーフロー例外 | SIGFPE |
| CEE34B | 10 進除算例外 | SIGFPE |
| CEE34C | 指数オーバーフロー例外 | SIGFPE |
| CEE34D | 指数アンダーフロー例外 | SIGFPE |
| CEE34E | 有効数字例外 | SIGFPE |
| CEE34F | 浮動小数点除算例外 | SIGFPE |
Debug Tool は、ほとんどの入力を 1 つ以上の式の集まりとして解釈します。式を使用して、プログラム変数を変更したり、AT ブレークポイントが制御しているポイントに式を追加してプログラムを拡張することができます。
Debug Tool は、C および C++ の式を「z/OS XL C/C++ ランゲージ・リファレンス」に示されている規則に従って評価します。式の計算の結果は、それと同じ式がコンパイルされたプログラムの 一部である場合の結果と同 じです。
暗黙のストリング連結がサポートされます。例えば、"abc" "def" は、"abcdef" として受け入れられ、同一のものとして扱われます。長いストリング・リテラルとストリング・リテラルの連結は、受け入れられません。例えば、L"abc"L"def" は有効であり、L"abcdef" と同値ですが、"abc" L"def" は無効です。
セッション時に使用する式は、式をコンパイルしたときの使用可能性と同じセンシティビティーで評価されます。使用可能になる条件は、プログラム・ステートメントについて存在する条件と 同じです。
Debug Tool のセッション時に、WARNING の現行の設定値が ON であれば、以下にリストしたいずれか 1 つの条件に当てはまる C または C++ プログラムが存在すると、診断メッセージが表示されます。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
C アプリケーションのデバッグ時に、SET INTERCEPT コマンドを使用してファイルを代行受信 (インターセプト) する場合、いくつかの考慮事項に注意する必要があります。
CICS® の場合のみ: SET INTERCEPT は CICS ではサポートされません。
C++ の場合、入出力ストリームの代行受信に特定のサポートはありません。入出力ストリームは C I/O を使用してインプリメントされますが、その意味は次のとおりです。
デバッグ・セッション中に、次の名前を SET INTERCEPT コマンドで使用できます。
入出力インターセプトの動作は、system() 呼び出し境界を超える グローバルなものです。これは、プログラム A の中での INTERCEPT ON for xx の 設定は、プログラム B でも有効である (プログラム A が プログラム B に system() 呼び出しを行っている場合) ことを意味します。したがって、プログラム B がプログラム A に戻るようになっている場合には、プログラム B での xx に対する INTERCEPT OFF の設定は、プログラム A のインターセプトの設定をオフにします。この関係は、プログラム B でファイルをインターセプトし、プログラム B がプログラム A に戻る場合にも成り立ちます。このモデルは、ディスク・ファイル、メモリー・ファイル、および標準ストリームにも適用されます。
ストリームはインターセプトされると、fopen ステートメントで指定された text/binary 属性を継承します。Debug Tool のログ・ファイルへの入出力は、端末入出力と同じように動作しますが、次のような考慮事項があります。
インターセプトされたファイルのそのほかの特性は、次のとおりです。
標準ストリームのコマンド行のリダイレクトは、Debug Tool のもとで次に 示すようにサポートされます。
同じ標準ストリームを二度コマンド行でリダイレクトすることはできません。次に示すように、インターセプトはこの規則が違反されると定義されません。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
オブジェクトは、そのデータ・タイプおよび宣言された名前がブロックまたはソース・ファイルの中で認識されれば、そのブロックまたはソース・ファイル内で可視 になります。オブジェクトが可視である領域は、その有効範囲として呼ばれます。Debug Tool では、変数または関数をオブジェクトにすることができ、また 行番号の参照にも使用します。
ANSI C では、次の 4 つの種類の有効範囲があります。
C++ の場合、C に対して定義された有効範囲に加えて、クラス有効範囲もあります。
オブジェクトは、その宣言がブロック内部にあれば、ブロック有効範囲を もちます。ブロック有効範囲をもつオブジェクトは、宣言されている点からブロックを 終了する右中括弧 (}) までが可視領域です。
オブジェクトの定義が任意のブロック外部にあれば、そのオブジェクトはファイル有効範囲をもちます。ファイル有効範囲をもつオブジェクトは、その宣言の場所からソース・ファイルの 終わりまでが、可視領域になります。Debug Tool では、コンパイル単位をファイルの静的変数で修飾すると、ファイル静的変数およびグローバル変数は常に可視的なものです。
関数有効範囲をもつオブジェクトの唯一のタイプは、ラベル名です。
オブジェクトの宣言が関数のプロトタイプのパラメーター・リスト内にあれば、そのオブジェクトは関数のプロトタイプ有効範囲をもちます。
クラス・メンバーは、その宣言がクラス内にある場合は、クラス有効範囲をもちます。
関数のプロトタイプ有効範囲で可視オブジェクトを参照することはできませんが、次のような場合には、ファイル有効範囲またはブロック有効範囲で可視オブジェクトは参照できます。
Debug Tool は、ANSI と同じ有効範囲の規則に従いますが、ファイル有効範囲ではオブジェクトの扱い方が異なります。ファイル有効範囲のオブジェクトは、ソース・ファイル内のそれが宣言されている場所からだけでなく、ソース・ファイル内の任意の場所で Debug Tool の中から参照できます。Debug Tool のセッション変数は、常にプログラム変数よりも高い有効範囲をもつので、同じ名前をもつプログラム変数よりも高い優先順位をもちます。プログラム変数は、常に修飾を介してアクセスできます。
さらに、Debug Tool は複数のロード・モジュールにある変数の参照を サポートします。複数のロード・モジュールは、C ライブラリー関数 dllload()、dllfree()、fetch()、および release() を介して管理されます。
例: C および C++ ブロックでの変数の参照とブレークポイントの設定
Debug Tool は、次のストレージ・クラスを使用して宣言されたすべてのオブジェクトの変更および参照をサポートします。
Debug Tool セッション中に宣言されたセッション変数は、参照および変更用に 使用することもできます。
auto ストレージ・クラスをもつオブジェクトは、その中で オブジェクトが定義されたブロックが活動状態であれば、Debug Tool で 参照または変更用に使用できます。一度ブロックが実行を終了すると、このブロック内の auto 変数は、変更には使用できなくなりますが、DESCRIBE ATTRIBUTES を使用して検査することは可能です。
register ストレージ・クラスのオブジェクトは、変数がレジスターに 対して最適化されていなければ、Debug Tool で参照または変更に使用できる場合があります。
static ストレージ・クラスのオブジェクトは、常に Debug Tool で変更または参照に使用できます。現在修飾されているコンパイル単位にない場合には、それを明確に 修飾しなければなりません。
extern ストレージ・クラスのオブジェクトは、常に Debug Tool で変更または参照に使用できます。また、プログラム内の変数などは、このソース・ファイルの中で定義または参照されなくても、参照することができます。これは、Debug Tool が別のコンパイル単位 (TEST(SYM) を使用してコンパイルされたもの) を、適切な定義で探すことができる場合に可能です。
あるブロックへの入口、またはそのブロックからの出口にブレークポイントを設定したり、現行ブロックから直接には見えない変数を参照する必要があることがしばしばあります。すべてのブロックに名前が付けられていれば、Debug Tool はこれを行えます。Debug Tool は、次の命名規則を使用します。
これらのブロック名が Debug Tool コマンドで使用されると、同じソース・ファイルの異なる 関数内でネストされたブロック同士を区別する必要があります。そのためには次の 2 つの方法のいずれかを使用してブロックに名前を付けます。
%BLOCKzzz は %BLOCKyyy の中に含まれ、%BLOCKyyy は %BLOCKxxx の中に含まれます。短い形式が常に使用できますから、長い形式での指定は必ずしも必要ではありません。
現在活動状態のブロック名は、Debug Tool 変数 %BLOCK から検索することができます。次のように入力して、ブロックの名前を表示することができます。
DESCRIBE CU;
C++ の場合、ブロック ID が C の場合よりも長くなりがちである理由は、C++ の関数は多重定義できるからです。ある関数名を他の関数名と区別するために、それぞれのブロック ID は プロトタイプと同じ意味をもちます。例えば、C で shapes(int,int) の名前をもつ関数は、shapes という名のブロックをもちますが、C++ では ブロック名は shapes(int,int) となります。
C++ のブロックは、関数が多重定義されていなくても、ブロック全体の ID を指す必要があります。すなわち、shapes(int,int) の参照は、shapes のみではできません。
ブロック名を相当に長くすることができるため、画面の 1 行目の LOCATION フィールドで、名前 が切り捨てられて表示されることはまれではありません。位置を正確に知る必要がある場合は、次のように入力します。
QUERY LOCATION
名前の全体がセッション・ログに表示されます (行を折り返して)。
ブロック ID の長さは 255 文字までの制限があります。255 文字以上の名前は切り捨てられます。
次のプログラムはいくつかのプログラムの基本として使用されます。これに ついてはプログラム・リストの後に説明します。
#pragma runopts(EXECOPS)
#include <stdlib.h>
main()
{
>>> Debug Tool is given <<<
>>> control here. <<<
init();
sort();
}
short length = 40;
static long *table;
init()
{
table = malloc(sizeof(long)*length);
·
·
·
}
sort ()
{ /* Block sort */
int i;
for (i = 0; i < length-1; i++) { /* If compiled with ISD, Block %BLOCK2; */
/* if compiled with DWARF, Block %BLOCK8 */
int j;
for (j = i+1; j < length; j++) { /* If compiled with ISD, Block %BLOCK3; */
/* if compiled with DWARF, Block %BLOCK13 */
static int temp;
temp = table[i];
table[i] = table[j];
table[j] = temp;
}
}
}
上記に示すプログラムが TEST(SYM) でコンパイルされているとします。Debug Tool が制御を受け取ると、ファイル有効範囲変数 length および table は次のように変更が可能です。
length = 60;
ブロック有効範囲変数 i、j、および temp はこの有効範囲では可視ではなく、この時点では Debug Tool の中から直接参照することはできません。次のコマンドを入力して、現在の有効範囲内の行番号をリストできます。
LIST LINE NUMBERS;
このプログラムが TEST(SYM, NOBLOCK) でコンパイルされているとします。プログラムが NOBLOCK を使用して明示的にコンパイルされると、変数 j および temp は別のブロックで ネストされたブロックで定義されているので、Debug Tool がこれらの変数を認識することはできません。Debug Tool は、変数 i がネストされた有効範囲内にないので、これを認識します。
上記のプログラムでは、関数 sort には以下の 3 つの ブロックがあります。
| プログラムが、ISD コンパイラー・オプションでコンパイルされる場合 | プログラムが、DWARF コンパイラー・オプションでコンパイルされる場合 |
|---|---|
| sort | sort |
| %BLOCK2 | %BLOCK8 |
| %BLOCK3 | %BLOCK13 |
次のようにして、入り口のブレークポイントを sort の 2 番目のブロックにセットします。
次の例は、main の最初のブロックの出口にブレークポイントをセットして、ソートされたテーブルの項目をリストします。
at exit main {
for (i = 0; i < length; i++)
printf("table entry %d is %d\n", i, table[i]);
}
次の例は、sort の 3 番目のブロック内の変数 temp をリストします。これは、temp が static ストレージ・クラスを持つので可能です。
DESCRIBE コマンドを使用して、現行のランタイム環境に該当する属性のリストを表示することもできます。表示される情報のタイプは、言語によって異なります。
DESCRIBE ENVIRONMENT を発行すると、ランタイム環境によりモニターされているオープン・ファイルと条件のリストが表示されます。例えば、C または C++ プログラム のデバッグ中に DESCRIBE ENVIRONMENT を入力すると、次のような出力が得られます。
Currently open files
stdout
sysprint
The following conditions are enabled:
SIGFPE
SIGILL
SIGSEGV
SIGTERM
SIGINT
SIGABRT
SIGUSR1
SIGUSR2
SIGABND
修飾は、次のことを行うための方法です。
名前が競合する場合、またはプログラムが複数のロード・モジュール、コンパイル単位または関数 (あるいはその両方) で構成されているときに、修飾が必要になります。
プログラムの実行が中断され、Debug Tool が制御を受け取ると、デフォルトの修飾、すなわち暗黙の 修飾が、プログラムの中断した場所での 活動ブロックになります。このブロック内の C または C++ プログラムにとって可視的であるすべてのオブジェクトは、Debug Tool にとっても可視的です。このようなオブジェクトは、修飾子を使用せずにコマンドで指定することができます。それ以外はすべて、明示修飾 を使用して指定されなければなりません。
次のことに考慮して、オブジェクトを正確に指定することができます。
これらは修飾子として認識され、その一部またはすべては、オブジェクトをコマンドで参照するときに必須です。修飾子は、より大きい記号 (>) とコロンの組み合わせで区切り、その後に修飾するオブジェクトを置きます。例えば、次は、完全修飾のオブジェクトです。
load_name::>cu_name:>block_name:>object
必要であれば、load_name がロード・モジュールの名前となります。ロード・モジュールの名前は、プログラムが複数のロード・モジュールで 構成される場合で、かつ修飾を現行のロード・モジュール以外に変更したい 場合にのみ必要です。load_name は二重引用符 (") で囲みます。 そうでない場合は、C または C++ プログラム言語で有効な識別名でなければなりません。load_name は、Debug Tool 変数の %LOAD にすることもできます。
必要であれば、CU_NAME がコンパイル単位またはソース・ファイルの名前となります。cu_name は、完全に修飾されたソース・ファイル名であるか、または絶対パス名でなければなりません。この指定は、現在修飾しているコンパイル単位以外に修飾を変更したい 場合にのみ必要です。これは、Debug Tool 変数 %CU にすることができます。コンパイル単位名と (例えば) ブロック名との間があいまいである場合には、コンパイル単位名を引用符 (") で囲まなければなりません。
必要であれば、block_name がブロックの名前となります。block_name は、Debug Tool 変数の %BLOCK にすることができます。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
コマンド行またはコマンド・ファイルから視点を変更するには、修飾子を SET QUALIFY コマンドで使用してください。この方法は、現行の視点からはアクセスできないデータを獲得するのに 必要であり、多くの オブジェクトが参照されるときのデバッグ操作を簡単にすることができます。
視点を別のロード・モジュールや DLL、別のコンパイル単位、ネストされたブロック、またはネストされていないブロックに変更することができます。SET キーワードはオプションです。
下記の例では次のプログラムを使用します。
LOAD MODULE NAME: MAINMOD
SOURCE FILE NAME: MVSID.SORTMAIN.C
short length = 40;
main ()
{
long *table;
void (*pf)();
table = malloc(sizeof(long)*length);
·
·
·
pf = fetch("SORTMOD");
(*pf)(table);
·
·
·
release(pf);
·
·
·
}
LOAD MODULE NAME: SORTMOD
SOURCE FILE NAME: MVSID.SORTSUB.C
short length = 40;
short sn = 3;
void (long table[])
{
short i;
for (i = 0; i < length-1; i++) {
short j;
for (j = i+1; j < length; j++) {
float sn = 3.0;
short temp;
temp = table[i];
·
·
·
>>> Debug Tool is given <<<
>>> control here. <<<
·
·
·
table[i] = table[j];
table[j] = temp;
}
}
}
Debug Tool が制御を得ると、変数 i、j、temp、table、および length は、修飾子なしでコマンドに指定できます。変数 sn が参照される場合、Debug Tool は float である変数を使用します。ただし、ブロックとコンパイル単位の名前は異なり、オペレーティング・システムとの互換性を維持します。
"SORTMOD"::>"MVSID.SORTSUB.C":>length = 20;
%LOAD::>"MVSID.SORTMAIN.C":>length = 20;
length は現行のロード・モジュールとコンパイル単位内に あるので、次のようにして変更することもできます。
length = 20;
AT CHANGE temp; AT CHANGE %BLOCK3:>temp; AT CHANGE sort:%BLOCK3:>temp; AT CHANGE %BLOCK:>temp; AT CHANGE %CU:>sort:>%BLOCK3:>temp; AT CHANGE "MVSID.SORTSUB.C":>sort:>%BLOCK3:>temp; AT CHANGE "SORTMOD"::>"MVSID.SORTSUB.C":>sort:>%BLOCK3:>temp;
この例の %BLOCK および %BLOCK3 変数は、プログラムが ISD コンパイラー・オプションを使用してコンパイルされたと想定します。DWARF コンパイラー・オプションを使用して例がコンパイルされた場合は、DESCRIBE PROGRAM コマンドを入力して、正しい %BLOCK 変数を決定します。
SET QUALIFY BLOCK %BLOCK2;これを行うには他にも多くの方法があり、例えば次の方法でもできます。
QUALIFY BLOCK sort:>%BLOCK2;
一度視点が変更されると、Debug Tool は、この視点からアクセスできるオブジェクトにアクセスします。次のようにして、これらのオブジェクトを修飾子を用いずにコマンドで指定することができます。
j = 3; temp = 4;
QUALIFY BLOCK "MAINMOD"::>"MVSID.SORTMAIN.C":>main; LIST table[i];
オブジェクトを生成 (construct) および消去 (destruct) しながら、メソッドをステップスルーできます。さらに、静的なコンストラクター (生成関数) とデストラクター (消去関数) を ステップスルーすることができます。これらはそれぞれ、main() の前と後に実行されるオブジェクトのメソッドです。
ヘッダー・ファイルにある関数を呼び出すプログラムをデバッグする場合、カーソルはアプリケーションのヘッダー・ファイルに移動します。そうすると、関数のソースをステップスルーするとき、それを見ることができます。関数から戻った後は、関数を呼び出した元の場所に続く行から デバッグが続行します。
また、STEP OVER コマンドにより、ヘッダー・ファイル関数を飛ばしてステップを進めることもできます。これは、自分ではデバッグができないライブラリー関数 (例: string.h に定義されたストリング関数) をステップオーバーするときに便利です。
C++ と C でのブレークポイントの設定の違いについて、次に説明します。
AT ENTRY/EXIT は、指定されたブロックにブレークポイントをセットします。メソッド、ネストされたクラスの中のメソッド、テンプレート、多重定義の演算子に対してブレークポイントの設定ができます。それぞれの例を下に示します。
ブロック ID は非常に長くなることがあり、特に、テンプレート、ネストされたクラス、多段階の継承をもつクラスでは長くなります。実際、特定の関数に対応するブロック名は、最初明確に分からない場合さえあります。これらの重要なブロックにブレークポイントをセットするのは、非常に面倒でもあります。したがって、DESCRIBE CU を使用 して、セッション・ログからブロック ID を検索することを お勧めします。
DESCRIBE CU を実行すると、常にクラスで修飾されたメソッドが 表示されます。メソッドが固有の場合には、メソッド名だけの使用でブレークポイントの設定が可能です。メソッドが固有でない場合には、メソッドをクラス名で修飾することが必要です。次の 2 つの例は同等です。
AT ENTRY method() AT ENTRY classname::method()
次の例は有効です。
| AT ENTRY square(int,int) | 「単純」メソッド square |
| AT ENTRY shapes::square(int) | メソッド square はそのクラス shapes により修飾されます。 |
| AT EXIT outer::inner::func() | ネストされたクラス。outer と inner はクラスです。func() はクラス inner の中にあります。 |
| AT EXIT Stack<int,5>::Stack() | テンプレート。 |
| AT ENTRY Plus::operator++(int) | 多重定義演算子。 |
| AT ENTRY ::fail() | ファイル有効範囲で定義された関数は、グローバル有効範囲演算子 :: により参照する必要があります。 |
次の例は無効です。
| AT ENTRY shapes | ここで、shapes はクラスです。クラスにブレークポイントをセットすることはできません。(クラスにはブロック ID がありません。) |
| AT ENTRY shapes::square | メソッド square の後にはパラメーター・リストが必要なので、無効です。 |
| AT ENTRY shapes:>square(int) | shapes が、ブロック名ではなくクラス名なので無効です。 |
AT CALL は、アプリケーション・コードが指定の入り口点を 呼び出そうとしたときに、Debug Tool に制御を与えます。入り口名は、完全修飾名である必要があります。すなわち、DESCRIBE CU で示される名前を使用する必要があります。次の例、
AT ENTRY shapes::square(int)
を使用し、メソッド square にブレークポイントをセットするには、次を入力する必要があります。
AT CALL shapes::square(int)
square が固有のものとして識別可能であっても、この形の指定が必要です。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
C++ オブジェクトを表示する場合、ローカル・メンバー変数のみが表示されます。アクセス・タイプ (public、private、protected) は、変数間で区別されません。メンバーの関数は表示されません。メンバーの関数の属性を見たい場合は、個々には表示できますが、クラスと 関連付けての表示はできません。派生クラスを表示する場合、その中にある基底クラスがタイプ・クラスとして表示され、拡張されません。
このトピックで説明している内容に関して詳しくは、以降のトピックを参照してください。
下記の例では次の定義を使用します。
class shape { ... };
class line : public shape {
member variables of class line...
}
line edge;
オブジェクト edge の属性を記述するには、次のコマンドを入力します。
DESCRIBE ATTRIBUTES edge;
ログ・ウィンドウには次の出力が表示されます。
DESCRIBE ATTRIBUTES edge;
ATTRIBUTES for edge
Its address is yyyyyyyy and its length is xx
class line
class shape
member variables of class shape....
基底クラスは、クラス shape _shape として表示されていることに 注意してください。
クラス shape の属性を表示するには、次のコマンドを入力します。
DESCRIBE ATTRIBUTES class shape;
ログ・ウィンドウには次の出力が表示されます。
DESCRIBE ATTRIBUTES class shape ; ATTRIBUTES for class shape const class shape...
クラスに静的データが含まれる場合、その静的データは クラスの一部として表示されます。例えば、次のようになります。
class A {
int x;
static int y;
}
A obj;クラス A の各オブジェクトは同じ値を持つため、A::y として静的メンバーを参照し、静的メンバーを表示することもできます。
あいまいさを避けるために、ファイル有効範囲で宣言した変数の参照には、グローバル有効範囲演算子 :: の使用が可能です。例えば、次のようになります。
int x;
class A {
int x;
·
·
·
}
}
A のメンバー関数のなかにいるときに、ファイル有効範囲で x の値を 表示したい場合は、LIST ::x と入力します。:: を使用せずに、LIST x を入力すると、現行オブジェクトの x の値 (すなわち、this->x) を表示します。
LIST REGISTERS コマンドを使用して、コードとアセンブリー・リストをステップごとに進めながら、レジスター (汎用および浮動小数点) をモニターすると便利な場合があります。コンパイラー・リストは、Debug Tool のフックを含め、疑似アセンブリー・コードを表示しています。停止する場所のフックを見たり、フックの間の疑似アセンブリー命令にしたがって、レジスター内の値が予期したとおりに 変わっていくのを段階的に監視することができます。また、コードをステップごとに進めながら、マシン・レジスターの 値を変更することもできます。
ストレージの内容はさまざまな方法でリストすることができます。LIST REGISTERS コマンドを使用すると、汎用レジスターまたは浮動小数点レジスターの内容のリストを得ることができます。
ストレージのダンプ形式の表示を指定して、ストレージの内容を モニターすることもできます。これを行うには、LIST STORAGE コマンドを使用します。表示したいストレージのアドレス、およびバイト数を指定することができます。
下記の例では、次の C プログラムを使用してレジスターとストレージの モニターと変更の方法を示しています。
int dbl(int j) /* line 1 */
{ /* line 2 */
return 2*j; /* line 3 */
} /* line 4 */
int main(void)
{
int i;
i = 10;
return dbl(i);
}
コンパイラー・オプション TEST(ALL),LIST を使用して上記のプログラムをコンパイルすると、疑似アセンブリー・リストは下記に示すようなものになります。
* int dbl(int j)
ST r1,152(,r13)
* {
EX r0,HOOK..PGM-ENTRY
* return 2*j;
EX r0,HOOK..STMT
L r15,152(,r13)
L r15,0(,r15)
SLL r15,1
B @5L2
DC A@5L2-ep)
NOPR
@5L1 DS 0D
* }
@5L2 DS 0D
EX r0,HOOK..PGM-EXIT
モニター・ウィンドウに、更新されたレジスターを継続的に 表示するには、次のコマンドを入力します。
MONITOR LIST REGISTERS
少しステップを進めた後、Debug Tool は行 1 (上記のリスト に示すプログラム入り口フック) で停止します。ここで STEP すると、行 3 に進み、ステートメント・フック で停止します。次に STEP すると、行 4 に進み、プログラム出口フックで 停止します。疑似アセンブリー・リストが示すように、この STEP 処理の間、レジスター 15 だけが変更され、ここには関数の戻り値が 含まれることがわかります。モニター・ウィンドウには、レジスター 15 に予想した値 0x00000014 (10 進数の 20) が 表示されています。
次のコマンドを出して、dbl() から戻る直前に、値を 20 から 8 に変更することができます。
%GPR15 = 8 ;