GDB利用法 第1回

ちょっと前にまとめたGDBの使い方を何回かにわたってブログで発表しようと思います。

GDBは組み込みや制御分野で結構お世話になっている方がいると思いますが、ちょっと違った目線でまとめています。

お役に立つ方がいれば良いのですが…

 

 

gdbによるプログラム試験と自動実行

gdbのいくつかのコマンドを利用してプログラム試験(評価)を行ったり自動実行を
行うための基本的な手順をまとめました。
特に組み合わせレベルを意識し、gccでデバッグオプションが有効でないプログラム、
既に実行中のプログラムを終了させないような形で利用可能な記述を基本としました。
(一部単体レベルや再起動についても記述があります)

 

1.基礎

1.1. 既に起動中のプログラムをコントロールする。

1) 起動中のプログラムと接続する
$gdb -p プロセスID (-x コマンドファイル名)
gdbはすでに起動中のプログラムにも利用できます。接続したプログラムは停止状態に
なりますので速やかに動作させたい場合はC(ontinue)で再開します。
-x で実行するコマンドを定義したファイルを読み込んで実行できます。

起動中のプロセスはgdb向けに-gオプションでコンパイルされている必要はありません。
gdbのフル機能は利用できませんが作業は可能です。
基本的にシンボルとして関数名、外部変数(制約有)等が利用可能です。

2) シンボルファイルを読み込む
(gdb)symbol-file デバッグ情報付のロードモジュール
実行中のモジュールのデバッグ情報付ロードモジュール(-g付でコンパイルしたもの)を
指定します。以降はデバッグ情報が利用できるようになります。

3) main関数の(再)実行
(gdb)r (main関数の引数)
プログラムを実行します。引数を指定した場合は引数が渡されます。
gdbでプログラムを起動する場合にこのコマンドで起動します。(再開はc)
既に起動中の場合は再起動になります。
再起動するとプロセスIDはもちろんタスクの親子関係も変わりますので注意が必要です。

1.2. ブレークポイントのセット

1) 関数の先頭で停止させる
(gdb)b 関数名 (条件式)
これで指定された関数の先頭で停止するようになります。
-gオプションなしの場合これが基本的な停止方法になります。(行指定ができないため)
条件式(ex: if a==0 )を付加した場合は条件が成立した場合に停止します。

2) 変数の値が変化したら停止させる
(gdb)watch 変数名
指定した変数の内容が変化したら停止します。
-gオプションがない場合は外部変数等の一部に限られます。

3) 変数を参照したら停止させる
(gdb)rwatch 変数名
指定した変数を参照したら停止します。
-gオプションがない場合は外部変数等の一部に限られます。

1.3. 関数制御

1) 現在の関数を終了する。
(gdb)return (式)
現在の関数を以降の処理を実行せずに終了(return)します。式を付加した場合は関数の
戻り値となります。(終了後停止)

2) 現在の関数を終了まで実行する。
(gdb)finish
現在の関数を最後まで実行し停止します。

3) 任意の関数を実行する
(gdb) call 関数(引数も指定すること)
指定された関数をその場で実行します。
呼び出された関数もgdbの管理対象です。(ブレークポイントがあればそこで停止します)
ダミーメインがあれば、それとリンクされたすべての関数をcall してテストすることが
可能です。

1.4. 確認、変更

1) 現在の場所を確認する
(gdb)where
現在停止している場所が呼出元を含めて表示されます。

2) 変数の値を確認、変更する
確認
(gdb)p 変数名
変更
(gdb)set 変数名=値
-gオプションがない場合は外部変数等の一部に限られます。

3) ブレークポイントの確認
(gdb)info b
現在登録されているブレークポイントの一覧が表示されます。
ブレークポイントの操作はここで表示される番号(Num)で操作します。

4) ブレークポイントの解除
(gdb)d (ブレークポイントのNum)
登録されているブレークポイントを解除します。(番号を指定しない場合はすべて解除)

1.5. ブレーク時の自動操作登録
(gdb)command breakNum
> (ここからコマンドを列挙する、登録モード中は’>’プロンプト)

>end (エンドで登録モード解除)
(gdb)
指定したブレークポイントで停止した場合に実行するコマンド群を登録します。
登録しておけば指定のブレークポイントで自動的に実行されます。
実行後停止しますが、C(ontinue)を最後に記述しておけば自動的に再開されます。
条件を記述可能で
>if 条件式
>条件成立時の実行文(複数可)
>else
>条件不成立時の実行文(複数可)
>end(if文の終了)

1.6. ログ制御

1) ログファイルを指定する
(gdb)set logging file ファイル名
2) ログの有効/無効
(gdb)set logging on/off
3) ログファイルの上書き/追記
(gdb)set logging overwrite on/off
4) ログの出力先(ファイルのみ on)
(gdb)set logging redirect on/off
5) ログの設定確認
(gdb)show logging

1.7. コマンド群の実行
(gdb)source コマンドファイル名
ファイルに記述されたコマンド群を実行します。

 

2.実践

2.1. 関数を単体デバッグする

1) デバッグするファイルにmain関数がない場合はダミーmainを作成しリンクします。
(ダミーmainにはデバッグに必要な変数だけ定義されていれば良い)
2) b main でメイン関数の最初で停止
3) 関数呼出に必要な変数に値をセット
(必要であればデバッグ対象の関数にブレークポイントをセット)
4) call 関数名(引数) で対象を呼び出す
5) 処理結果を確認する

2.2.対象プログラムを再コンパイルすることなくデバッグに必要な関数を追加する

必要になればライブラリだけ再コンパイルすればよい(プログラム側は変更なし)
初回のみダミーで良いのでライブラリ(.so)をリンクしておく必要はあります。
なお動的リンクを利用するため対象プログラムの外部変数は利用できません。
1) ダミー関数を持った実行時リンクライブラリ(.so)を作成しリンクしておきます。
2) 利用したい関数を作成し、上で指定したライブラリ名で.soを生成します。(リンク不要)
3) 実行時にLD_LIBRARY_PATHで作成した.soのパスを指定します。
4) call で上記で作成した関数を呼び出すことが可能です。(プログラムの再起動は必要)

2.3. 関数の処理内容を変更する

1) b 関数名 で処理内容を変更したい関数にブレークを設定します。
2) 関数実行後に値等を変更する場合は finish で最後まで実行し値を変更します。
3) 実行不要の場合はreturn で処理を飛ばし値を変更します。
4) 必要に応じて call で他の関数を実行します。

2.4. 外部変数が特定の値にどこで設定されるのか確認する

1) watch 変数名 で目的の変数の変化でブレークを登録します。
2) info b でブレークポイントの番号を確認します。
3) command breakNum で目的のブレークポイントでの処理をセットします。
>if 変数名==特定の値
>where
>end
>end
必要に応じて各種のコマンドを追加して処理を続行させることも可能です。
ブレークの番号は基本的に1づつ増えます。(消しても次の番号は減りません)

 

第2回に続く

Pocket