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


デバッグ・ターゲットの指定

ターゲットとは、 ユーザ・プログラムが持つ実行環境を指します。

多くの場合、 GDBはユーザ・プログラムと同一のホスト環境上で実行されます。 この場合には、 fileコマンドやcoreコマンドを実行すると、 その副作用としてデバッグ・ターゲットが指定されます。 例えば、 物理的に離れた位置にあるホスト・マシン上でGDBを実行したい場合や、 シリアル・ポート経由でスタンドアロン・システムを制御したい場合、 または、 TCP/IP接続を利用してリアルタイム・システムを制御したい場合などのように、 より多くの柔軟性が必要とされる場合、 targetコマンドを使うことによって、 configureによって設定されたGDBのターゲットの種類の中から1つを指定することができます (ターゲットを管理するコマンド参照)。

アクティブ・ターゲット

ターゲットには3つのクラスがあります。 プロセス、コア・ファイル、 そして、 実行ファイルです。 GDBは同時に、 1クラスにつき1つ、 全体で最高で3つまでアクティブなターゲットを持つことができます。 これにより、 (例えば) コア・ファイルに対して行ったデバッグ作業を破棄することなく、 プロセスを起動してその動作を調べることができます。

例えば、 `gdb a.out'を実行すると、 実行ファイルa.outが唯一のアクティブなターゲットになります。 コア・ファイル (おそらくは、 前回実行したときにクラッシュしてコア・ダンプしたもの) を併せて指定すると、 GDBは2つのターゲットを持ち、 メモリ・アドレスを知る必要がある場合には、 それを知るために2つのターゲットを並行して使用します。 この場合、 まずコア・ファイルを参照し、 次に実行ファイルを参照します。 (典型的には、 これら2つのクラスのターゲットは相互に補完的です。 というのも、 コア・ファイルには、 プログラムが持っている変数などの読み書き可能なメモリ域の内容とマシン・ステータスだけがあり、 実行ファイルには、 プログラムのテキストと初期化されたデータだけがあるからです)。

runコマンドを実行すると、 ユーザの実行ファイルはアクティブなプロセス・ターゲットにもなります。 プロセス・ターゲットがアクティブな間は、 メモリ・アドレスを要求するすべてのGDBコマンドは、 プロセス・ターゲットを参照します。 アクティブなコア・ファイル・ターゲットや実行ファイル・ターゲットの中のアドレスは、 プロセス・ターゲットがアクティブな間は、 隠された状態になります。

新しいコア・ファイル・ターゲットや実行ファイル・ターゲットを選択するには、 core-fileコマンドやexec-fileコマンドを使用します (ファイルを指定するコマンド参照)。 既に実行中のプロセスをターゲットとして指定するには、 attachコマンドを使用します (既に実行中のプロセスのデバッグ参照)。

ターゲットを管理するコマンド

target type parameters
GDBのホスト環境をターゲット・マシン またはターゲット・プロセスに接続します。 ターゲットとは、 典型的には、 デバッグ機能と通信するためのプロトコルを指します。 引数typeによって、 ターゲット・マシンの種類またはプロトコルを指定します。 parametersはターゲット・プロトコルによって解釈されるものですが、 典型的には、 接続すべきデバイス名やホスト名、 プロセス番号、 ボーレートなどが含まれます。 targetコマンドを実行した後にRETキーを押しても、 targetコマンドは再実行されません。
help target
利用可能なすべてのターゲットの名前を表示します。 現在選択されているターゲットを表示させるには、 info targetコマンドまたはinfo filesコマンドを使用します (ファイルを指定するコマンド参照)。
help target name
ある特定のターゲットに関する説明を表示します。 選択時に必要となるパラメータも表示されます。
set gnutarget args
GDBは、 自分で持っているライブラリBFDを使用してユーザ・ファイルを読み取ります。 GDBは、 実行ファイルコア・ファイル.oファイルのどれを自分が読み取っているのかを知っています。 しかし、 set gnutargetコマンドを使用して、 ファイルのフォーマットを指定することもできます。 ほとんどのtargetコマンドとは異なり、 gnutargetにおけるtargetは、 マシンではなくプログラムです。

注意:set gnutargetでファイル・フォーマットを指定するには、 実際のBFD名を知っている必要があります。

ファイルを指定するコマンド を参照してください。
show gnutarget
gnutargetがどのようなファイル・フォーマットを読むよう設定されているかを表示させるには、 show gnutargetコマンドを使用します。 gnutargetを設定していない場合、 個々のファイルのフォーマットをGDBが自動的に決定します。 この場合、 show gnutargetを実行すると `The current BDF target is "auto"' と表示されます。

以下に、 一般的なターゲットをいくつか示します (GDBの構成によって、 利用可能であったり利用不可であったりします)。

