Home

Mar 09

Debugging Go 1.4.2 code in GDB on OS X

  • go-lang
  • tips

There are lots of guides and answers when it comes to debugging Go with gdb, but none of them worked for my environment. Here’s what worked.

Go GDB Prompt

My Environment

I have Go installed via homebrew brew install go and have set my GOPATH in ~/.bash_profile, so this may be specific to any or all of my environment. Go says my environment is:

[~/src/go]: go env
GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/jordan/src/go"
GORACE=""
GOROOT="/usr/local/opt/go/libexec"
GOTOOLDIR="/usr/local/opt/go/libexec/pkg/tool/darwin_amd64"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"

Attempts to use delve resulted in the message “Could not launch program: could not acquire mach task 5” which is likely due to my code not being signed the way OS X wants it to be. Running any dlv command leaves bash in a mode where it doesn’t echo input, which doesn’t inspire much confidence, so I’m loath to spend more time trying to get delve working.

Attempts to use gdb resulted in a couple issues that proved to be surmountable.

Build

When building with go build Main.go and running via gdb Main, gdb promptly states “no debugging symbols found”. That’s not going to be very useful, so we’ll build with debugging symbols:

go build -gcflags "-N -l" Main.go

Alas, loading the resulting executable in gdb still prints “no debugging symbols found”. It turns out we need two additional flags:

-work will tell go build to keep the working directory with .o files. Note that you’ll probably need to clean these up once in a while, since go build is no longer removing them after building.

-a will rebuild any packages that have already been built (e.g. without debugging flags). This seems to be necessary even after the first rebuild with debugging flags.

Now we can build with all the debugging symbols gdb needs,

go build -a -work -gcflags "-N -l" Main.go

and gdb Main no longer says there are “no debugging symbols found”.

Run

Unfortunately, the r (run) command in gdb doesn’t yield much success:

(gdb) r
Starting program: /Users/jordan/src/go/GoTest1/Main
Unable to find Mach task port for process-id 95573: (os/kern) failure (0x5).
 (please check gdb is codesigned - see taskgated(8))

This can be mitigated in one of two ways:

1 Run as sudo

2 Code-sign gdb, per this SO answer

sudo gdb Main gets us there quickly enough, at which point you can set breakpoints, but that’s about it.

Loading gdb support for the Go runtime doesn’t work so well:

(gdb) source /usr/local/opt/go/libexec/src/runtime/runtime-gdb.py
Loading Go Runtime support.
Traceback (most recent call last):
  File "/usr/local/opt/go/libexec/src/runtime/runtime-gdb.py", line 205, in <module>
    _rctp_type = gdb.lookup_type("struct runtime.rtype").pointer()
gdb.error: No struct type named runtime.rtype.

There are some different approaches to fixing this, but the one that worked for me was based on this patch:

Edit /usr/local/opt/go/libexec/src/runtime/runtime-gdb.py and comment out (or remove) line 205:

#_rctp_type = gdb.lookup_type("struct runtime._type").pointer()

then change line 216 to:

  return go_type_ptr.cast(gdb.lookup_type("struct reflect.rtype").pointer()).dereference()

Now we can load the Go runtime support:

(gdb) source /usr/local/opt/go/libexec/src/runtime/runtime-gdb.py
Loading Go Runtime support.
(gdb)

and finally start doing some debugging… in as much as the very limited debugging capacity of Go’s gdb support allows.

blog comments powered by Disqus