mirror of
https://github.com/golang/go
synced 2024-11-23 17:10:03 -07:00
documentation: Debugging Go code with GDB tutorial.
R=adg, cw, lvd CC=golang-dev https://golang.org/cl/5168046
This commit is contained in:
parent
5844fc1b21
commit
3e26862c1a
479
doc/debugging_with_gdb.html
Normal file
479
doc/debugging_with_gdb.html
Normal file
@ -0,0 +1,479 @@
|
||||
<!-- title Debugging Go Code with GDB -->
|
||||
|
||||
<p><i>
|
||||
This applies to the 6g toolchain. 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>
|
||||
|
||||
<h2 id="Introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
When you compile and link your Go programs with the 6g/6l or 8g/8l toolchains
|
||||
on Linux, Mac OSX or FreeBSD, 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>'-s'</code> flag to the linker to omit the debug information.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="Common_Operations">Common Operations</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Show file and line number for code
|
||||
and set breakpoints:
|
||||
<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>
|
||||
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/pkg/runtime/runtime-gdb.py">src/pkg/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/ld/dwarf.c">src/cmd/ld/dwarf.c</a>) ensures are described in
|
||||
the DWARF code.
|
||||
</ines
|
||||
|
||||
<p>
|
||||
If you're interested in what the debugging information looks like, run
|
||||
'<code>objdump -W 6.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/pkg/regexp</code> and run <code>gotest</code>.
|
||||
This should produce an executable file named <code>6.out</code>.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="Getting_Started">Getting Started</h3>
|
||||
|
||||
<p>
|
||||
Launch GDB, debugging <code>6.out</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gdb 6.out</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/pkg/regexp/6.out...
|
||||
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/pkg/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 6.out -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/pkg/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>doParse</code> method is known as
|
||||
<code>'regexp.*Regexp.doParse'</code>. (Note that the second dot is a "middot,"
|
||||
an artifact of Go’s internal representation of methods.)
|
||||
</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/pkg/regexp/find_test.go, line 148.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Run the program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>run</b>
|
||||
Starting program: /home/lvd/g/src/pkg/regexp/6.out
|
||||
|
||||
Breakpoint 1, regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/pkg/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/pkg/regexp/find_test.go:148
|
||||
#1 0x000000000042f60b in testing.tRunner (t=0xf8404a89c0, test=0x573720) at /home/user/go/src/pkg/testing/testing.go:156
|
||||
#2 0x000000000040df64 in runtime.initdone () at /home/user/go/src/pkg/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/lvd/g/src/pkg/runtime/proc.c:873
|
||||
#1 0x00000000004031c9 in runtime.chanrecv (c=void, ep=void, selected=void, received=void)
|
||||
at /home/lvd/g/src/pkg/runtime/chan.c:342
|
||||
#2 0x0000000000403299 in runtime.chanrecv1 (t=void, c=void) at/home/lvd/g/src/pkg/runtime/chan.c:423
|
||||
#3 0x000000000043075b in testing.RunTests (matchString={void (struct string, struct string, bool *, os.Error *)} 0x7ffff7f9ef60, tests= []testing.InternalTest = {...}) at /home/lvd/g/src/pkg/testing/testing.go:201
|
||||
#4 0x00000000004302b1 in testing.Main (matchString={void (struct string, struct string, bool *, os.Error *)} 0x7ffff7f9ef80, tests= []testing.InternalTest = {...}, benchmarks= []testing.InternalBenchmark = {...})
|
||||
at /home/lvd/g/src/pkg/testing/testing.go:168
|
||||
#5 0x0000000000400dc1 in main.main () at /home/lvd/g/src/pkg/regexp/_testmain.go:98
|
||||
#6 0x00000000004022e7 in runtime.mainstart () at /home/lvd/g/src/pkg/runtime/amd64/asm.s:78
|
||||
#7 0x000000000040ea6f in runtime.initdone () at /home/lvd/g/src/pkg/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/lvd/g/src/pkg/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 represntation of a channel. It is currently empty, or gdb would have pretty-printed it's 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/lvd/g/src/pkg/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>
|
||||
(gdb) bt
|
||||
#0 regexp.(*Regexp).String (re=0xf84068d070, noname=void)
|
||||
at /home/lvd/g/src/pkg/regexp/regexp.go:97
|
||||
#1 0x0000000000425615 in regexp.TestFind (t=0xf840688b60)
|
||||
at /home/lvd/g/src/pkg/regexp/find_test.go:151
|
||||
#2 0x0000000000430233 in testing.tRunner (t=0xf840688b60, test=0x5747b8)
|
||||
at /home/lvd/g/src/pkg/testing/testing.go:156
|
||||
#3 0x000000000040ea6f in runtime.initdone () at /home/lvd/g/src/pkg/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>
|
@ -188,6 +188,11 @@ one goroutine can be guaranteed to observe values produced by writes to the
|
||||
same variable in a different goroutine.
|
||||
</p>
|
||||
|
||||
<h3 id="debugging_with_gdb"><a href="debugging_with_gdb.html">Debugging Go Code with GDB</a></h3>
|
||||
<p>
|
||||
Using GDB to debug Go programs.
|
||||
</p>
|
||||
|
||||
<h2 id="videos_talks">Videos and Talks</h2>
|
||||
|
||||
<h3 id="writing_web_apps"><a href="http://www.youtube.com/watch?v=-i0hat7pdpk">Writing Web Apps in Go</a></h3>
|
||||
|
Loading…
Reference in New Issue
Block a user