target exec program
実行ファイルです。 `target exec program'`exec-file program'と同じです。
target core filename
コア・ダンプ・ファイルです。 `target core filename'`core-file filename'と同じです。
target remote dev
GDB固有のプロトコルによる、 リモートのシリアル・ターゲットです。 引数devによって、 接続を確立するために使用するシリアル装置 (例えば、 `/dev/ttya') を指定します。 リモート・デバッギング を参照してください。 target remoteは、 loadコマンドをサポートしています。 これは、 スタブをターゲット・システム上に持っていく方法が別にあり、 かつ、 ダウンロードが実行されたときに破壊されないようなメモリ域にそれを置くことができる場合にのみ役に立ちます。
target sim
組み込みCPUシミュレータです。 GDBには、 ほとんどのアーキテクチャ用のシミュレータが含まれています。 一般には、
        target sim
        load
        run
でうまくいきます。 しかし、 シミュレータによっては特定のメモリ・マップ、 デバイス・ドライバ、 基本的なI/Oを提供するものもありますが、 それらが利用可能であることを前提することはできません。 プロセッサ固有のシミュレータの詳細に関しては、 組み込みプロセッサ の該当するセクションを参照してください。

構成によっては、 以下のターゲットも含まれている可能性があります。

target nrom dev
NetROM ROMエミュレータです。 このターゲットは、 ダウンロードのみサポートしています。

configureによるGDBの構成によって、 利用可能なターゲットも異なるものになります。 configureの構成次第で、 ターゲットの数は多くなったり少なくなったりします。

多くのリモート・ターゲットでは、 接続に成功すると、 実行プログラムのコードをダウンロードすることが必要となります。

load filename
configureの実行時にGDBに組み込まれたリモート・デバッグ機能によっては、 loadコマンドが使用可能になります。 これが利用可能な場合、 実行ファイルfilenameが (例えば、 ダウンロードやダイナミック・リンクによって) リモート・システム上でデバッグできるようになることを意味します。 また、 loadコマンドはadd-symbol-fileコマンドと同様、 ファイルfilenameのシンボル・テーブルをGDB内に記録します。 GDBがloadコマンドを提供していない場合、 それを実行しようとすると 「You can't do that when your target is ...」 というエラー・メッセージが表示されます。 実行ファイルの中で指定されたアドレスに、 ファイルはロードされます。 オブジェクト・ファイルのフォーマットによっては、 プログラムをリンクするときに、 ファイルをロードするアドレスを指定できるものもあります。 これ以外のフォーマット (例えば、 a.out) では、 オブジェクト・ファイルのフォーマットによって固定的にアドレスが指定されます。 loadコマンドを実行後にRETキーを押しても、 コマンドは再実行されません。

ターゲットのバイト・オーダの選択

MIPS、 PowerPC、 Hitachi SHなどのプロセッサは、 ビッグ・エンディアン、 リトル・エンディアンのどちらのバイト・オーダでも実行することができます。 通常は、 実行ファイルまたはシンボルの中に、 エンディアン種別を指定するビットがあるので、 どちらを使用するかを気にする必要はありません。 しかし、 GDBの認識しているプロセッサのエンディアン種別を手作業で調整することができれば、 便利なこともあるでしょう。

set endian big
GDBに対して、 ターゲットはビッグ・エンディアンであると想定するよう指示します。
set endian little
GDBに対して、 ターゲットはリトル・エンディアンであると想定するよう指示します。
set endian auto
GDBに対して、 実行ファイルに関連付けされているバイト・オーダを使用するよう指示します。
show endian
GDBが認識している、 ターゲットの現在のバイト・オーダ種別を表示します。

これらのコマンドは、 ホスト上でのシンボリック・データの解釈を調整するだけであり、 ターゲット・システムに対しては全く何の影響も持たないということに注意してください。

リモート・デバッギング

通常の方法でGDBを実行することのできないマシン上で実行されているプログラムをデバッグするには、 リモート・デバッグ機能を使うのが便利です。 例えば、 オペレーティング・システムのカーネルのデバッグや、 フル機能を持つデバッガを実行するのに十分な機能を持つ汎用的なオペレーティング・システムを持たない小規模なシステムでのデバッグでは、 ユーザはリモート・デバッグ機能を使うことになるかもしれません。

GDBは、 その構成によっては、 特別なシリアル・インターフェイスやTCP/IPインターフェイスを持ち、 これを特定のデバッグ・ターゲット用に使用することができます。 さらに、 GDBには汎用的なシリアル・プロトコルが組み込まれており (GDB固有のもので、 特定のターゲット・システムに固有なものではありません)、 リモート・スタブを作成すれば、 これを使用することができます。 リモート・スタブとは、 GDBと通信するためにリモート・システム上で動作するコードです。

GDBの構成によっては、 他のリモート・ターゲットが利用可能な場合もあります。 利用可能なリモート・ターゲットを一覧表示させるには、 help targetコマンドを使用します。

GDBリモート・シリアル・プロトコル

他のマシン上で実行中のプログラムをデバッグするには (ターゲット・マシンをデバッグするには)、 そのプログラムを単独で実行するために通常必要となる事前条件をすべて整える必要があります。 例えば、 Cのプログラムの場合、

  1. Cの実行環境をセットアップするためのスタートアップ・ルーチンが必要です。 これは通常`crt0'のような名前を持っています。 スタートアップ・ルーチンは、 ハードウェアの供給元から提供されることもありますし、 ユーザが自分で書かなければならないこともあります。
  2. ユーザ・プログラムからのサブルーチン呼び出しをサポートするために、 入出力の管理などを行うCのサブルーチン・ライブラリが必要になるかもしれません。
  3. ユーザ・プログラムを他のマシンに持っていく手段、 例えばダウンロード・プログラムが必要です。 これはハードウェアの供給元から提供されることが多いのですが、 ハードウェアのドキュメントをもとにユーザが自分で作成しなければならないこともあります。

次に、 ユーザ・プログラムがシリアル・ポートを使って、 GDBを実行中のマシン (ホスト・マシン) と通信できるように準備します。 一般的には、以下のような形になります。

ホスト上では:
GDBは既にこのプロトコルの使い方を理解しています。 他の設定がすべて終了した後、 単に`target remote'コマンドを使用するだけです (デバッグ・ターゲットの指定参照)。
ターゲット上では:
ユーザ・プログラムに、 GDBリモート・シリアル・プロトコルを実装した特別なサブルーチンを いくつかリンクする必要があります。 これらのサブルーチンを含むファイルは、 デバッグ・スタブと呼ばれます。 特定のリモート・ターゲットでは、 ユーザ・プログラムにスタブをリンクする代わりに、 gdbserverという補助プログラムを使うこともできます。 詳細については、 gdbserverプログラムの使用 を参照してください。

デバッグ・スタブはリモート・マシンのアーキテクチャに固有のものです。 例えば、 SPARCボード上のプログラムをデバッグするには`sparc-stub.c'を使います。

以下に実際に使えるスタブを列挙します。 これらは、 GDBとともに配布されています。

i386-stub.c
Intel 386アーキテクチャ、 およびその互換アーキテクチャ用です。
m68k-stub.c
Motorola 680x0アーキテクチャ用です。
sh-stub.c
日立SHアーキテクチャ用です。
sparc-stub.c
SPARCアーキテクチャ用です。
sparcl-stub.c
富士通SPARCLITEアーキテクチャ用です。

GDBとともに配布されるREADMEファイルには、 新しく追加された他のスタブのことが記されているかもしれません。

スタブの提供する機能

各アーキテクチャ用のデバッグ・スタブは、 3つのサブルーチンを提供します。

set_debug_traps
このルーチンは、 ユーザ・プログラムが停止したときにhandle_exceptionが実行されるよう設定します。 ユーザ・プログラムは、 その先頭付近でこのサブルーチンを明示的に呼び出さなければなりません。
handle_exception
これが中心的な仕事をする部分ですが、 ユーザ・プログラムはこれを明示的には呼び出しません。 セットアップ・コードによって、 トラップが発生したときに handle_exceptionが実行されるよう設定されます。 ユーザ・プログラムが実行中に (例えば、ブレイクポイントで) 停止すると、 handle_exceptionが制御権を獲得し、 ホスト・マシン上のGDBとの通信を行います。 これが、 通信プロトコルが実装されている部分です。 handle_exceptionは、 ターゲット・マシン上でGDBの代理として機能します。 それはまず、 ユーザ・プログラムの状態に関する情報を要約して送ることから始めます。 次に、 GDBが必要とする情報を入手して転送する処理を継続します。 これは、 ユーザ・プログラムの実行を再開させるようなGDBコマンドが実行されるまで続きます。 そのようなコマンドが実行されると、 handle_exceptionは、 制御をターゲット・マシン上のユーザ・コードに戻します。
breakpoint
ユーザ・プログラムにブレイクポイントを持たせるには、 この補助的なサブルーチンを使います。 特定の状況においては、 これがGDBが制御を獲得する唯一の方法です。 例えば、 ユーザのターゲット・マシンに割り込みを発生させるボタンのようなものがあれば、 このサブルーチンを呼び出す必要はありません。 割り込みボタンを押すことで、 制御はhandle_exceptionに、 つまり事実上GDBに渡されます。 マシンによっては、 シリアル・ポートから文字を受け取るだけでトラップが発生することもあります。 このような場合には、 ユーザ・プログラム自身からbreakpointを呼び出す必要はなく、 ホストのGDBセッションから`target remote'を実行するだけで制御を得ることができます。 これらのどのケースにも該当しない場合、 あるいは、 デバッグ・セッションの開始箇所としてあらかじめ決めてあるところでユーザ・プログラムが停止することを 単に確実にしたいのであれば、 breakpointを呼び出してください。

スタブに対する必須作業

GDBとともに配布されるデバッグ用スタブは、 特定のチップのアーキテクチャ用にセットアップされたものですが、 デバッグのターゲット・マシンに関してそれ以外の情報は持っていません。

まず最初に、 どのようにしてシリアル・ポートと通信するかをスタブに教えてやる必要があります。

int getDebugChar()
シリアル・ポートから単一文字を読み取るサブルーチンとしてこれを書きます。 これは、 ターゲット・システム上の getcharと同一かもしれません。 これら2つを区別したい場合を考慮して、 異なる名前が使われています。
void putDebugChar(int)
シリアル・ポートに単一文字を書き込むサブルーチンとしてこれを書きます。 これは、 ターゲット・システム上の putcharと同一かもしれません。 これら2つを区別したい場合を考慮して、 異なる名前が使われています。

実行中のユーザ・プログラムをGDBが停止できるようにしたいのであれば、 割り込み駆動型のシリアル・ドライバを使用して、 ^C (control-C文字、 すなわち`\003') を受信したときに停止するよう設定する必要があります。 GDBは^Cを使って、 リモート・システムに対して停止するよう通知します。

デバッグ・ターゲットが適切なステータス情報をGDBに対して返せるようにするためには、 おそらく標準のスタブを変更する必要があるでしょう。 美しい方法ではありませんが、 とりあえず手っ取り早くこれを実現する方法は、 ブレイクポイント命令を実行することです (この方法が「美しくない」のは、 GDBがSIGINTではなくSIGTRAPを報告してくる点にあります)。

ユーザが提供する必要のあるルーチンには、 ほかに以下のようなものがあります。

void exceptionHandler (int exception_number, void *exception_address)
例外処理テーブルにexception_addressを組み込むよう、 この関数を書きます。 ユーザがこれを提供しなければならないのは、 スタブにはターゲット・システム上の例外処理テーブルがどのようなものになるかを知る手段がないからです (例えば、 プロセッサのテーブルはROM上にあり、 その中のエントリがRAM上のテーブルを指す、 という形になっているかもしれません)。 exception_number は例外番号で、 これは変更される必要があります。 例外番号の意味は、 アーキテクチャに依存します (例えば、 0による除算、 境界を無視したメモリ・アクセス等は、 異なる番号によって表わされるかもしれません)。 この例外が発生したとき、 制御は直接exception_addressに渡されなければならず、 また、 プロセッサの状態 (スタック、レジスタなど) はプロセッサ例外が発生したときの状態と同じでなければなりません。 したがって、 exception_addressに到達するのにジャンプ命令を使用したいのであれば、 サブルーチン・ジャンプではなく、 ただのジャンプ命令を使わなければなりません。 386では、 ハンドラが実行されているときに割り込みがマスクされるよう、 exception_addressは割り込みゲートとして組み込まれる必要があります。 そのゲートは特権レベル0 (最も高いレベル) でなければなりません。 SPARC用のスタブや68k用のスタブは、 exceptionHandlerの助けを借りなくても自分で割り込みをマスクすることができます。
void flush_i_cache()
(SPARC、 SPARCLITEのみ) ターゲット・マシンに命令キャッシュがある場合、 それをフラッシュするようこのサブルーチンを書きます。 命令キャッシュがない場合には、 このサブルーチンは何もしないものになるかもしれません。 命令キャッシュを持つターゲット・マシンを対象としている場合、 GDBは、 ユーザ・プログラムが安定した状態にあることをこの関数が保証してくれることを必要とします。

また、次のライブラリ・ルーチンが使用可能であることを確かめなければなりません。

void *memset(void *, int, int)
あるメモリ領域に既知の値を設定する標準ライブラリ関数memsetです。 フリーのlibc.aを持っていれば、 そこにmemsetがあります。 フリーのlibc.aがなければ、 memsetをハードウェアの供給元から入手するか、 自分で作成する必要があります。

GNU Cコンパイラを使っていないのであれば、 他の標準ライブラリ・サブルーチンも必要になるかもしれません。 これは、 スタブによっても異なりますが、 一般的にスタブは、 gccがインライン・コードとして生成する共通ライブラリ・サブルーチンを使用する可能性があります。

ここまでのまとめ

要約すると、 ユーザ・プログラムをデバッグする準備が整った後、 以下の手順に従わなければなりません。

  1. 下位レベルのサポート・ルーチンがあることを確認します (スタブに対する必須作業参照)。
    getDebugChar, putDebugChar,
    flush_i_cache, memset, exceptionHandler.
    
  2. ユーザ・プログラムの先頭付近に以下の行を挿入します。
    set_debug_traps();
    breakpoint();
    
  3. 680x0のスタブに限り、 exceptionHookという変数を提供する必要があります。 通常は、 以下のように使います。
    void (*exceptionHook)() = 0;
    
    しかし、 set_debug_trapsが呼び出される前に、 ユーザ・プログラム内のある関数を指すようこの変数を設定すると、 トラップ (例えば、 バス・エラー) で停止した後にGDBが処理を継続実行するときに、 その関数が呼び出されます。 exceptionHookによって指される関数は、 1つの引数付きで呼び出されます。 それは、 int型の例外番号です。
  4. ユーザ・プログラム、 ターゲット・アーキテクチャ用のGDBデバッグ・スタブ、 サポート・サブルーチンをコンパイルしリンクします。
  5. ターゲット・マシンとGDBホストとの間がシリアル接続されていることを確認します。 また、 ホスト上のシリアル・ポートの名前を調べます。
  6. ターゲット・マシンにユーザ・プログラムをダウンロードし (あるいは、 製造元の提供する手段によってターゲット・マシンにユーザ・プログラムを持っていき)、 起動します。
  7. リモート・デバッグを開始するには、 ホスト・マシン上でGDBを実行し、 リモート・マシン上で実行中のプログラムを実行ファイルとして指定します。 これにより、 ユーザ・プログラムのシンボルとテキスト域の内容を見つける方法がGDBに通知されます。
  8. 次にtarget remoteコマンドを使って通信を確立します。 引数には、 シリアル回線に接続された装置名または (通常はターゲットと接続されたシリアル回線を持つ端末サーバの) TCPポートを指定することで、 ターゲット・マシンとの通信方法を指定します。 例えば、 `/dev/ttyb'という名前の装置に接続されているシリアル回線を使うには、
    target remote /dev/ttyb
    
    とします。 TCP接続を使うには、 host:portという形式の引数を使用します。 例えば、 manyfarmsという名前の端末サーバのポート2828に接続するには、
    target remote manyfarms:2828
    
    とします。

ここまでくると、 データの値の調査、 変更、 リモート・プログラムのステップ実行、 継続実行に通常使用するすべてのコマンドを使用することができます。

リモート・プログラムの実行を再開し、 デバッグするのをやめるには、 detachコマンドを使います。

GDBがリモート・プログラムを待っているときにはいつでも、 割り込み文字 (多くの場合 C-C) を入力すると、 GDBはそのプログラムを停止しようとします。 これは成功することも失敗することもありますが、 その成否は、 リモート・システムのハードウェアやシリアル・ドライバにも依存します。 割り込み文字を再度入力すると、 GDBは以下のプロンプトを表示します。

Interrupted while waiting for the program.
Give up (and stop debugging it)?  (y or n)

ここでyを入力すると、 GDBはリモート・デバッグ・セッションを破棄します (後になって再実行したくなった場合には、 接続するために`target remote'を再度使用します)。 nを入力すると、 GDBは再び待ち状態になります。

通信プロトコル

GDBとともに提供されるスタブ・ファイルは、 ターゲット側の通信プロトコルを実装します。 そしてGDB側の通信プロトコルは、 GDBのソース・ファイル`remote.c'に実装されています。 通常は、 これらのサブルーチンに通信処理を任せて、 詳細を無視することができます (独自のスタブ・ファイルを作成するときでも、 詳細については無視して、 既存のスタブ・ファイルをもとにして作成を始めることができます。 `sparc-stub.c'が最もよく整理されており、 したがって最も読みやすくなっています)。

しかし、 場合によっては、 プロトコルについて何かを知る必要が出てくることもあるでしょう。 例えば、 ターゲット・マシンにシリアル・ポートが1つしかなく、 GDBに対して送られてきたパケットを検出したときに、 ユーザ・プログラムが何か特別なことをするようにしたい場合です。

以下の例では、 `<-'`->'が、 それぞれ転送されたデータと受信されたデータを示すために使われています。

(確認メッセージを除く) すべてのGDBコマンドとそれに対する応答は、 packet(パケット)として送信されます。 packetは、 文字`$'で始まり、 その後ろに実際のpacket-data(パケット・データ)が続きます。 さらにその後ろに、 終端文字`#'と2桁のチェックサム値が続きます。

$packet-data#checksum

ここで、 2桁の数字から構成されるchecksumは、 先頭の`$'と終端の`#'の間にあるすべての文字の値を合計したものを 256で割った余りとして計算されます (8ビットの無符合チェックサム)。

プロトコル実装者は、 GDB 5.0よりも古いバージョンのプロトコル仕様においては、 必須ではないものの、 2桁の数字のsequence-id(シーケンスID)が含まれていたことに注意する必要があります。

$sequence-id:packet-data#checksum

このsequence-idは確認メッセージの末尾に付加されていました。 GDBがsequence-idを出力するようになっていたことは過去に一度もありません。 GDB 5.0以降に追加されたパケットを処理するスタブは、 sequence-idを受け付けてはなりません。

ホスト・マシンまたはターゲット・マシンがパケットを受信したとき、 最初に期待される応答は確認メッセージです。 これは単一文字で、 (パッケージが正しく受信されたことを示す) `+'または (再送要求を示す) `-'です。

<- $packet-data#checksum
-> +

ホスト (GDB) がcommand(コマンド)を送信し、 ターゲット (ユーザ・プログラムに組み込まれたデバッグ・スタブ) がresponse(応答)を送信します。 ステップ実行コマンドや継続実行コマンドの場合には、 操作が完了した (ターゲットが再び停止した) ときにのみ応答が送信されます

packet-dataは、 `#'`$'を除く任意の文字が連続したものです (`X'パケットについてはこれら以外にも除外される文字があります)。

