導入
Go言語で開発を行っていると、本番環境やテスト実行中に発生した「スタックトレース上のメモリ番地(アドレス)」に頭を悩ませることはありませんか?通常、Goのランタイムはパニック時にソースコードの行番号を表示してくれますが、バイナリが最適化されていたり、特定の条件下でアドレスしか得られない場合があります。そんな時に強力な武器となるのが、Go標準ツールである「go tool addr2line」です。このツールを使えば、バイナリ内の情報を辿り、実行時の問題をピンポイントで特定することが可能です。
基礎知識
「addr2line」とは、実行可能ファイル(バイナリ)内のメモリ番地を、ソースコードのファイル名と行番号に変換するデバッグ用ツールです。Goのコンパイルプロセスでは、ソースコードの情報がデバッグ情報としてバイナリに埋め込まれます。このツールは、そのバイナリ内のシンボルテーブルを参照することで、CPUが実行していたアドレスが「どのファイルの何行目」に対応しているかを逆引きしてくれます。
実装/解決策
addr2lineを使用するには、まず調査対象となる「バイナリファイル」が必要です。手順は以下の通りです。
1. 解析したいプログラムを「デバッグ情報を含めて」ビルドする(go build -gcflags=”-N -l”)。
2. プログラム実行中に得られた、あるいはスタックトレース上の16進数のアドレスを特定する。
3. ターミナルで `go tool addr2line [バイナリ名]` を実行し、続いてアドレスを入力する。
サンプルプログラム
以下のコード例では、実際にパニックを発生させ、そのアドレスを解析する流れを想定しています。
// main.go
package main
import “fmt”
func main() {
// わざとパニックを発生させる関数を呼び出す
triggerPanic()
}
func triggerPanic() {
// この行でパニックが発生したと仮定します
var ptr int
fmt.Println(ptr)
}
/
実行と解析手順:
1. ビルド:
go build -o myapp main.go
2. 実行してパニックを起こし、スタックトレースからアドレス(例: 0x456789)を確認する。
3. addr2lineの実行:
go tool addr2line myapp
(入力待ち状態になるので、アドレスを入力する)
0x456789
4. 出力結果:
/path/to/main.go:14
(これで14行目に問題があることが即座に分かります)
/
応用・注意点
現場でこのツールを使う際の重要な注意点が2つあります。
一つ目は「ビルドオプション」です。最適化(インライン化など)が強くかかっていると、アドレスと行番号の対応が正確に結びつかないことがあります。デバッグを優先する場合は、ビルド時に `-gcflags=”-N -l”` を付与して最適化を無効化することを検討してください。
二つ目は「バイナリの不一致」です。解析対象のアドレスを出力したバイナリと、手元で `addr2line` に渡すバイナリが同一ビルドであることを必ず確認してください。異なるバージョンのバイナリを渡すと、全く無関係な行番号が表示され、デバッグが迷宮入りする原因となります。CI/CDパイプライン上で、ビルドしたバイナリを成果物として保存しておく習慣をつけておくと、いざという時の解析が非常にスムーズになります。

コメント