デバッガとは何ぞや
はじめに
みなさんはデバッガというソフトウェアをご存じでしょうか。デバッガはプログラムのバグを発見、修正してくれるもの…というわけではありません。そんなものがあればわたしが欲しいです。
デバッガはプログラムがバグを発見しやすくするための補助ツールです。あくまでバグを見つけたり修正したりする主体はみなさん自身であってデバッガではありません。
デバッガには主に2つの用途があります。
- 実行中のプロセスの状態を見る
- 異常終了したプロセスの終了時の状態を見る
以下それぞれについて説明します。
実行中のプログラムの状態を見る
デバッガはデバッグ対象のプログラムの実行ファイルを変更することなく、次のようなことができます。
- 実行中のプロセスの状態を見られるようにする
- プロセスの実行を特定の箇所で停止させる
- 停止させたプロセスの変数の値を表示する
- プロセスを一気に実行するのではなくソース1行(あるいはアセンブリ言語命令1つ)レベルで少しづつ実行する
- 停止させたプロセスを再開させる
これらをまとめると以下の図のようになります。
プログラムにバグがあるとわかったときに、次のような、いわゆるprintfデバッグをしているかたは多いかと思います。
- バグがありそうなところにあたりをつける
- あたりをつけた場所に変数などの所定の情報を含んだ文字列を表示するコードを追加する
- プログラムを再ビルドする
- 実行する
- 仕込んだ文字列を見る。原因がわかればOK、わからなければまた1に戻る
この方法には、一つの試行のためにいちいちプログラムを変更しなくてはならないという問題があります。ビルドに時間がかかるというコストもあります。
このようなときにデバッガを使えば、あたりを付けた場所でプログラムの実行を止めて、そのあと一行一行実行するといったことができるので便利です。
その一方でprintfのほうが好ましいこともあります。
- リビルド時間のコストが低い
- 「あたりを付けた場所でプログラムの実行を止める」ための条件設定をデバッガのレベルで書くのが面倒、困難なことが多々ある。たとえばループの階層が深いところに疑わしいコードがあるような場合
- デバッガによる実行停止時間が許容されないことがある
- デバッガを使ったことによって事象が再現しなくなることがある。とくにタイミングがシビアなレースコンディションによるバグなど
デバッガはデバッグ以外の用途にも使えます。プログラムを実際に動かしながら内部情報を確かめられるため、プログラムの理解を深めるためにソースコード読解と併用すると大変便利です。
異常終了したプロセスの終了時の状態を見る
プロセスが異常終了したときに、終了時のメモリダンプをファイルに書き出せます。このメモリダンプをデバッガに与えると、プロセスが異常終了したときの状態を見られます。異常終了したときのバックトレースや、そのときの変数の値はデバッグの大いなる助けになります。
とくにプログラムが異常終了した際に原因調査と再発防止策を厳しく求められるエンタープライズシステムにおいてデバッグとコアダンプを使った問題の解析は便利です。筆者もかつてサポート技術者をしていたことは毎日たくさんのコアダンプ[1]を見ていました。
実行中のプログラムのコアダンプだけ採取して実行を継続させるgcore
というプログラムもあります。
筆者はどうしているか
筆者がデバッガを使うのは主に次の用途です。
- 未知のプログラムの実行の流れを実際に動かしながら確認する
- プロセスが異常終了した際の原因究明
この二つの用途ではデバッガは素晴らしく役に立っています。その一方で、既存バグのデバッグのためにデバッガを介してプログラムを動かすということは滅多にやりません。
これは筆者が主に触っているプログラムが前述の「printfのほうが好ましい」に該当するからです。デバッガは使えるなら必ず使えばいいというわけではなく、適材適所で使うものです。
おわりに
デバッガは最初に使うまでに心理的抵抗があるのですが、それほど使い方が難しいわけではありません。使ったことがないかたは一度試してみてはいかがでしょうか。CやC++プログラムならgdb、Goプログラムならdelveなどが一般的に使われています。
-
正確には筆者が見ていたのはプロセスのコアダンプではなくシステム全体のメモリのダンプ、カーネルダンプでした ↩︎
Discussion