ユーザ・プログラムの中に誤りのある箇所を見つけると、 次に、 その明らかな誤りを訂正することで、 その後の実行が正しく行われるかどうかを知りたくなるでしょう。 プログラムの実行を変更するGDBの機能を使って実験することで、 その答を知ることができます。 例えば、 変数やメモリ上のある箇所に新しい値を格納したり、 ユーザ・プログラムにシグナルを送ったり、 ユーザ・プログラムを異なるアドレスで再起動したり、 関数が完全に終了する前に呼び出し元に戻ったりすることができます。
ある変数の値を変更するには、 代入式を評価します。 式を参照してください。 例えば、
print x=4
は、
変数x
に値4を格納してから、
その代入式の値
(すなわち4)
を表示します。
サポートされている言語の演算子の詳細情報については、
異なる言語の使用を参照してください。
代入の結果を表示させることに関心がなければ、
print
コマンドの代わりにset
コマンドを使用してください。
実際のところset
コマンドは、
式の値が表示されず、
値ヒストリ
(値ヒストリを参照)
にも入らないことを除けば、
print
コマンドと同等です。
式は、
その結果の入手のみを目的として評価されます。
set
コマンドの引数となる文字列の先頭の部分が、
set
コマンドのサブ・コマンドの名前と一致してしまうような場合には、
ただのset
コマンドではなくset variable
コマンドを使用してください。
このコマンドは、
サブ・コマンドを持たないという点を除けば、
set
コマンドと同等です。
例えば、
ユーザ・プログラムにwidth
という変数がある場合、
この変数に`set width=13'によって値を設定しようとするとエラーになります。
これは、
GDBがset width
というコマンドを持っているためです。
(gdb) whatis width type = double (gdb) p width $4 = 13 (gdb) set width=47 Invalid syntax in expression.
ここで不当な表現となっているのは、
もちろん`=47'の部分です。
プログラム内の変数width
に値を設定するには、
以下のようにしてください。
(gdb) set var width=47
GDBは、
代入時の暗黙の型変換をC言語よりも多くサポートしています。
整数値を自由にポインタ型変数に格納できますし、
その逆もできます。
また、
任意の構造体を、
それと同じサイズかより小さいサイズの構造体に変換することができます。
メモリ上の任意の箇所に値を格納するには、
`{...}'を使用して、
指定されたアドレスにおいて指定された型の値を生成してください
(式を参照)。
例えば、
{int}0x83040
はメモリ・アドレス0x83040
を整数値として参照します
(メモリ上においてある特定のサイズと表現を取るということを示唆しています)。
また、
set {int}0x83040 = 4
は、 そのメモリ・アドレスに値4を格納します。
通常ユーザ・プログラムを継続実行するには、
continue
コマンドを使用して、
停止した箇所から継続実行させます。
以下のコマンドを使用することで、
ユーザが選択したアドレスにおいて実行を継続させることができます。
jump linespec
jump
コマンドは、
カレントなスタック・フレーム、
スタック・ポインタ、
メモリ内の任意の箇所の内容、
プログラム・カウンタを除くレジスタの内容を変更しません。
linespecで指定される行が、
その時点において実行されている関数とは異なる関数の中にある場合、
それら2つの関数が異なるパターンの引数やローカル変数を持つ場合、
奇妙な結果が発生するかもしれません。
このため、
指定された行が、
その時点において実行されている関数の中にない場合、
jump
コマンドは実行の確認を求めてきます。
しかし、
ユーザがプログラムのマシン言語によるコードを熟知していたとしても、
奇妙な結果の発生することが予想されます。
jump *address
レジスタ$pc
に新しい値を設定することで、
jump
コマンドとほとんど同等の効果を実現することができます。
相違は、
レジスタ$pc
への値の設定は、
ユーザ・プログラムの実行を再開しないという点にあります。
ユーザが実行を継続するときに、
プログラムが実行を再開するアドレスが変更されるだけです。
例えば、
set $pc = 0x485
によって、
次にcontinue
コマンドやステップ実行を行うコマンドが実行されるとき、
ユーザ・プログラムが停止したアドレスにある命令ではなく、
アドレス0x485
にある命令から実行されることになります。
継続実行とステップ実行を参照してください。
jump
コマンドが最も一般的に使用されるのは、
既に実行されたプログラムのある部分を、
さらに多くのブレイクポイントを設定した状態で再度実行する場合でしょう。
これにより、
実行される処理の内容をさらに詳しく調べることができます。
signal signal
signal 2
とsignal SIGINT
はともに割り込みシグナルを通知する方法になります。
一方、
signalが0であれば、
シグナルを通知することなく実行を継続します。
ユーザ・プログラムがシグナルのために停止させられ、
continue
コマンドによって実行を再開すると通常はそのシグナルを検知してしまうような場合に便利です。
`signal 0'を実行すると、
プログラムはシグナルを受信することなく実行を再開します。
signal
を実行した後、
RETキーを押しても、
繰り返し実行は行われません。
signal
コマンドを実行することは、
シェルからkill
ユーティリティを実行するのと同じではありません。
kill
によってシグナルを送ると、
GDBはシグナル処理テーブルによって何をするべきかを決定します
(シグナルを参照)。
一方、
signal
コマンドは、
ユーザ・プログラムに直接シグナルを渡します。
return
return expression
return
コマンドによって、
関数呼び出しの実行をキャンセルすることができます。
式expressionを引数に指定すると、
その値が関数の戻り値として使用されます。
ユーザがreturn
を実行すると、
GDBは選択されているスタック・フレーム
(および、
その内部のすべてのフレーム)
を破棄します。
破棄されたフレームは、
実行を完結する前に復帰したのだと考えればよいでしょう。
戻り値を指定したいのであれば、
その値をreturn
への引数として渡してください。
このコマンドは、
選択されているスタック・フレーム
(フレームの選択を参照)、
およびその内部のすべてのフレームをポップして、
もともと選択されていたフレームを呼び出したフレームを、
最も内側のフレームにします。
つまり、
そのフレームが選択されることになります。
指定された値は、
関数から戻り値を返すのに使用されるレジスタに格納されます。
return
コマンドは実行を再開しません。
関数から復帰した直後の状態でプログラムが停止したままにします。
これに対して、
finish
コマンド
(継続実行とステップ実行を参照)は、
選択されているスタック・フレームが自然に復帰するまで、
実行を再開、
継続します。
call expr
void
型の戻り値を表示することなく、
式exprを評価します。
ユーザ・プログラムの中からある関数を呼び出したいが、
void型の戻り値を出力させたくない場合、
このprint
コマンドの変種を使用することができます。
戻り値がvoid
型でない場合には、
それは表示され、
値ヒストリに保存されます。
ユーザの制御する新しい変数call_scratch_addressが、
GDBがターゲット中の関数を呼び出すときに使用するスクラッチ領域を指定します。
通常はスクラッチ領域をスタック上に置きますが、
この方法は命令空間とデータ空間とが異なるシステム上では機能しないため、
これが必要になります。
デフォルトでは、
GDBはユーザ・プログラムの実行コードを含むファイル
(あるいは、
コア・ファイル)
を書き込み不可の状態でオープンします。
これにより、
マシン・コードを誤って変更してしまうことを防ぐことができます。
しかし、
ユーザ・プログラムのバイナリに意図的にパッチを適用することもできなくなってしまいます。
バイナリにパッチを適用したいのであれば、
set write
コマンドによって明示的にそれを指定することができます。
例えば、
内部的なデバッグ・フラグを立てたり、
緊急の修正を行いたいということがあるでしょう。
set write on
set write off
set write
の設定を変更後、
その変更を反映させるためには、
(exec-file
コマンド
、
core-file
コマンド
を使用して)、
そのファイルを再ロードしなければなりません。
show write