[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]  


実行処理の変更

ユーザ・プログラムの中に誤りのある箇所を見つけると、 その明らかな誤りを訂正することで、 その後の実行が正しく行われるかどうかを知りたくなるでしょう。 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
linespecで指定される行において、 実行を再開します。 その行にブレイクポイントが設定されている場合には、 実行は再びすぐに停止します。 linespecの形式については、 ソース行の表示 を参照してください。 一般的な慣例として、 jumpコマンドは、 tbreakコマンドと組み合わせて使用されます。 ブレイクポイントの設定 を参照してください。 jumpコマンドは、 カレントなスタック・フレーム、 スタック・ポインタ、 メモリ内の任意の箇所の内容、 プログラム・カウンタを除くレジスタの内容を変更しません。 linespecで指定される行が、 現在実行されている関数とは異なる関数の中にある場合、 それら2つの関数が異なるパターンの引数やローカル変数を期待していると、 奇妙な結果が発生するかもしれません。 このため、 指定された行が、 現在実行されている関数の中にない場合、 jumpコマンドは実行の確認を求めてきます。 しかし、 ユーザがプログラムのマシン言語によるコードを熟知していたとしても、 奇妙な結果の発生することが予想されます。
jump *address
addressで指定されるアドレスにある命令から実行を再開します。

多くのシステムでは、 レジスタ$pcに新しい値を設定することで、 jumpコマンドとほとんど同等の効果を実現することができます。 両者の違いは、 レジスタ$pcに値を設定しただけでは、 ユーザ・プログラムの実行は再開されないという点にあります。 ユーザが実行を継続するときに、 プログラムが実行を再開するであろうアドレスが変更されるだけです。 例えば、

set $pc = 0x485

を実行すると、 次にcontinueコマンドやステップ実行を行うコマンドが実行されるとき、 ユーザ・プログラムが停止したアドレスにある命令ではなく、 アドレス0x485にある命令から実行されることになります。 継続実行とステップ実行 を参照してください。

jumpコマンドが最も一般的に使用されるのは、 既に実行されたプログラム部分を、 さらに多くのブレイクポイントを設定した状態で再実行する場合でしょう。 これにより、 実行される処理の内容をさらに詳しく調べることができます。

ユーザ・プログラムへのシグナルの通知

signal signal
実行を停止した箇所からユーザ・プログラムを再開させますが、 すぐにsignalで指定されるシグナルを通知します。 signalには、 シグナルの名前または番号を指定できます。 例えば、 多くのシステムにおいて、 signal 2signal 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 on'を指定すると、 GDBは実行ファイルやコア・ファイルを、 読み取り、 書き込みともに可能な状態でオープンします。 `set write off' (デフォルト) を指定すると、 GDBはこれらのファイルを読み取りしかできない状態でオープンします。 既にファイルをロード済みの場合、 set writeの設定を変更後、 その変更を反映させるためには、 (exec-fileコマンド、 core-fileコマンド を使用して)、 そのファイルを再ロードしなければなりません。
show write
実行ファイル 、コア・ファイルが、 読み取りだけではなく書き込みもできる状態でオープンされる設定になっているか否かを表示します。


[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]