gdb の使い方・デバッグ方法まとめ



デバッガにはロードモジュールをそのまま、そのレベルでデバッグするabsolute debugger(adb)とソースレベルのエントリを利用してデバッグを行なう symbolic debugger(dbx/gdb)の2種類があります。

ソースコードが存在するプログラムのデバッグにはシンボリックデバッガが適しています。

スポンサードリンク

gdb を利用する

ソースコードが大量にあり、どのソースコードでエラーが発生しているか分 からない場合に威力を発揮します。

gdb を利用するためのビルド手順

「gcc」はLinuxや、Windowsのcygwin等で使えるC言語のコンパイラです。

$ gcc -g ソースコード名

「-g」オプションを付けてビルドを行うことで、「gdb」でデバッグが可能となります。

なお、デバッグのための情報が増えるため、生成された実行ファイルのサイズは大きくなります。

gdb の起動方法

$ gdb 実行ファイル名

デバッグ対象バイナリの実行方法

(gdb) r

r は runの省略です。これにより、バイナリの実行が開始されます。

もし、バイナリの実行時に引数をつけて動作させたい場合は、「r 引数」と入力してください。

gdb の終了方法

(gdb) q

ブレークポイントを指定する

ブレークポイントを設定すると、そこで実行が一時停止します。

(gdb) b 行番号
(gdb) b 関数名
(gdb) b ファイル名:行番号

b はbreakの省略です。

ジャンプ

関数の中の処理まで追い掛けたくない場合。

(gdb) n

n はnextの省略です。

関数内の処理を追いかける場合。

(gdb) s

s はstepの省略です。

ブレークポイントを設定した箇所だが、実行の継続する場合。

(gdb) c

c はcontinueの省略です。

表示(変数の出力)方法

(gdb) p 変数表示
(gdb) p *ポインタ変数
(gdb) p &アドレス変数

p は printの省略です。

printコマンドに /format を付加することで、出力書式を指定することができます。

書式意味書式意味
o8進表示d符号付き10進表示
x16進表示u符号なし10進表示
t2進表示c文字表示
f浮動小数点表示aアドレス

たとえば、変数 var の値を2進数で表示したい場合は、次のように指定します。

(gdb) p/t var

一覧表示

whatis        変数の型を調べる。 
info b 今設定しているブレークポイントの一覧を表示

セグメントフォルトをした後に利用すれば、どの関数で発生したか確認できます。

info stack 関数の呼び出しスタックの一覧を表示
info Thread 存在しているスレッドの一覧を表示

異なるアドレスにおける処理継続

以下のコマンドを使用することで、ユーザが選択したアドレスにおいて実行を継続させることができます

jump linespec linespecで指定される行において、実行を再開
jump *address addressで指定されるアドレスにある命令から、実行を再開

アドレスが分かっている場合のメモリリーク出力

xはhexの意味です。

(gdb) p (char*)アドレス番号
(gdb) x/(文字数)c アドレス番号

ブレークポイントにブレーク条件を設定する

file.cppのfunction関数にブレークポイント(ブレークポイント番号=1)を指定し、さらに 変数xが1になったときにブレークする。

(gdb) break file.cpp:function
(gdb) condition 1 x==1
(gdb) run

ブレークポイント1の条件を解除するには、次のように行います。

(gdb) condition 1

ウォッチポイントを指定する

「i==0 以外の時にストップさせる」などを行う方法

次のように使います。

(gdb) break file.cpp:function
(gdb) run
(gdb) delete      → break pointをすべて削除
(gdb) watch i==0  → i==0 以外の時にストップ
(gdb) c

マルチスレッドのデバッグ

複数のスレッドが走っているプログラムにおいて、デッドロックなどを調査するのに便利です。

(gdb) info thread

詳細を知りたいスレッドは、スレッド番号を選択し、where や up コマンドで確認します。

(gdb) thread 3
(gdb) where / bt
(gdb) up 2

1つのコマンドを複数のスレッドに対して実行するコマンドは「thread apply [threadno] [all] args」です。全スレッドの callstack を表示するには次のように入力します。

(gdb) thread apply all info stack

変更

(gdb) set 変数 = 値

core ファイルの生成方法

gdb-5.2.1からは、gdb を起動した後に動的に coreファイルを生成できるようになりました。

(gdb) help generate-core-file

Save a core file with the current state of the debugged process.
Argument is optional filename.  Default filename is 'core.<process_id>'.

これで「core.プロセスID」と言う名前のcore ファイルが出来ます。

core の解析方法

実際に生成されたcoreファイルをどのようにして解析するのかを簡単に説明しておきます。

core dump を有効化する

$ limit coredumpsize (サイズ) → 容量にあわせて 10000 等

deadlock した場合の coreファイルの生成方法

上記の通り core dump を有効化しておき、別 terminal から signal を送って core を吐かせます。

% ps -aux | grep (デバッグしたい実行ファイル)

(実行ファイル の プロセスID を調べる)

% kill -3 (プロセスID)<pid>

「-3」は「-ABRT」でも同じです。

core の利用方法

(gdb) gdb 実行ファイル coreファイル 

あとは通常通り、whereコマンド等で関数のスタックトレースを得ることができます。しかしながら、ここでスタックトレースを正常に得られるのは、プログラムがシンボルテーブルを持っている場合に限られます。

例)core dump からの thread backtrace 取得

上記で取得した core を利用し、segfault (or deadlock) 発生時の状況を gdb で解析できます。

% gdb 実行ファイル core.<pid>
...
(gdb) set logging file <ログファイル名>
(gdb) set logging on
(gdb) thread apply all bt → 全スレッド表示
(gdb) set logging off
(gdb) quit

例)実行中に deadlock してしまった場合

実行中に deadlock してしまった場合、gdb を attach し、backtrace を取る。

% ps auxww | grep 実行ファイル → 実行ファイルの pid を調べる
% gdb 実行ファイル
(gdb) attach <実行ファイル の pid>
...
(gdb) set logging file <ログファイル名>
(gdb) set logging on
(gdb) thread apply all bt
(gdb) set logging off
(gdb) quit

その他のツール

デバッグに便利なツールを紹介

nm コマンドを使う

$ nm -D libuXXX.so

「.so」ファイルの場合には「-D」オプションを付けることでダイナミックシンボルが表示できます。

仮に「シンボルがありません」と表示される場合は、ビルドオプションに「-gが付いている」「strip されていない」などを確認してください

小文字はそのシンボルがローカルであることを意味し、 大文字はそのシンボルがグローバル (外部定義) であることを意味します。

objdump コマンドを使う

$ objdump -T libuXXX.so

「.so」ファイルの場合には「-T」オプションを付けることでダイナミックシンボルが表示できます。

これは「nmコマンド」を利用したのと得られる情報はほぼ一緒です。

lddコマンドによる依存ファイル一覧

$ ldd 実行ファイル

プログラムヘッダ構造

$ strace 実行ファイル

システムコールのトレース結果

$ readelf -l 実行ファイル

オススメ書籍

人気の高い書籍および参考文献を紹介します。

スポンサードリンク