10. 実行内容の変更

 あなたが、プログラム内のエラーを見つけたと思ったならば、実行の停止時に 正しい結果を設定することで、見つかったエラーを修整して、正しい実行結果を 見てみたいと思うはずです。あなたは、GDB のプログラムの実行内容変更機能に よって、実験の結果の答えを知ることができます。

 例えば、あなたは、変数やメモリに新しい値を設定したり、プログラムに シグナルを与えたり、異なったアドレスでリスタートしたり、関数のコール 元に対して早めにリターンする、などとといったことが可能です。


10.1 変数への代入

 変数の値を変更するには、式による代入を評価させます。“8.1 式”を参照して下さい。 例えば、
print x=4
は、変数 x に対して値4を格納し、代入後の式の値 (この場合4) を 表示します。

 インクリメント用のオペレータである `++'`--'、そして 複合オペレータの `+='`<<=' といった、C言語の全ての代入用 オペレータがサポートされています。

 もし、あなたが代入後の値を見ることに興味がない場合は、 `print' コマンドのかわりに `set' コマンドを使います。 `set' は、式の値が表示されず、また、変数履歴 (“8.7 変数値の履歴”をご覧下さい) にも記録が残らないことを除けば、`print' コマンドと同じです。 副作用としては、式が評価されるだけです。

 `set' コマンドに渡す引数の文字列の最初の部分が `set' の サブコマンドと一致する場合、`set variable' コマンドを使用する 必要があることに注意して下さい。このコマンドは、サブコマンドと 一致する変数を `set' で設定するためのものです。

 GDB は、C言語よりも、代入に対してはより絶対的な変換を許可しています; あなたは、整数値を自由にポインタ値などに設定でき、任意の構造体は、 同じ長さかそれより短い、他の構造体に変換することができます。

 値をメモリ内の気まぐれな位置に設定したい場合、`{...}' の 構造を使うことによって、指定されたアドレスに指定された型の値を 生成することができます(“8.1 式”をご覧下さい)。 例えば、{int}0x83040 はメモリ位置 0x83040 を整数値とみなして 参照します(これは、正確なサイズとメモリ内の正確な表現を意味しています)。 また、

set {int}0x83040 = 4
は、そのメモリ位置に値4を設定します。


10.2 異なったアドレスへの処理の継続

 プログラムの実行を継続する場合、普通、`cont' コマンドによって停止 した位置から継続します。あなたは、このアドレスを使う代わりに、次に 説明するコマンドを使って、自分で選んだアドレスから処理を継続させる ことができます:
jump linenum
linenum から実行を再開します。そこにブレークポイントが設定されて いた場合、実行はただちに停止されます。

`jump' コマンドはカレントのスタックフレーム、スタックポインタ、 又はプログラムカウンタ以外の他のレジスタやメモリ位置を変更しません。 もし、linenum の行がカレントで実行されているものとは異なった 関数の場合、2つの関数が異なったパターンの引数やローカル変数を要求 したならば、その結果は思いがけないものとなります。 そのため、指定された行がカレントで実行中の関数ではない場合、`jump' コマンドは確認を求めてきます。しかしながら、プログラムのコードと してのマシン語を注意深く勉強したという土台があれば、思いがけない 結果でさえ予想することができます。

jump *address
address 上のインストラクションから実行を再開します。
 あなたは、レジスタ $pc に新しい値を設定することで、 jump コマンドと同様な効果を得ることができます。この方法で 唯一異なる点は、動作中のプログラムをスタートさせないということです; これは、処理を継続する時のアドレスを変更させるだけです。例えば、
set $pc = 0x485
は、次に `cont' コマンドを実行したり、ステップ実行コマンドを 処理したりする時のアドレスを、プログラムが停止したアドレスの かわりに、0x485 にします。“5.4 ステップ実行”を参照して下さい。

 `jump' コマンドを最もよく利用するケースとしては、next に よって関数コールにまたがって停止し、リターン値が正しくないことが わかったといったような場合です。もし、全ての関連するデータが関数 コール前に正しいならば、恐らく、エラーはリターンしてきた直前の関数に あるはずです。

 一般的にあなたの次のステップは、プログラムを再実行し、この関数 コールを行い、間違った部分をステップごとに実行して見つけることに なるでしょう。しかし、これは時間の無駄です。もし、その関数が重大な 副作用を持っていないのなら、あなたは関数コールの直前から実行し直し、 その中をステップごとに調べていくことで、同一の情報を得られます。 このことを実現するには、まず、ブレークポイントをその関数に設定し; そこで、`jump' コマンドを使って、その関数コールを含む行へと 処理を継続させることになります。


10.3 プログラムへのシグナルの送信

signal signalnum
プログラムが停止した箇所から処理を継続しますが、signalnum で 表されるシグナルを即座に送ります。

もう一つのケースとして、signalnum がゼロの場合、シグナルを 与えずに処理を継続します。これは、プログラムがシグナルのせいで停止し、 普通、`cont' コマンドによって継続した場合はシグナルを見てしまう ような場合に便利です; `signal 0' はシグナルなしの処理の継続を行います。


10.4 関数からのリターン

 あなたは、`return' コマンドを使うことによって、関数の実行を キャンセルすることができます。このコマンドには、 選択されたスタックフレーム (と、その中の全てのフレーム) を捨て、 その関数のコール元に制御を戻すという効果があります。 あなたは、このことを早急なリターンによるフレームの放棄と考える ことができます。

 まず最初に、リターンしたいスタックフレームを選択します(“6.3 フレームの選択”をご覧下さい)。 そこで、`return' コマンドを入力して下さい。もし、あなたが リターン時の値を指定したい場合は、引数としてそれを与えます。

 このことにより、選択されたスタックフレーム (と、その内部にある その他のフレーム) は破棄され、残ったフレームのうち、最深部のフレームの コール元へと戻ります。次からは、このフレームが選択されたことになります。 指定された値はレジスタに設定され、リターン時の関数値として使用されます。

 `return' コマンドは、実行を再開しません; このコマンドは、関数がリターンした直後の状態として、プログラムを 停止させたままです。このことを、`finish' コマンド (“5.4 ステップ実行”をご覧下さい) と比較してみて下さい。 これは、選択されたスタックフレームから自然にリターンするまで 実行を継続します。


目次に戻る