delveを使って起動済みプロセスにアタッチする方法
delveをインストール
$ go install github.com/go-delve/delve/cmd/dlv@latest
アタッチ
サンプルプログラムを用意。3秒置きに文字列を出力するやつ
package main import ( "fmt" "os" "time" ) func main() { fmt.Println("start", os.Getpid()) for range time.Tick(3 * time.Second) { fmt.Println("Tick!!") } }
起動したら`go buildとかして
$ dlv attach ${PID}
をするだけでアタッチができる。便利
最適化などの無効化
インクリメントしたけど使わない変数やインライン展開されると手元のコードと差異が出てデバッグしにくい。そういう時はビルドフラグにgo build -gcflags=all='-N -l'をつけることでそれぞれを無効化できる。gccでいう-O0みたいなイメージ。(Goの場合はコンパイル時にどれくらい最適化が働くのだろう?デバッグの際にも予期しないような結果みたいなのはgdb使ってるとよくあったが...)
デバッグ情報
Goはオプションに何もつけないとデバッグ情報のDWARFが生成されるようです。gccでいう-gを付けずともgdbやdelveを使ったデバッグをできるのはこの仕様のためのようです。-ldflags='-w'をつけてビルドすることでこの抑制することができます。
ちなみにgo runとかgo testで生成されるバイナリを見たところデバッグ情報はついていないようでした(コンパイル時間の短縮などが狙い?)。go runしたプロセスとかデバッグ情報なしでビルドした場合にdelveでアタッチを試みるとcould not open debug infoと表示されます。
$ objdump -g main_nodwarf main_nodwarf: file format elf64-x86-64
デフォルトで無効にしようという声もあるようでした。