パケット内部のフィールドは、 `,'`;'`:'のいずれかによって区切られなければなりません。 特にことわりがない限り、 数字はすべて16進数で表現し、 先頭のゼロは記しません。

プロトコル実装者は、 GDB 5.0よりも古いバージョンでは、 (sequence-idと潜在的に矛盾するため) パケット内部の3番目の文字が文字`:'であってはならなかったことに注意するべきです。

領域を節約するために、 ある文字が繰り返し現われる回数を符合化する方式を使って応答データ(data)を符号化することができます。 `*'は、 その次の文字が、 `*'の前にある文字の繰り返し回数をASCII符号化したものであることを意味しています。 繰り返し回数の符号化の結果はn+29となります。 29を加算することにより、 (繰り返し回数nを符号化する方式が有意味である) n >=3の場合において、 nに対応する表示可能文字が生成されます。 表示可能文字 `$'`#'`+'`-'、 および、 126を超える数値は使ってはなりません。

いくつかのリモート・システムでは、 繰り返し回数を符号化する別のメカニズムが使われていました。 これは、 大雑把にシスコ符号化と呼ばれています。 この場合は、 文字`*'の後ろには、 パケットのサイズを示す2桁の数字が続きます。

したがって、

"0* "

は、 "0000"と同等のことを意味します。

いくつかのパケットに対して返されるエラー応答には2文字のエラー番号が含まれます。 この番号は明確には定義されていません。

スタブがサポートしていないコマンド(command)に対しては、 空の応答(`$#00')が返されるべきです。 こうすれば、 プロトコルの拡張が可能です。 最新のGDBは、 この応答を頼りにして、 あるパケットがサポートされているかどうかを判断することができます。

