デバッガ

個人的には、ソフトの開発にはデバッガが必須であると考えている。しかし、プロのエンジニアの人たちに聞いてみても、デバッガを使っていない人が驚くほど多い。ちゃんとした(?)ソフトウェアの開発現場に居たことがないのでよくわからないが、みんなどうやって開発してるんだろうか。

バグをほとんど出さないような天才とか、頭の中にCPUエミュレータを搭載していてステップ実行なんかが出来てしまうような特異能力者ならまだしも、普通にコードを書いて、その後のバグ取りに時間をかけている開発者にとって、デバッガは無くてはならないものだと思う。現場でほとんど使われていないような高級言語とか、最近流行のLightWeightなものに関しては知りません。

確かにprintfを使って、任意の時点での環境をそれなりに把握することができるし、これを繰り返せば原因は特定できる。熟練したソフトウェア開発者であれば、経験からバグの原因を短い時間で特定することができるかもしれない(熟練した開発者じゃないのでわからないけど)。しかし、デバッガを使えば、それほどの熟練者でなくとも、驚くほど短い時間で問題を見つける事が可能である。正しく解決できるかどうかは別だが。

デバッグの準備

基本的にはコンパイル時にデバッグ情報を付加すれば、ソースレベルでのデバッグが可能である。ただし、最適化をはずさないと非常にデバッグしづらい。デバッガの歴史は最適化との戦いの歴史である(そうでもない)。デバッグ情報も進化する余地が十分残っているのだが、変数が削除されてしまったり、命令の順序がガラッと変わったりしてしまうと、もうどうしようもない。

というわけで、この際思い切ってGCCの場合には-O0オプションで最適化をはずす事にする。デバッグ情報を付加するオプションは -g -gstabs -gstabs+など。-g はDWARFで、-gstabs -gstabs+ はstabのデバッグ情報フォーマットである。DWARF2の場合は、同じヘッダをいっぱいインクルードすると、その数だけデバッグ情報が出てしまうのでサイズがでかくなってしまう。stabは大丈夫。DWARF3でも、この辺は改良されるみたい。

最適化について

最適化をはずさないとデバッグしづらいとは書いたが、ソースレベルデバッグできないわけではない。ただ、ソース上でステップ実行したりすると、あっちこっちに飛んでいってしまって、正確にどこを実行しているのかを把握するのは難しい。ローカル変数なんかも、無くなってしまったものは当然ながら表示されない。

gdbでは、optimized outとか表示されたような気がする。gccはvar-trackingとかで、最適化されてもローカル変数が今どこにあるのかという情報を出来るだけ吐こうとするが、完全に正確というわけではない。gccのプロジェクト内では、現在もデバッグ情報の精度向上について頑張っている人もいるが、最適化のパスを書いてる人達はあまり考えてないような気がする。最適化が進めば進むほど、ソースコードと最終的なコードの対応がつかなくなり、最適化したプログラムのソースレベルデバッグが更に困難になっていくのは避けられない。

んじゃあんまりデバッグに影響を与えないような最適化のパスだけ通せばいいんじゃねーのって事で、-Ogオプションなんかも提案されているが、動きがあるんだか無いんだかわからない。

プログラムのロード

ビルドして出来たプログラムをデバッガでロードする。たいていの場合は、デバッガのロードコマンドを使えば良いだけだが、例えばJTAG-ICE経由でターゲットのメモリに転送する場合などは、メモリアドレスを指定しなければいけないかもしれない。デバッグ情報にロードするべき各セクションのアドレスが書いてあるので、多分大丈夫だろうけど、MMUが無効の場合にLinuxカーネルを転送する時なんかは(普通はそうだろう)、物理アドレスでちゃんと指定してやる必要がある。デバッグ情報に書いてあるアドレスは論理アドレスだし。

続きはいつかかく