デバッガにはロードモジュールをそのまま、そのレベルでデバッグするabsolute debugger(adb)とソースレベルのエントリを利用してデバッグを行なう symbolic debugger(dbx/gdb)の2種類があります。
ソースコードが存在するプログラムのデバッグにはシンボリックデバッガが適しています。
スポンサードリンク
ソースコードが大量にあり、どのソースコードでエラーが発生しているか分 からない場合に威力を発揮します。
「gcc」はLinuxや、Windowsのcygwin等で使えるC言語のコンパイラです。
$ gcc -g ソースコード名
「-g」オプションを付けてビルドを行うことで、「gdb」でデバッグが可能となります。
なお、デバッグのための情報が増えるため、生成された実行ファイルのサイズは大きくなります。
$ gdb 実行ファイル名
(gdb) r
r は runの省略です。これにより、バイナリの実行が開始されます。
もし、バイナリの実行時に引数をつけて動作させたい場合は、「r 引数」と入力してください。
(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 を付加することで、出力書式を指定することができます。
書式 | 意味 | 書式 | 意味 |
---|---|---|---|
o | 8進表示 | d | 符号付き10進表示 |
x | 16進表示 | u | 符号なし10進表示 |
t | 2進表示 | 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 変数 = 値
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ファイルをどのようにして解析するのかを簡単に説明しておきます。
$ limit coredumpsize (サイズ) → 容量にあわせて 10000 等
上記の通り core dump を有効化しておき、別 terminal から signal を送って core を吐かせます。
% ps -aux | grep (デバッグしたい実行ファイル)
(実行ファイル の プロセスID を調べる)
% kill -3 (プロセスID)<pid>
「-3」は「-ABRT」でも同じです。
(gdb) gdb 実行ファイル coreファイル
あとは通常通り、whereコマンド等で関数のスタックトレースを得ることができます。しかしながら、ここでスタックトレースを正常に得られるのは、プログラムがシンボルテーブルを持っている場合に限られます。
上記で取得した 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 してしまった場合、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 -D libuXXX.so
「.so」ファイルの場合には「-D」オプションを付けることでダイナミックシンボルが表示できます。
仮に「シンボルがありません」と表示される場合は、ビルドオプションに「-gが付いている」「strip されていない」などを確認してください
小文字はそのシンボルがローカルであることを意味し、 大文字はそのシンボルがグローバル (外部定義) であることを意味します。
$ objdump -T libuXXX.so
「.so」ファイルの場合には「-T」オプションを付けることでダイナミックシンボルが表示できます。
これは「nmコマンド」を利用したのと得られる情報はほぼ一緒です。
$ ldd 実行ファイル
$ strace 実行ファイル
$ readelf -l 実行ファイル
人気の高い書籍および参考文献を紹介します。
スポンサードリンク
スポンサードリンク