スタブに対しては、 `g'`G'`m'`M'`c'`s' の各コマンド(command)をサポートすることが要求されています。 これら以外のコマンドはすべて必須ではありません。

以下に、 現在定義されているすべてのコマンド(command)と対応する応答データ(data)の一覧を示します。
パケット 要求 説明
拡張ops ! 拡張リモート・プロトコルを使用します。 これは一度だけセットすれば十分であり、 設定は持続します。 拡張リモート・プロトコルは`R'パケットをサポートしています。
応答`' 拡張リモート・プロトコルをサポートしているスタブは`'を返します。 これは残念なことに、 プロトコル拡張をサポートしていないスタブが返す応答と同一です。
最後のシグナル ? ターゲットが停止した理由を示します。 応答は、 ステップ実行や継続実行の場合と同じです。
応答 後述
予約済 a 将来のために予約されています。
プログラム引数のセット(予約済) Aarglen,argnum,arg,...
プログラムに渡された`argv[]'配列を初期化します。 arglenには、 16進で符号化されたバイト・ストリームであるargのバイト数を指定します。 詳細については`gdbserver'を参照してください。
応答OK
応答ENN
ボーレートのセット(非推奨) bbaud シリアル回線のスピードをbaudに変更します。
ブレイクポイントのセット(非推奨) Baddr,mode mode`S'の場合は) addrによって指定されるアドレスにブレイクポイントをセットします。 また、 (mode`C'の場合は) addrによって指定されるアドレスのブレイクポイントを削除します。 これは、 `Z'パケットと`z'パケットによって取って代わられました。
継続実行 caddr addrは実行を再開すべきアドレスです。 addrが省略された場合、 現在のアドレスにおいて実行を再開します。
応答 後述
シグナルによる継続実行 Csig;addr (16進数)sigによって示されるシグナル通知によって継続実行します。 ;addrの部分が省略されると、 現在のアドレスから実行を再開します。
応答 後述
デバッグのトグル(非推奨) d デバッグ・フラグをトグルします。
ディタッチ D リモート・システムからGDBをディタッチします。 GDBが接続を切断する前に、 リモート・ターゲットに送られます。
応答なし このパケットを送った後、 GDBはいかなる応答もチェックしません。
予約済 e 将来のために予約されています。
予約済 E 将来のために予約されています。
予約済 f 将来のために予約されています。
予約済 F 将来のために予約されています。
レジスタの読み取り g 汎用レジスタの内容を読み取ります。
応答XX... レジスタ・データの個々のバイトは2桁の16進数字によって表現されます。 レジスタのバイト情報はターゲットのバイト・オーダで転送されます。 個々のレジスタのサイズと`g' packetの中における位置は、 GDBの内部マクロREGISTER_RAW_SIZEおよびREGISTER_NAMEによって決定されます。 いくつかの標準gパケットの仕様を以下に示します。
ENN エラーを示します。
レジスタへの書き込み GXX... XX...データの説明については`g'の項を参照してください。
応答OK 成功を示します。
応答ENN エラーを示します。
予約済 h 将来のために予約されています。
スレッドのセット Hct... 後続のオペレーション (`m'`M'`g'`G'、 その他) のためのスレッドをセットします。
応答OK 成功を示します。
応答ENN エラーを示します。
クロック・サイクルによるステップ実行(ドラフト) iaddr,nnn 単一クロック・サイクルによってリモート・ターゲットをステップ実行します。 ,nnnの部分が指定されていれば、 nnnサイクルだけステップ実行します。 addrが指定されていれば、 そのアドレスからステップ実行を開始します。
シグナル通知後、クロック・サイクルによるステップ実行(予約済) I 構文とその意味は、 おそらく`i'`S'と似たものになると思われます。 これらの項を参照してください。
予約済 j 将来のために予約されています。
予約済 J 将来のために予約されています。
キル(kill)要求 k
予約済 l 将来のために予約されています。
予約済 L 将来のために予約されています。
メモリの読み取り maddr,length アドレスaddrから始まるlengthバイトのメモリを読み取ります。 GDBもスタブも、 このメモリ転送がワード境界に境界整列されたアクセスを使うものと前提してはいません。
応答XX... XX...はメモリの内容です。 データの一部しか読むことができない場合は、 要求されたバイト数よりも少ない可能性があります。 GDBもスタブも、 このメモリ転送がワード境界に境界整列されたアクセスを使うものと前提してはいません。
応答ENN NNはerrnoです。
メモリへの書き込み Maddr,length:XX... アドレスaddrから始まるメモリにlengthバイトのデータを書き込みます。 XX...はデータです。
応答OK 成功を示します。
応答ENN エラーを示します (データの一部しか書き込めなかった場合も含まれます)。
予約済 n 将来のために予約されています。
予約済 N 将来のために予約されています。
予約済 o 将来のために予約されています。
予約済 O 将来のために予約されています。
レジスタの読み取り(予約済) pn... 「レジスタへの書き込み」の項を参照してください。
応答r.... レジスタの値をターゲットのバイト・オーダで16進符号化したもの。
レジスタへの書き込み Pn...=r... レジスタn...に値r...を書き込みます。 r...には、 レジスタ内の個々のバイトについて2桁の16進数字が含まれます (ターゲットのバイト・オーダによる)。
応答OK 成功を示します。
応答ENN エラーを示します。
一般的なクエリー qquery クエリー(問い合わせ)queryに関する情報を要求します。 通常GDBのクエリーは大文字で始まります。 ベンダがカスタマイズしたクエリーには、 例えば`qfsf.var'のように、 その企業を表わす(小文字の)接頭語を使うべきです。 queryの後ろには、 `,'または`;'によって区切られたリストが続くこともあります。 スタブは、 完全なquery名にマッチすることを保証しなければなりません。
応答XX... クエリーの結果を16進符号化したデータです。 応答は空であってはなりません。
応答ENN エラー応答です。
応答`' queryを理解できなかったことを示します。
一般的なセット Qvar=val varの値をvalにセットします。 命名規則に関する議論については`q'の項を参照してください。
リセット(非推奨) r システム全体をリセットします。
リモート再起動 RXX リモート・サーバを再起動します。 XXの部分は必要ではありますが、 明確には定義されていません。
ステップ実行 saddr addrは実行を再開するアドレスです。 addrが省略されると、 現在のアドレスから実行を再開します。
応答 後述
シグナルによるステップ実行 Ssig;addr `C'と似ていますが、 継続実行するのではなくステップ実行します。
応答 後述
検索 taddr:PP,MM アドレスaddrからはじめて、 パターンPPおよびマスクMMにマッチするものを後方検索します。 PPMMは4バイトです。 addrは少なくとも3桁の数字でなければなりません。
スレッドの状態確認 TXX スレッドXXが存在する(alive)かどうかを調べます。
応答OK スレッドはまだ存在します(alive)。
応答ENN スレッドはもう存在しません(dead)。
予約済 u 将来のために予約されています。
予約済 U 将来のために予約されています。
予約済 v 将来のために予約されています。
予約済 V 将来のために予約されています。
予約済 w 将来のために予約されています。
予約済 W 将来のために予約されています。
予約済 x 将来のために予約されています。
メモリへの書き込み(バイナリ) Xaddr,length:XX... addrはアドレス、 lengthはバイト数、 XX...はバイナリ・データです。 文字 $#、 および0x7d0x7dを使ってエスケープします。
応答OK 成功を示します。
応答ENN エラーを示します。
予約済 y 将来のために予約されています。
予約済 Y 将来のために予約されています。
ブレイクポイント、ウォッチポイントの削除(ドラフト) zt,addr,length `Z'の項を参照してください。
ブレイクポイント、ウォッチポイントの挿入(ドラフト) Zt,addr,length tは以下の種類を示します。 `0' - ソフトウェア・ブレイクポイント、 `1' - ハードウェア・ブレイクポイント、 `2' - ウォッチポイントへの書き込み、 `3' - ウォッチポイントの読み取り `4' - ウォッチポイントへのアクセス。 addrはアドレスです。 lengthはバイト数による長さです。 ソフトウェア・ブレイクポイントの場合、 lengthはパッチを当てられる命令のサイズを指定します。 ハードウェア・ブレイクポイントおよびハードウェア・ウォッチポイントの場合、 lengthは監視されるメモリ域を指定します。 重複するパケットによる潜在的な問題を回避するために、 オペレーションは副作用のないよう(idempotent)に実装しなければなりません。
応答ENN エラーを示します
応答OK 成功を示します。
`' サポートされていない場合の応答です。
予約済 <other> 将来のために予約されています。

パケット `C'`c'`S'`s'`?'は、 以下のいずれであっても応答として受け取ることができます。 パケット `C'`c'`S'`s'の場合、 この応答はターゲットが停止したときにはじめて返されます。 以下において、 `signal number'(シグナル番号)の正確な意味はきちんと定義されていません。 一般的には、 UNIXにおけるシグナルの番号付けの慣習の1つが使われます。
SAA AAはシグナル番号です。
TAAn...:r...;n...:r...;n...:r...; AAは2桁の数字で表わされたシグナル番号です。 n...は16進数のレジスタ番号です。 r...はレジスタの内容をターゲットのバイト・オーダで表現したもので、 そのサイズはREGISTER_RAW_SIZEによって定義されます。 n...`thread'です。 r...はそのスレッドのプロセスIDで、 16進整数です。 n...は先頭の文字が正当な16進数字以外である文字列です。 GDBは、 このn...r...のペアを無視して、 次に進むはずです。 これにより、 プロトコルの拡張が可能になります。
WAA プロセスが終了し、 その終了ステータスがAAです。 これは、 特定の種類のターゲットにのみ適用可能です。
XAA プロセスはシグナルAAによって停止しました.
NAA;t...;d...;b... (旧) AAはシグナル番号です。 t...はシンボル"_start"のアドレスです。 d...はdataセクションのベース・アドレスです。 b...はbssセクションのベース・アドレスです。 注:Cisco Systems社のターゲットによってのみ利用されます。 この応答と"qOffsets"クエリーの違いは、 前者においては'N'パケットが自然発生的に来るのに対して、 'qOffsets'はホストのデバッガによって開始されたクエリーであるという点です。
OXX... XX...は、 ASCIIデータを16進符号化したものです。 これは、 プログラムが動作中で、 デバッガが'W'、 'T'、 等々を待ち続けなければならない状況ではいつでも発生し得ます。

以下のセット・パケットおよびクエリー・パケットは定義済みです。
カレント・スレッド qC カレント・スレッドのIDを返します。
応答QCpid pidは16ビットのプロセスIDを16進符号化したものです。
応答* その他の応答はいずれも古いPID(プロセスID)を示唆します。
すべてのスレッドID qfThreadInfo
qsThreadInfo ターゲット(OS)から、 すべてのアクティブなスレッドのIDのリストを取得します。 アクティブなスレッドの数が多すぎて1つの応答パケットに入りきらない可能性があるため、 このクエリーは対話的に行われます。 スレッドの全リストを取得するためには、 複数のクエリー/応答シーケンスが必要になるかもしれません。 シーケンスの最初のクエリーはqfThreadInfoクエリーです。 また、 シーケンス中の後続のクエリーはqsThreadInfoクエリーです。
注:qLクエリーを置き換えます(後述)。
応答m<id> 単一のスレッドID
応答m<id>,<id>... カンマで区切られたスレッドIDのリスト
応答l (アルファベット小文字の「エル」)リストの終端を示します。
ターゲットは、 個々のクエリーに対して、 ビッグ・エンディアンの16進数であるスレッドID(複数可)をカンマで区切ったリストを返します。 GDBは、 個々の応答に対して、 (qsクエリーを使って) さらにスレッドIDを求める要求を返します。 これは、 ターゲットがl (アルファベット小文字の「エル」。'last'を表わす) を返すまで続きます。
追加のスレッド情報 qThreadExtraInfo,id
<id>はビッグ・エンディアンの16進数であるスレッドIDです。 スレッド属性の表示可能な文字列による説明はターゲットOSから取得されます。 この文字列には、 そのスレッドに関してGDBからユーザに知らせたほうが良いとターゲットOSが考えたことであれば、 何でも含まれている可能性があります。 この文字列は、 GDBの`info threads'の表示結果の中に含まれます。 追加のスレッド情報文字列として考えられる例としては、 "Runnable"や"Blocked on Mutex"が挙げられます。
応答XX... XX...はASCIIデータを16進符号化したもので、 スレッドの属性に関する追加情報を含む表示可能な文字列から構成されます。
クエリーLISTまたはクエリーthreadLIST(非推奨) qLstartflagthreadcountnextthread
RTOSからスレッド情報を取得します。 startflag (1桁の16進数字) は、 先頭のクエリーを示すときは1、 後続のクエリーを示すときは0です。 threadcount (2桁の16進数字) は、 応答パケットに含まれるスレッド数の最大値です。 nextthread (8桁の16進数字) は、 後続のクエリー (startflagが0) に対するもので、 応答内においてargthreadとして返されます。
注:このクエリーはqfThreadInfoクエリーによって置き換えられます (既述)。
応答qMcountdoneargthreadthread...
count (2桁の16進数字) は返されたスレッドの数です。 done (1桁の16進数字) は、 まだスレッドがあることを示す場合は0、 もうスレッドがないことを示す場合は1です。 argthread(6) (8桁の16進数字) は、 要求パケットの中のnextthreadです。 thread...は、 ターゲットから送られたスレッドIDのシーケンスです。(7) remote.c:parse_threadlist_response()を参照してください。
メモリ・ブロックのCRCの計算 qCRC:addr,length
応答ENN エラー(例えば、メモリ・フォルト)
応答CCRC32 指定されたメモリ域の32ビット周期的冗長性チェック(cyclic redundancy check)
セクション・オフセットのクエリー qOffsets ダウンロードされたイメージを再配置する際にターゲットが使ったセクション・オフセットを取得します。 注:応答にはBssオフセットが含まれていますが、 GDBはこれを無視し、 代わりにBssセクションに対してDataオフセットを適用します。
応答Text=xxx;Data=yyy;Bss=zzz
スレッド情報の要求 qPmodethreadid
threadidに対応する情報を返します。 modeは16進符号化された32ビットのモードです。 threadidは16進符号化された64ビットのスレッドIDです。
応答* remote.c:remote_unpack_thread_info_response()を参照してください。
リモート・コマンド qRcmd,COMMAND
(16進符号化された)COMMANDは、 実行するために、 ローカルにあるインタープリタに渡されます。 不正なコマンドは、 出力文字列を通じて報告されるはずです。 最終的な結果パケットの前に、 ターゲットがコンソール出力パケットOOUTPUTをいくつか応答する可能性もあります。 実装者は、 スタブのインタープリタへのアクセスを提供することには、 セキュリティ上の問題がある可能性のあることに注意するべきです。
応答OK 出力を伴わないコマンド応答。
応答OUTPUT 16進符号化された出力文字列OUTPUTを伴うコマンド応答。
応答ENN 要求が不正な形式であったことを示します。
応答`' `q'`Rcmd'が認識できないときに返されます。

