ユーザ・プログラムの中に誤りのある箇所を見つけると、 その明らかな誤りを訂正することで、 その後の実行が正しく行われるかどうかを知りたくなるでしょう。 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
set
コマンドは、
プログラムの変数名と衝突する可能性のあるサブコマンドを多く持っているので、
ただのset
コマンドではなく、
set variable
コマンドを使用する方が良いでしょう。
例えば、
プログラムの中にg
という名前の変数がある場合に、
単に`set g=4'として新しい値をセットしようとすると、
問題が発生します。
これは、
GDBがset gnutarget
というコマンドを持っていて、
その省略形がset g
であるからです。
(gdb) whatis g type = double (gdb) p g $1 = 1 (gdb) set g=4 (gdb) p g $2 = 1 (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/smith/cc_progs/a.out "/home/smith/cc_progs/a.out": can't open to read symbols: Invalid bfd target. (gdb) show g The current BFD target is "=4".
プログラム変数g
の値は変わらず、
gnutarget
にこっそりと不正な値をセットしてしまいました。
変数g
に値をセットするためには、
以下のようにします。
(gdb) set var g=4
GDBは、 代入時の暗黙の型変換をC言語よりも多くサポートしています。 整数値を自由にポインタ型変数に格納できますし、 その逆もできます。 また、 任意の構造体を、 同じサイズの別の構造体、 または、 より小さいサイズの別の構造体に変換することができます。
メモリ上の任意の箇所に値を格納するには、
指定されたアドレスにおいて指定された型の値を生成するために、
`{...}'を使用します
(式参照)。
例えば{int}0x83040
は、
メモリ・アドレス0x83040
を整数値として参照します
(メモリ上における、
ある特定のサイズと表現を示唆しています)。
また、
set {int}0x83040 = 4
は、 そのメモリ・アドレスに値4を格納します。
通常、
ユーザ・プログラムを継続実行するには、
continue
コマンドを使用して、
停止した箇所から継続実行させます。
以下のコマンドを使用することで、
ユーザが選択したアドレスにおいて実行を継続させることができます。
jump linespec
jump
コマンドは、
tbreak
コマンドと組み合わせて使用されます。
ブレイクポイントの設定
を参照してください。
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
型でない戻り値は表示され、
値履歴に保存されます。
A29Kでは、
ユーザが制御する変数call_scratch_address
によって、
GDBがデバッグ対象の関数を呼び出すときに使用するスクラッチ領域が指定されます。
通常はスクラッチ領域をスタック上に置きますが、
この方法は命令空間とデータ空間を別々に持つシステム上では機能しないため、
これが必要になります。
デフォルトでは、 GDBはユーザ・プログラムの実行コードを持つファイル (あるいは、 コア・ファイル) を読み取りしかできない状態でオープンします。 これにより、 マシン・コードを誤って変更してしまうことを防ぐことができます。 しかし、 ユーザ・プログラムのバイナリに意図的にパッチを適用することもできなくなってしまいます。
バイナリにパッチを適用したいのであれば、
set write
コマンドによって明示的にそのことを指定することができます。
例えば、
内部的なデバッグ・フラグを立てたり、
緊急の修正を行いたいということがあるでしょう。
set write on
set write off
set write
の設定を変更後、
その変更を反映させるためには、
(exec-file
コマンド、
core-file
コマンド
を使用して)、
そのファイルを再ロードしなければなりません。
show write