Goコードのデバッグ(現状報告)
Debugging Go code (a status report) by Luuk van Dijk
デバッグでは、変数を調べるための気の利いたprint文をいくつか仕込むことや、スタックトレースを得るための適切な位置に置いたpanicに勝るものはありません。ただ、忍耐力かソースコードのどちらかが足りないこともあり、そういうときには優れたデバッガが大きな助けになります。だからこそ、これまでの複数のリリースを通じて、Goのgcリンカ(6lと8l)がGNUデバッガGDBをサポートする機能を改善してきました。
最新のリリース(2010年11月2日)では、6lと8lのリンカがELF(Linux、FreeBSD)またはMach-O(Mac OS X)バイナリを書き出す際にDWARF3のデバッグ情報を出力するようになりました。このDWARFのコードは十分に充実しており、次のようなことができます。
- GDBバージョン7.xでGoプログラムを読み込む
- Go、C、アセンブリの各ソースファイルを行番号付きですべて一覧表示する(Goランタイムの一部はCとアセンブリで書かれています)
- 行番号を指定してブレークポイントを設定し、コードをステップ実行する
- スタックトレースを表示し、スタックフレームを調べる
- ほとんどの変数のアドレスを見つけて、その内容を表示する
まだいくつか不便な点があります。
- 出力されるDWARFコードは、Mac OS Xに付属するGDBバージョン6.xでは読み込めません。標準のOS X版GDBでもDWARFの出力を読み込めるようにするパッチは喜んで受け入れますが、それが修正されるまでは、OS X上で使うにはGDB 7.xをダウンロードしてビルドし、インストールする必要があります。ソースは http://sourceware.org/gdb/download/ にあります。OS X特有の事情により、
chgrp procmodとchmod g+sを実行して、ローカルのファイルシステム上にバイナリをインストールする必要があります。 - 名前はパッケージ名で修飾されており、GDBはGoのパッケージを理解しないため、各項目をフルネームで参照しなければなりません。たとえば、パッケージ
mainにある変数vは、シングルクォートで囲んだ'main.v'として参照する必要があります。この結果、変数名や関数名のタブ補完は機能しません。 - レキシカルスコープの情報はいくぶん分かりにくくなっています。同じ名前の変数が複数ある場合、n番目のインスタンスには「#n」という形式のサフィックスが付きます。これは修正する予定ですが、コンパイラとリンカの間でやり取りされるデータにいくつか変更が必要になります。
- スライスと文字列の変数は、ランタイムライブラリ内部の構造そのままの形で表示されます。
{data = 0x2aaaaab3e320, len = 1, cap = 1}のような見た目になります。スライスの場合、要素を調べるにはdataポインタを参照解決する必要があります。
まだ動かないものもあります。
- チャンネル、関数、インターフェース、マップの変数は調べられません。
- 型情報が付与されているのはGoの変数だけで、ランタイムのC変数には付与されていません。
- WindowsとARMのバイナリにはDWARFのデバッグ情報が含まれておらず、そのためGDBで調べることはできません。
今後数ヶ月のうちに、コンパイラとリンカを変更するか、GDB向けのPython拡張を使うことで、これらの問題に対処していく予定です。それまでの間、Goプログラマの皆さんがこのよく知られたデバッグツールに、より良い形でアクセスできるようになることを願っています。
追記として、DWARF情報はGDB以外のツールからも読み込めます。たとえば、Linuxではシステム全体を対象としたプロファイラであるsysprofと組み合わせて使えます。
By Luuk van Dijk