123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- <!--{
- "Title": "Debugging Go Code with GDB",
- "Path": "/doc/gdb"
- }-->
- <p><i>
- This applies to the standard toolchain (the <code>gc</code> Go
- compiler and tools). Gccgo has native gdb support.
- Besides this overview you might want to consult the
- <a href="http://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
- </i></p>
- <p>
- GDB does not understand Go programs well.
- The stack management, threading, and runtime contain aspects that differ
- enough from the execution model GDB expects that they can confuse
- the debugger, even when the program is compiled with gccgo.
- As a consequence, although GDB can be useful in some situations, it is
- not a reliable debugger for Go programs, particularly heavily concurrent ones.
- Moreover, it is not a priority for the Go project to address these issues, which
- are difficult.
- In short, the instructions below should be taken only as a guide to how
- to use GDB when it works, not as a guarantee of success.
- </p>
- <p>
- In time, a more Go-centric debugging architecture may be required.
- </p>
- <h2 id="Introduction">Introduction</h2>
- <p>
- When you compile and link your Go programs with the <code>gc</code> toolchain
- on Linux, Mac OS X, FreeBSD or NetBSD, the resulting binaries contain DWARFv3
- debugging information that recent versions (>7.1) of the GDB debugger can
- use to inspect a live process or a core dump.
- </p>
- <p>
- Pass the <code>'-w'</code> flag to the linker to omit the debug information
- (for example, <code>go build -ldflags "-w" prog.go</code>).
- </p>
- <p>
- The code generated by the <code>gc</code> compiler includes inlining of
- function invocations and registerization of variables. These optimizations
- can sometimes make debugging with <code>gdb</code> harder. To disable them
- when debugging, pass the flags <code>-gcflags "-N -l"</code> to the
- <a href="/cmd/go"><code>go</code></a> command used to build the code being
- debugged.
- </p>
- <p>
- If you want to use gdb to inspect a core dump, you can trigger a dump
- on a program crash, on systems that permit it, by setting
- <code>GOTRACEBACK=crash</code> in the environment (see the
- <a href="/pkg/runtime/#hdr-Environment_Variables"> runtime package
- documentation</a> for more info).
- </p>
- <h3 id="Common_Operations">Common Operations</h3>
- <ul>
- <li>
- Show file and line number for code, set breakpoints and disassemble:
- <pre>(gdb) <b>list</b>
- (gdb) <b>list <i>line</i></b>
- (gdb) <b>list <i>file.go</i>:<i>line</i></b>
- (gdb) <b>break <i>line</i></b>
- (gdb) <b>break <i>file.go</i>:<i>line</i></b>
- (gdb) <b>disas</b></pre>
- </li>
- <li>
- Show backtraces and unwind stack frames:
- <pre>(gdb) <b>bt</b>
- (gdb) <b>frame <i>n</i></b></pre>
- </li>
- <li>
- Show the name, type and location on the stack frame of local variables,
- arguments and return values:
- <pre>(gdb) <b>info locals</b>
- (gdb) <b>info args</b>
- (gdb) <b>p variable</b>
- (gdb) <b>whatis variable</b></pre>
- </li>
- <li>
- Show the name, type and location of global variables:
- <pre>(gdb) <b>info variables <i>regexp</i></b></pre>
- </li>
- </ul>
- <h3 id="Go_Extensions">Go Extensions</h3>
- <p>
- A recent extension mechanism to GDB allows it to load extension scripts for a
- given binary. The tool chain uses this to extend GDB with a handful of
- commands to inspect internals of the runtime code (such as goroutines) and to
- pretty print the built-in map, slice and channel types.
- </p>
- <ul>
- <li>
- Pretty printing a string, slice, map, channel or interface:
- <pre>(gdb) <b>p <i>var</i></b></pre>
- </li>
- <li>
- A $len() and $cap() function for strings, slices and maps:
- <pre>(gdb) <b>p $len(<i>var</i>)</b></pre>
- </li>
- <li>
- A function to cast interfaces to their dynamic types:
- <pre>(gdb) <b>p $dtype(<i>var</i>)</b>
- (gdb) <b>iface <i>var</i></b></pre>
- <p class="detail"><b>Known issue:</b> GDB can’t automatically find the dynamic
- type of an interface value if its long name differs from its short name
- (annoying when printing stacktraces, the pretty printer falls back to printing
- the short type name and a pointer).</p>
- </li>
- <li>
- Inspecting goroutines:
- <pre>(gdb) <b>info goroutines</b>
- (gdb) <b>goroutine <i>n</i> <i>cmd</i></b>
- (gdb) <b>help goroutine</b></pre>
- For example:
- <pre>(gdb) <b>goroutine 12 bt</b></pre>
- </li>
- </ul>
- <p>
- If you'd like to see how this works, or want to extend it, take a look at <a
- href="/src/runtime/runtime-gdb.py">src/runtime/runtime-gdb.py</a> in
- the Go source distribution. It depends on some special magic types
- (<code>hash<T,U></code>) and variables (<code>runtime.m</code> and
- <code>runtime.g</code>) that the linker
- (<a href="/src/cmd/link/internal/ld/dwarf.go">src/cmd/link/internal/ld/dwarf.go</a>) ensures are described in
- the DWARF code.
- </p>
- <p>
- If you're interested in what the debugging information looks like, run
- '<code>objdump -W a.out</code>' and browse through the <code>.debug_*</code>
- sections.
- </p>
- <h3 id="Known_Issues">Known Issues</h3>
- <ol>
- <li>String pretty printing only triggers for type string, not for types derived
- from it.</li>
- <li>Type information is missing for the C parts of the runtime library.</li>
- <li>GDB does not understand Go’s name qualifications and treats
- <code>"fmt.Print"</code> as an unstructured literal with a <code>"."</code>
- that needs to be quoted. It objects even more strongly to method names of
- the form <code>pkg.(*MyType).Meth</code>.
- <li>All global variables are lumped into package <code>"main"</code>.</li>
- </ol>
- <h2 id="Tutorial">Tutorial</h2>
- <p>
- In this tutorial we will inspect the binary of the
- <a href="/pkg/regexp/">regexp</a> package's unit tests. To build the binary,
- change to <code>$GOROOT/src/regexp</code> and run <code>go test -c</code>.
- This should produce an executable file named <code>regexp.test</code>.
- </p>
- <h3 id="Getting_Started">Getting Started</h3>
- <p>
- Launch GDB, debugging <code>regexp.test</code>:
- </p>
- <pre>
- $ <b>gdb regexp.test</b>
- GNU gdb (GDB) 7.2-gg8
- Copyright (C) 2010 Free Software Foundation, Inc.
- License GPLv 3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
- Type "show copying" and "show warranty" for licensing/warranty details.
- This GDB was configured as "x86_64-linux".
- Reading symbols from /home/user/go/src/regexp/regexp.test...
- done.
- Loading Go Runtime support.
- (gdb)
- </pre>
- <p>
- The message <code>"Loading Go Runtime support"</code> means that GDB loaded the
- extension from <code>$GOROOT/src/runtime/runtime-gdb.py</code>.
- </p>
- <p>
- To help GDB find the Go runtime sources and the accompanying support script,
- pass your <code>$GOROOT</code> with the <code>'-d'</code> flag:
- </p>
- <pre>
- $ <b>gdb regexp.test -d $GOROOT</b>
- </pre>
- <p>
- If for some reason GDB still can't find that directory or that script, you can load
- it by hand by telling gdb (assuming you have the go sources in
- <code>~/go/</code>):
- </p>
- <pre>
- (gdb) <b>source ~/go/src/runtime/runtime-gdb.py</b>
- Loading Go Runtime support.
- </pre>
- <h3 id="Inspecting_the_source">Inspecting the source</h3>
- <p>
- Use the <code>"l"</code> or <code>"list"</code> command to inspect source code.
- </p>
- <pre>
- (gdb) <b>l</b>
- </pre>
- <p>
- List a specific part of the source parametrizing <code>"list"</code> with a
- function name (it must be qualified with its package name).
- </p>
- <pre>
- (gdb) <b>l main.main</b>
- </pre>
- <p>
- List a specific file and line number:
- </p>
- <pre>
- (gdb) <b>l regexp.go:1</b>
- (gdb) <i># Hit enter to repeat last command. Here, this lists next 10 lines.</i>
- </pre>
- <h3 id="Naming">Naming</h3>
- <p>
- Variable and function names must be qualified with the name of the packages
- they belong to. The <code>Compile</code> function from the <code>regexp</code>
- package is known to GDB as <code>'regexp.Compile'</code>.
- </p>
- <p>
- Methods must be qualified with the name of their receiver types. For example,
- the <code>*Regexp</code> type’s <code>String</code> method is known as
- <code>'regexp.(*Regexp).String'</code>.
- </p>
- <p>
- Variables that shadow other variables are magically suffixed with a number in the debug info.
- Variables referenced by closures will appear as pointers magically prefixed with '&'.
- </p>
- <h3 id="Setting_breakpoints">Setting breakpoints</h3>
- <p>
- Set a breakpoint at the <code>TestFind</code> function:
- </p>
- <pre>
- (gdb) <b>b 'regexp.TestFind'</b>
- Breakpoint 1 at 0x424908: file /home/user/go/src/regexp/find_test.go, line 148.
- </pre>
- <p>
- Run the program:
- </p>
- <pre>
- (gdb) <b>run</b>
- Starting program: /home/user/go/src/regexp/regexp.test
- Breakpoint 1, regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/regexp/find_test.go:148
- 148 func TestFind(t *testing.T) {
- </pre>
- <p>
- Execution has paused at the breakpoint.
- See which goroutines are running, and what they're doing:
- </p>
- <pre>
- (gdb) <b>info goroutines</b>
- 1 waiting runtime.gosched
- * 13 running runtime.goexit
- </pre>
- <p>
- the one marked with the <code>*</code> is the current goroutine.
- </p>
- <h3 id="Inspecting_the_stack">Inspecting the stack</h3>
- <p>
- Look at the stack trace for where we’ve paused the program:
- </p>
- <pre>
- (gdb) <b>bt</b> <i># backtrace</i>
- #0 regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/regexp/find_test.go:148
- #1 0x000000000042f60b in testing.tRunner (t=0xf8404a89c0, test=0x573720) at /home/user/go/src/testing/testing.go:156
- #2 0x000000000040df64 in runtime.initdone () at /home/user/go/src/runtime/proc.c:242
- #3 0x000000f8404a89c0 in ?? ()
- #4 0x0000000000573720 in ?? ()
- #5 0x0000000000000000 in ?? ()
- </pre>
- <p>
- The other goroutine, number 1, is stuck in <code>runtime.gosched</code>, blocked on a channel receive:
- </p>
- <pre>
- (gdb) <b>goroutine 1 bt</b>
- #0 0x000000000040facb in runtime.gosched () at /home/user/go/src/runtime/proc.c:873
- #1 0x00000000004031c9 in runtime.chanrecv (c=void, ep=void, selected=void, received=void)
- at /home/user/go/src/runtime/chan.c:342
- #2 0x0000000000403299 in runtime.chanrecv1 (t=void, c=void) at/home/user/go/src/runtime/chan.c:423
- #3 0x000000000043075b in testing.RunTests (matchString={void (struct string, struct string, bool *, error *)}
- 0x7ffff7f9ef60, tests= []testing.InternalTest = {...}) at /home/user/go/src/testing/testing.go:201
- #4 0x00000000004302b1 in testing.Main (matchString={void (struct string, struct string, bool *, error *)}
- 0x7ffff7f9ef80, tests= []testing.InternalTest = {...}, benchmarks= []testing.InternalBenchmark = {...})
- at /home/user/go/src/testing/testing.go:168
- #5 0x0000000000400dc1 in main.main () at /home/user/go/src/regexp/_testmain.go:98
- #6 0x00000000004022e7 in runtime.mainstart () at /home/user/go/src/runtime/amd64/asm.s:78
- #7 0x000000000040ea6f in runtime.initdone () at /home/user/go/src/runtime/proc.c:243
- #8 0x0000000000000000 in ?? ()
- </pre>
- <p>
- The stack frame shows we’re currently executing the <code>regexp.TestFind</code> function, as expected.
- </p>
- <pre>
- (gdb) <b>info frame</b>
- Stack level 0, frame at 0x7ffff7f9ff88:
- rip = 0x425530 in regexp.TestFind (/home/user/go/src/regexp/find_test.go:148);
- saved rip 0x430233
- called by frame at 0x7ffff7f9ffa8
- source language minimal.
- Arglist at 0x7ffff7f9ff78, args: t=0xf840688b60
- Locals at 0x7ffff7f9ff78, Previous frame's sp is 0x7ffff7f9ff88
- Saved registers:
- rip at 0x7ffff7f9ff80
- </pre>
- <p>
- The command <code>info locals</code> lists all variables local to the function and their values, but is a bit
- dangerous to use, since it will also try to print uninitialized variables. Uninitialized slices may cause gdb to try
- to print arbitrary large arrays.
- </p>
- <p>
- The function’s arguments:
- </p>
- <pre>
- (gdb) <b>info args</b>
- t = 0xf840688b60
- </pre>
- <p>
- When printing the argument, notice that it’s a pointer to a
- <code>Regexp</code> value. Note that GDB has incorrectly put the <code>*</code>
- on the right-hand side of the type name and made up a 'struct' keyword, in traditional C style.
- </p>
- <pre>
- (gdb) <b>p re</b>
- (gdb) p t
- $1 = (struct testing.T *) 0xf840688b60
- (gdb) p t
- $1 = (struct testing.T *) 0xf840688b60
- (gdb) p *t
- $2 = {errors = "", failed = false, ch = 0xf8406f5690}
- (gdb) p *t->ch
- $3 = struct hchan<*testing.T>
- </pre>
- <p>
- That <code>struct hchan<*testing.T></code> is the
- runtime-internal representation of a channel. It is currently empty,
- or gdb would have pretty-printed its contents.
- </p>
- <p>
- Stepping forward:
- </p>
- <pre>
- (gdb) <b>n</b> <i># execute next line</i>
- 149 for _, test := range findTests {
- (gdb) <i># enter is repeat</i>
- 150 re := MustCompile(test.pat)
- (gdb) <b>p test.pat</b>
- $4 = ""
- (gdb) <b>p re</b>
- $5 = (struct regexp.Regexp *) 0xf84068d070
- (gdb) <b>p *re</b>
- $6 = {expr = "", prog = 0xf840688b80, prefix = "", prefixBytes = []uint8, prefixComplete = true,
- prefixRune = 0, cond = 0 '\000', numSubexp = 0, longest = false, mu = {state = 0, sema = 0},
- machine = []*regexp.machine}
- (gdb) <b>p *re->prog</b>
- $7 = {Inst = []regexp/syntax.Inst = {{Op = 5 '\005', Out = 0, Arg = 0, Rune = []int}, {Op =
- 6 '\006', Out = 2, Arg = 0, Rune = []int}, {Op = 4 '\004', Out = 0, Arg = 0, Rune = []int}},
- Start = 1, NumCap = 2}
- </pre>
- <p>
- We can step into the <code>String</code>function call with <code>"s"</code>:
- </p>
- <pre>
- (gdb) <b>s</b>
- regexp.(*Regexp).String (re=0xf84068d070, noname=void) at /home/user/go/src/regexp/regexp.go:97
- 97 func (re *Regexp) String() string {
- </pre>
- <p>
- Get a stack trace to see where we are:
- </p>
- <pre>
- (gdb) <b>bt</b>
- #0 regexp.(*Regexp).String (re=0xf84068d070, noname=void)
- at /home/user/go/src/regexp/regexp.go:97
- #1 0x0000000000425615 in regexp.TestFind (t=0xf840688b60)
- at /home/user/go/src/regexp/find_test.go:151
- #2 0x0000000000430233 in testing.tRunner (t=0xf840688b60, test=0x5747b8)
- at /home/user/go/src/testing/testing.go:156
- #3 0x000000000040ea6f in runtime.initdone () at /home/user/go/src/runtime/proc.c:243
- ....
- </pre>
- <p>
- Look at the source code:
- </p>
- <pre>
- (gdb) <b>l</b>
- 92 mu sync.Mutex
- 93 machine []*machine
- 94 }
- 95
- 96 // String returns the source text used to compile the regular expression.
- 97 func (re *Regexp) String() string {
- 98 return re.expr
- 99 }
- 100
- 101 // Compile parses a regular expression and returns, if successful,
- </pre>
- <h3 id="Pretty_Printing">Pretty Printing</h3>
- <p>
- GDB's pretty printing mechanism is triggered by regexp matches on type names. An example for slices:
- </p>
- <pre>
- (gdb) <b>p utf</b>
- $22 = []uint8 = {0 '\000', 0 '\000', 0 '\000', 0 '\000'}
- </pre>
- <p>
- Since slices, arrays and strings are not C pointers, GDB can't interpret the subscripting operation for you, but
- you can look inside the runtime representation to do that (tab completion helps here):
- </p>
- <pre>
- (gdb) <b>p slc</b>
- $11 = []int = {0, 0}
- (gdb) <b>p slc-></b><i><TAB></i>
- array slc len
- (gdb) <b>p slc->array</b>
- $12 = (int *) 0xf84057af00
- (gdb) <b>p slc->array[1]</b>
- $13 = 0</pre>
- <p>
- The extension functions $len and $cap work on strings, arrays and slices:
- </p>
- <pre>
- (gdb) <b>p $len(utf)</b>
- $23 = 4
- (gdb) <b>p $cap(utf)</b>
- $24 = 4
- </pre>
- <p>
- Channels and maps are 'reference' types, which gdb shows as pointers to C++-like types <code>hash<int,string>*</code>. Dereferencing will trigger prettyprinting
- </p>
- <p>
- Interfaces are represented in the runtime as a pointer to a type descriptor and a pointer to a value. The Go GDB runtime extension decodes this and automatically triggers pretty printing for the runtime type. The extension function <code>$dtype</code> decodes the dynamic type for you (examples are taken from a breakpoint at <code>regexp.go</code> line 293.)
- </p>
- <pre>
- (gdb) <b>p i</b>
- $4 = {str = "cbb"}
- (gdb) <b>whatis i</b>
- type = regexp.input
- (gdb) <b>p $dtype(i)</b>
- $26 = (struct regexp.inputBytes *) 0xf8400b4930
- (gdb) <b>iface i</b>
- regexp.input: struct regexp.inputBytes *
- </pre>
|