fix を使用すると、デバッグプロセスを停止しないで、編集されたソースコードを簡単に再コンパイルすることができます。
この章は次の各節から構成されています。
fix と continue の各機能を使用すると、ソースファイルを修正して再コンパイルし、プログラム全体を作成しなおすことなく実行を続けることができます。.o ファイルを更新して、それらをデバッグ中のプログラムに組み込むことにより、再リンクの必要がなくなります。
この機能を使用する利点は次のとおりです。
プログラムをリンクしなおす必要がない。
プログラムを dbx に再読み込みする必要がない。
修正した位置からプログラムの実行を再開できる。
構築が進行中の場合は、fix を使用しないでください。
fix コマンドを適用する前に、エディタでソースを編集する必要があります。ソースファイルを変更した後、fix と入力します。
fix が実行されると、dbx は適切なコンパイラオプションでコンパイラを呼び出します。変更後のファイルがコンパイルされ、一時共有オブジェクト (.so) ファイルが作成されます。古いファイルと新しいファイルとを比較することによって、修正の安全性を検査する意味上のテストが行われます。
実行時リンカーを使用して新しいオブジェクトファイルが動作中のプロセスにリンクされ、プログラムカウンタが古い関数から新しい関数の同じ行に移動します (その関数が修正中のスタックの 1 番上にある場合)。さらに、古いファイルのブレークポイントがすべて新しいファイルに移動します。
対象となるファイルがデバッグ情報つきでコンパイルされているかどうかに関わらず、fix と continue を実行できます。ただし、デバッグ情報なしでコンパイルされているファイルの場合には多少の機能制限があります。詳細はコンパイラの -g オプションの説明を参照してください。
共有オブジェクト (.so) ファイルの修正は可能ですが、その場合、そのファイルを特別なモードでオープンする必要があります。dlopen の呼び出しで、RTLD_NOW|RTLD_GLOBAL または RTLD_LAZY|RTLD_GLOBAL のどちらかを使用します。
fix と continue を使用すると、ソースを次の方法で変更できます。
関数の各行を追加、削除、変更する。
関数を追加または削除する。
大域変数および静的変数を追加または削除する。
関数が古いファイルから新しいファイルにマップされているときに dbx で問題が起きることがあります。ソースファイルの編集時にそのような問題ができるだけ起きないように、次のことを守ってください。
関数の名前を変更しない。
関数に渡す引数の型を追加、削除、または変更しない。
スタック上で現在アクティブな関数の局所変数の型を追加、削除、または変更しない。
テンプレートの宣言やテンプレートインスタンスを変更しない。C++ テンプレート関数定義の本体でのみ修正可能です。
進行中に上記の変更のいずれかを行う必要がある場合は、プログラムを構築しなおしてください。
ファイルを修正するには、次の手順に従ってください。
修正は無制限に行うことができますが、1 つの行でいくつかの修正を行った場合は、プログラムを作成しなおすことを考えてください。fix は、メモリー内のプログラムのイメージを変更しますが、ディスク上のイメージは変更しません。また修正を行うと、メモリーのイメージは、ディスク上のイメージと同期しなくなります。
fix は、実行可能ファイル内での変更ではなく、.o ファイルとメモリーイメージの変更だけを行います。プログラムのデバッグを終了したら、プログラムを作成しなおして、変更内容を実行可能ファイルにマージする必要があります。デバッグを終了すると、プログラムを作成しなおすように指示するメッセージが出されます。
continue を使用すると、実行を続けることができます。
プログラムの実行を再開する前に、次の条件に注意する必要があります。
すでに実行された関数に変更を加えた場合、その変更内容は次のことが起こるまで無効です。
プログラムが再び実行される
その関数が次に呼び出される
変数への単純な変更以上のことを修正した場合は、fix に続けて run を使用してください。run を使用すると、プログラムの再リンクが行われないため処理が速くなります。
呼び出されていない関数に変更を加えた場合、変更内容は、その関数が呼び出されたときに有効になります。
現在実行中の関数に変更を加えた場合、fix の影響は、変更内容が停止した関数のどの場所に関連しているかによって異なります。
変更内容がすでに実行されたコード内にある場合、そのコードは再実行されません。 現在の関数をスタックからポップし、変更した関数を呼び出した場所から実行を続けることによって、そのコードを実行してください。これには、コードをよく理解し、関数に取り消し不可能な副作用 (たとえばファイルのオープンなど) があるかどうかを判別しなくてはなりません。
変更内容がまだ実行されていないコードにある場合は、新しいコードが実行されます。
停止された関数ではなく、現在スタック上にある関数に変更を加えた場合、変更されたコードは、その関数の現在の呼び出しでは使用されません。停止した関数から戻ると、スタック上の古いバージョンの関数が実行されます。
この問題を解決する方法はいくつかあります。
変更された関数すべてがスタックから除去されるまで、スタックを pop する。各自のコードをよく理解して、悪影響がないことを確認する必要があります。
cont at linenum コマンドを使用して、別の行から実行を続ける。
データ構造を手作業で修正してから (assign コマンドを使用)、実行を続ける。
start を使用してプログラムを再び実行する。
スタック上の修正された関数にブレークポイントがある場合、このブレークポイントは、新しいバージョンの関数に移動します。古いバージョンが実行される場合、プログラムはこれらの関数で停止しません。
大域変数への変更は、pop コマンドでも fix コマンドでも取り消されません。大域変数に正しい値を手作業で再び割り当てるには、assign コマンドを使用してください。
以下の例は、修正継続機能を使用して簡単なバグを修正する方法を示しています。6 行目で NULL ポインタを逆参照しようとしたときに、セグメンテーションエラーが発生します。
(dbx) list 1,$ 1 #include<stdio.h> 2 3 char *from = "ships"; 4 void copy(char *to) 5 { 6 while ((*to++ = *from++) != '¥0'); 7 *to = '¥0'; 8 } 9 10 main() 11 { 12 char buf[100]; 13 14 copy(0); 15 printf("%s¥n", buf); 16 return 0; 17 } (dbx) run 実行中: testfix (プロセス id 11667) シグナル SEGV (フォルトのアドレスにマッピングしていません) 関数 copy 行番号 6 ファイル "testfix.c" 6 while ((*to++ = *from++) != '¥0');
edit でファイルの編集をします。14 行目を 0 ではなく buf をコピー (copy) するように変更し、fix を実行します。
(dbx) edit # エディタが起動します。 14 copy(0);# 変更前 14 copy(buf);# 変更後 # エディタを保存して終了します。 (dbx) fix 修正中 "testfix.c" ...... pc は "testfix.c":6 に移動しました copy で停止しました 行番号 6 ファイル "testfix.c" 6 while ((*to++ = *from++) != '¥0');
ここでプログラムを続行しても、NULL ポインタがスタックをプッシュしているため SEGV が返されます。pop コマンドを使用して、スタックフレームを 1 つ上がってください。
(dbx) pop main で停止しました 行番号 14 ファイル "testfix.c" 14 copy(buf);
ここでプログラムを続行すると、プログラムは実行されますが、大域変数 from がすでに増分されているため正しい値が出力されません。assign コマンドを使用して大域変数を復元し、続行してください。プログラムは次のように正しい値を表示します。assign コマンドを使用しないと、プログラムは ships と表示すべきところを hips と表示します。
(dbx) assign from = from-1 (dbx) cont ships
fix [options] [file1, file2,...]
-a |
変更されたすべてのファイルを再コンパイルします。 |
-f |
ソースが変更されていなくても、そのファイルを修正します。 |
-c |
コンパイル行を出力します (dbx 用に内部的に追加されたオプションも含まれます)。実際にはコンパイルは行われません。 |
-g |
再コンパイルのためのコマンド行で、-O フラグの代わりに -g フラグを使用します。 |
-n |
何の fix を行うかを表示します。再コンパイルを実行しないで、再コンパイルの対象になるソースファイルを調べたい場合は、このオプションを使用してください。 |
file1, file2,... |
修正 (fix) したい変更済みソースファイルを指定します。 |
-a 以外のオプションを指定し、ファイル名を指定しないで fix を呼び出すと、現在のソースファイルだけが再コンパイルの対象になります。
ソースファイルだけでなくヘッダーファイル (.h) も変更しなければならないことがあります。変更したヘッダーファイルが、それをインクルードするプログラム内のすべてのソースファイルからアクセスされるようにするには、そのヘッダーファイルをインクルードするすべてのソースファイルを fix コマンドに引数として渡す必要があります。ソースファイルを指定しないと、主なソースファイルだけが再コンパイルされ、変更後のヘッダーファイルはそのファイルにしかインクルードされません。プログラム内の他のソースファイルには、変更前のヘッダーファイルがインクルードされたままになります。
C++ テンプレート定義を直接修正することはできません。代わりにテンプレートインスタンスを使用してファイルを修正してください。-f オプションを使用すると、テンプレート定義ファイルが変更されなかった場合に、日付検査を上書きすることができます。dbx は、テンプレート定義 .o ファイルをデフォルトのレポジトリディレクトリ SunWS_cache で検索します。-ptr コンパイラスイッチは、dbx の fix コマンドではサポートされていません。
fix を呼び出すと、dbx はコンパイル時のソースファイルの現在の作業ディレクトリを探し、再コンパイルのためのコマンド行を実行します。コンパイル後にファイルシステム構造が変更されていると、dbx が正しいディレクトリを見つけられないことがあります。この問題を避けるためには、pathmap コマンドを使用します。このコマンドは、あるパス名を別のパス名にマッピングします。マッピングは、ソースパスとオブジェクトファイルパスに適用されます。