次の`g'/`G'パケットは以前は定義されていました。 以下においては、 いくつかの32ビット・レジスタが64ビットとして転送されています。 これらのレジスタは、 割り当てられた領域を埋めるためにゼロ拡張または符号拡張される必要があります。 レジスタのバイトは、 ターゲットのバイト・オーダで転送されます。 レジスタのバイトの中の2つの4ビットは、 most-significant、 least-significant の順に転送されます。
MIPS32 すべてのレジスタは32ビットのサイズとして転送されます。 転送の順序は、 32個の汎用レジスタ、 sr、 lo、 hi、 bad、 cause、 pc、 32個の浮動小数点レジスタ、 fsr、 fir、 fpです。
MIPS64 すべてのレジスタは (srのような32ビットのレジスタも含めて) 64ビットのサイズとして転送されます。 転送の順序はMIPS32の場合と同じです。

ターゲットが再起動される場合のシーケンス例を以下に示します。 再起動による直接の出力はまったくないことに注目してください。

<- R00
-> +
ターゲット再起動
<- ?
-> +
-> T001:1234123412341234
<- +

ターゲットを単一命令ごとにステップ実行する場合のシーケンス例を以下に示します。

<- G1445...
-> +
<- s
-> +
時間経過
-> T001:1234123412341234
<- +
<- g
-> +
-> 1455...
<- +

