2014/04/15

MacでGoのデバッグ環境を構築する

導入まで手間がかかったのでメモ。

コマンドラインツールに含まれるgdbはちょっと古い (GNU gdb 6.3.50-20050815 (Apple version gdb-1824))ので Goのデバッグに使えません。また、導入したgdbでプロセスのデバッグをするためには署名を入れる必要があります。

さらに、環境変数を適切にセットした上で正しいファイル構成でコンパイルする必要があります。

Goが利用できるgdbを導入する

brewを用いました。

brew install homebrew/dupes/gdb

これだけだと、Gatekeeperによってデバッグプロセスの実行を禁止されてしまいます。

Unable to find Mach task port for process-id 84034: (os/kern) failure (0x5).
 (please check gdb is codesigned - see taskgated(8))

これをやめるにはこのgdbに署名を付けてしまえばよいです。

手順は次の通りです。

  1. Keychain Accessを起動してCreate Certificateを選択。

  2. いろいろ変更する。

    • 「Name」を「gdb-cert」にする
    • 「Certificate Type」を「Code Signing」にする
    • 「Let me override defautls」にチェック
  3. Continueしまくってから、Specify a Location For The Certificateでは「Keychain」を「System」にする。そして「Create」をクリック。

  4. キーチェイン変更でパスワードを求められる。

  5. 無事追加された。

  6. Keychain Accessでgdb-certを見つける。KeychainsをSystemにして、CategoryをMy Certificatesにすると見つかりやすい。

  7. ダブルクリックで詳細を見て、Trustを展開。Code SigningをAlways Trustにする。

  8. codesign -s gdb-cert /usr/local/Cellar/gdb/7.7/bin/gdb

  9. sudo killall taskgated

なお、署名の手順などの詳細は次のページを参照してください。

あとは、このgdbに、パスを通したり、エイリアスやリンクを張ればよいでしょう。

alias ggdb=/usr/local/Cellar/gdb/7.7/bin/gdb

Goでgdbデバッグできるようにする

こちらもbrewを用いました。

brew install go

そして、環境変数GOROOTをセットしておきます。これは設定ファイルに書いてもよいでしょう。

export GOROOT=/usr/local/Cellar/go/1.2.1/libexec

gdb起動時に、Goのランタイムサポート用のスクリプト$GOROOT/src/pkg/runtime/runtime-gdb.pyを読みに行くのでGOROOTを正しくセットする必要があるのです。

続いての環境変数GOPATHは、結論から言うと、ターミナル上でGoのプロジェクトのルートディレクトリで、export GOPATH=`pwd`としたほうがよいみたいです。

なぜなら、gdbは「GOPATH environment variable」 のようなファイル構成があると思っていて、$GOPATH/src以下からソースファイルを捜すためです。

なので、例えば、パッケージfooのソースは、$GOPATH/src/fooなんかに置いておくと見つけてくれます。

環境変数を設定して、ファイルを正しい場所に置いたら、あとはコンパイルするだけです。例えば、パッケージfooをコンパイルするには次のようにします。

$ go build -gcflags "-N -l" foo

-gcflags "-N -l"は関数のインライン化や変数のレジスタ化をやめさせるためのオプションです。

これで生成されたバイナリをデバッグするには次のようにします。

$ ggdb ./foo -d .

gdbの利用例

ブレークポイントはfoo.go:12とかmain.fibonacciとか指定します。

$ cat src/main/foo.go 
package main

import "fmt"

func fibonacci(n int) int {
    if n == 0 {
        return 0
    }
    if n == 1 {
        return 1
    }
    return fibonacci(n-1) + fibonacci(n-2)
}

func main() {
    fmt.Println("fibonacci")
    fmt.Println(fibonacci(20))
}

$ go build -gcflags "-N -l" main

$ ggdb ./main -d .     
GNU gdb (GDB) 7.7
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin13.1.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...done.
Loading Go Runtime support.
(gdb) b main.fibonacci
Breakpoint 1 at 0x2000: file /Users/safx/src/golang/src/main/foo.go, line 5.
(gdb) r
Starting program: /Users/safx/src/golang/main 
fibonacci
[New Thread 0x160f of process 92283]
[New Thread 0x1803 of process 92283]
[New Thread 0x1903 of process 92283]

Breakpoint 1, main.fibonacci (n=20, ~anon1=1) at /Users/safx/src/golang/src/main/foo.go:5
5   func fibonacci(n int) int {
(gdb) bt
#0  main.fibonacci (n=20, ~anon1=1) at /Users/safx/src/golang/src/main/foo.go:5
#1  0x0000000000002167 in main.main () at /Users/safx/src/golang/src/main/foo.go:17
(gdb) c
Continuing.
Breakpoint 1, main.fibonacci (n=19, ~anon1=10) at /Users/safx/src/golang/src/main/foo.go:5
5   func fibonacci(n int) int {
(gdb) clear
Deleted breakpoint 1 
(gdb) c
Continuing.
6765
[Inferior 1 (process 92631) exited normally]

関連リンク

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。