地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Go】delveで起動済みのプロセスにアタッチする

github.com

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

デフォルトで無効にしようという声もあるようでした。

github.com