gdbserverプログラムの使用

gdbserverは、 UNIX系システム用の制御プログラムで、 これにより、 通常のデバッグ用スタブをリンクすることなく、 target remoteコマンドによって、 ユーザ・プログラムをリモートのGDBに接続することができます。

gdbserverは、 デバッグ用スタブに完全に取って代わるものではありません。 gdbserverは、 GDBが必要とするのと同様のオペレーティング・システムの機能を基本的には必要とするからです。 実際、 リモートのGDBと接続するためにgdbserverを実行できるシステムであれば、 GDBをローカルに実行することも可能でしょう。 それでも、 gdbserverはGDBと比較するとかなりサイズが小さいので、 便利なことがあります。 また、 gdbserverの移植はGDB全体の移植よりも簡単なので、 gdbserverを使うことで、 新しいシステムでの作業をより早く開始することができます、 最後に、 リアルタイム・システムをターゲットとする開発をしている場合、 リアルタイムな操作に関わるトレードオフのために、 例えばクロス・コンパイルなどによって、 他のシステム上で可能な限り多くの開発作業を行ったほうが便利であるということがあるでしょう。 デバッグ作業に関しても、 gdbserverを使うことでこれと同じような選択を行うことができます。

GDBとgdbserverは、 シリアル回線またはTCP接続を経由して、 標準的なGDBリモート・シリアル・プロトコルによって通信します。

