Stepping through Go code with gdb sometimes continues

541 views
Skip to first unread message

Chris McGee

unread,
Aug 15, 2013, 10:31:57 PM8/15/13
to golan...@googlegroups.com
I am trying to debug some of my Go code using the gdb debugger based on the tutorial here:


However, sometimes when I set a breakpoint and step through the Go code (next, actually) gdb never comes back. It appears as though the inferior Go process simply continues. I would say that this happens more frequently when I'm stepping over calls to built-in functions that ultimately make system calls (e.g. fmt.Printf).

I have tried providing the compiler parameters as suggested by the above tutorial ("-gcflags "-N -l"). I can see that some of the inlining is disabled but the behaviour persists.

I have tried the newest version of gdb (7.6) as well and the same thing is happening.

I'm guessing that the Go scheduler decides to move the current go routine to a different OS thread because of the syscall confusing gdb.

Does anybody have suggestions on how to work around this problem? Do I need to insert breakpoints defensively to make sure I get control back after making a syscall?

Thanks,
Chris

Chris McGee

unread,
Aug 16, 2013, 5:12:47 PM8/16/13
to golan...@googlegroups.com
I'm running into another problem. Whenever I inspect the local variables using "info locals" I'm seeing certain variables with a '&' prefix. I can't seem to inspect those variables, which appear to be pointer types, with the gdb print command. It complains that they are not in the current context.

I'm fairly certain that the Go extensions are loaded into GDB because I see the "Loading Go Runtime support" message and the $len and $cap seem to work.

Anybody else having gdb problems with Go?

Thanks,
Chris

Chris McGee

unread,
Aug 16, 2013, 11:38:32 PM8/16/13
to golan...@googlegroups.com
I found this recent thread on the topic of gdb:


It seems that heap allocated objects will show up in gdb "info locals" with the ampersand but gdb has no way to print variables with the ampersand in it.

I tried printing a heap allocated string by printing the dereferenced address like this:

print *0xc200098940

However, it seems to think that the destination is an integer or long:

$2 = -4323

Is there any way to get the value of this string?

Thanks,
Chris

Ian Lance Taylor

unread,
Aug 17, 2013, 2:33:45 PM8/17/13
to Chris McGee, golang-nuts
On Fri, Aug 16, 2013 at 2:12 PM, Chris McGee <newt...@gmail.com> wrote:
> I'm running into another problem. Whenever I inspect the local variables
> using "info locals" I'm seeing certain variables with a '&' prefix. I can't
> seem to inspect those variables, which appear to be pointer types, with the
> gdb print command. It complains that they are not in the current context.

Print them using back quotes in gdb:

print '&varname'

The backquotes tell gdb that the & is part of the name of the
variable, not the unary & operator. Of course &varname will hold the
pointer to the variable, so to see the real value you will want

print *'&varname'

Ian

Chris McGee

unread,
Aug 17, 2013, 2:51:32 PM8/17/13
to golan...@googlegroups.com, Chris McGee
Using the single quotes did the trick, even in the gdb MI.

Thank you,
Chris

Aaron Johnson

unread,
Sep 3, 2013, 3:59:16 PM9/3/13
to golan...@googlegroups.com
Chris,

I'm having the same problems you experienced.  I'm glad to hear that it's not just my own incompetence getting in the way here.

I'm relatively new to gdb, especially using it with go binaries.  I've been reading through the gdb manual to make sure that I wasn't just experiencing some subtle nuance of the 'next' command, but none of my RTFM-ing so far has turned up anything useful.

My setup:
  • uname -a
    • Linux ajvb 3.2.0-52-generic #78-Ubuntu SMP Fri Jul 26 16:21:44 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
  • go -version
    • go version go1.1 linux/amd64
  • gnu --version
    • GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04

I have a function that uses the Get method of a net/http Client to get several URLs.  Apparently Get creates a new thread (or two, or three; I don't know when/why they are created.)  When I 'next' over the function that makes the calls to Get, I experience the same unintended 'continue' effect that you described and I lose control over execution.  The program works its merry way through to the very end.

Did you ever find a way to solve this?  As you suggested, I've been working around this with some defensive breakpointing.  It works, but it's fairly tedious sometimes.

For anyone else that might be interested, here's a small demo program that reproduces the behavior.  Build it with -gcflags "-N -l", and set a breakpoint at main.main.  'next' your way over the first getUrl, and you will (hopefully) lose control of execution.

--------------------------------------------------------------------------
package main

import (
    "log"
    "net/http"
)

var client http.Client

func main() {
    getUrl("http://www.google.com")
    getUrl("http://en.wikipedia.org")
    getUrl("http://www.msn.com")
    getUrl("http://www.yahoo.com")
    getUrl("http://ruprecht.com")
    getUrl("http://www.about.com")
}

func getUrl(url string) {
    log.Printf("Getting %v ...\n", url)
    resp, err := client.Get(url)
    if err != nil {
        log.Printf("Get => %v\n", err.Error())
    }
    defer resp.Body.Close()
}
---------------------------------------------------------------------------

Output from this program on my machine is the following:

Breakpoint 1, main.main ()
    at /home/aaron/.../test.go:10
10    func main() {
(gdb) n
11        makeCall("http://www.google.com")
(gdb) n
2013/09/03 13:45:25 Getting http://www.google.com ...
[New Thread 0x7fffe6ff1700 (LWP 20630)]
[New Thread 0x7fffe67f0700 (LWP 20631)]
2013/09/03 13:45:26 Getting http://en.wikipedia.org ...
2013/09/03 13:45:27 Getting http://www.msn.com ...
[New Thread 0x7fffe57bb700 (LWP 20632)]
2013/09/03 13:45:27 Getting http://www.yahoo.com ...
2013/09/03 13:45:28 Getting http://ruprecht.com ...
2013/09/03 13:45:30 Getting http://www.about.com ...
[Thread 0x7fffe57bb700 (LWP 20632) exited]
[Thread 0x7fffe67f0700 (LWP 20631) exited]
[Thread 0x7fffe6ff1700 (LWP 20630) exited]
[Thread 0x7ffff7fdd700 (LWP 20626) exited]
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
[Inferior 1 (process 20626) exited normally]
(gdb)

Chris McGee

unread,
Sep 4, 2013, 8:46:38 PM9/4/13
to golan...@googlegroups.com
I got as far as trying to use the special goroutine command to do the next (eg. "(gdb) goroutine 1 next") but the special command is read only and doesn't support execution commands.

I was thinking that a special next command (eg. gonext) could set the breakpoint to the next line and continue but it won't work in all cases.

Chris

Reply all
Reply to author
Forward
0 new messages