ターゲット・マシンでは:
デバッグしたいプログラムのコピーが1つ必要です。 gdbserverはユーザ・プログラムのシンボル・テーブルを必要とはしませんので、 スペースの節約が必要であれば、 プログラムをストリップすることができます。 ホスト・システム上のGDBが、 シンボルに関するすべての処理を実行します。 gdbserverを使うには、 GDBとの通信方法、 ユーザ・プログラムの名前、 ユーザ・プログラムへの引数を教えてやる必要があります。 構文は、 以下のとおりです。
target> gdbserver comm program [ args ... ]
commは (シリアル回線を使うための) 装置名、 あるいは、 TCPのホスト名とポート番号です。 例えば、 `foo.txt'という引数を指定してEmacsをデバッグし、 シリアル・ポート`/dev/com1'経由でGDBと通信するには、 以下のように実行します。
target> gdbserver /dev/com1 emacs foo.txt
gdbserverは、 ホスト側のGDBが通信してくるのを受動的に待ちます。 シリアル回線の代わりにTCP接続を使うには、 以下のようにします。
target> gdbserver host:2345 emacs foo.txt
前の例との唯一の違いは第1引数です。 これは、 ホストのGDBとTCPによって通信することを指定しています。 `host:2345'は、 マシン`host'からローカルのTCPポート2345へのTCP接続をgdbserverが期待していることを意味します (現在のバージョンでは、 `host'の部分は無視されます)。 ターゲット・システム上で既に使われているTCPポートでなければ、 任意の番号をポート番号として選択できます (例えば、 23telnetに予約されています) (8)。 ここで指定したのと同じポート番号を、 ホスト上のGDBのtarget remoteコマンドで使わなければなりません。
GDBのホスト・マシンでは:
GDBはシンボル情報、 デバッグ情報を必要とするので、 ストリップされていないユーザ・プログラムのコピーが必要です。 通常どおり、 第1引数にユーザ・プログラムのローカル・コピーの名前を指定してGDBを起動します (シリアル回線の速度が9600bps以外であれば、 `--baud'オプションも必要になります)。 その後、 target remoteコマンドによってgdbserverとの通信を確立します。 引数には、 装置名 (通常は`/dev/ttyb'のようなシリアル装置)、 または、 host:PORTという形式でのTCPポート記述子を指定します。 例えば、
(gdb) target remote /dev/ttyb
では、 シリアル回線`/dev/ttyb'を介してgdbserverと通信します。 また、
(gdb) target remote the-target:2345
では、 ホスト`the-target'上のポート2345に対するTCP接続によって通信します。 TCP接続を使う場合には、 target remoteコマンドを実行する前に、 gdbserverを起動しておかなければなりません。 そうしないと、エラーになります。 エラー・テキストの内容はホスト・システムによって異なりますが、 通常は`Connection refused'のような内容です。

gdbserve.nlmプログラムの使用

gdbserve.nlmはNetWareシステム用の制御プログラムです。 これによって、 target remoteコマンドでユーザ・プログラムをリモートのGDBに接続することができます。

GDBとgdbserve.nlmは、 標準のGDBリモート・シリアル・プロトコルを使って、 シリアル回線経由で通信します。

ターゲット・マシンでは:
デバッグしたいプログラムのコピーが1つ必要です。 gdbserve.nlmはユーザ・プログラムのシンボル・テーブルを必要とはしませんので、 スペースの節約が必要であれば、 プログラムをストリップすることができます。 ホスト・システム上のGDBが、 シンボルに関わるすべての処理を実行します。 gdbserve.nlmを使うには、 GDBとの通信方法、 ユーザ・プログラムの名前、 ユーザ・プログラムの引数を教えてやる必要があります。 構文は、 以下のとおりです。
load gdbserve [ BOARD=board ] [ PORT=port ]
              [ BAUD=baud ] program [ args ... ]
boardportがシリアル回線を指定します。 baudは接続に使われるボーレートを指定します。 portnodeのデフォルト値は0、 baudのデフォルト値は9600bpsです。 例えば、 `foo.txt'という引数を指定してEmacsをデバッグし、 シリアル・ポート番号2、 ボード1を経由して19200bpsの接続でGDBと通信するには、 以下のように実行します。
load gdbserve BOARD=1 PORT=2 BAUD=19200 emacs foo.txt
GDBのホスト・マシンでは:
GDBはシンボル情報、 デバッグ情報を必要とするので、 ストリップされていないユーザ・プログラムのコピーが必要です。 通常どおり、 第1引数にユーザ・プログラムのローカル・コピーの名前を指定してGDBを起動します (シリアル回線の速度が9600bps以外であれば、 `--baud'オプションも必要になります)。 その後、 target remoteコマンドによって gdbserve.nlmとの通信を確立します。 引数には、 装置名 (通常は`/dev/ttyb'のようなシリアル装置) を指定します。 例えば、
(gdb) target remote /dev/ttyb
は、 シリアル回線`/dev/ttyb'を経由してgdbserve.nlmと通信します。

カーネル・オブジェクト表示

いくつかのターゲットでは、 カーネル・オブジェクトの表示がサポートされています。 GDBは、 この機能を使うことで、 オペレーティング・システムと特別に通信を行い、 mutexやその他の同期オブジェクトのようなオペレーティング・システム階層におけるオブジェクトに関する情報を表示することができます。 表示可能なオブジェクトはOSごとに決まっています。

オペレーティング・システムを指定するにはset osコマンドを使います。 これによりGDBに対して、 初期化するべきカーネル・オブジェクト表示モジュールが指示されます。

(gdb) set os cisco

set osが成功すると、 GDBはオペレーティング・システムに関していくつかの情報を表示し、 ターゲットに関するクエリー(問い合わせ)に使うことのできる新しいinfoコマンドが生成されます。 infoコマンドには、 オペレーティング・システムをもとに名前が付与されます。

(gdb) info cisco
List of Cisco Kernel Objects
Object     Description
any        Any and all objects

さらにサブコマンドを使うことによって、 カーネルが認識している特定のオブジェクトに関して問い合わせることができます。

現時点では、 あるオペレーティング・システムがサポートされているかどうかを判定するには、 実際に試してみるよりほかに方法がありません。


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