Contents
gc vs. gccgo
There are two compilers: gc and gccgo
Packages like Docker require the most recent version of Go - 1.4.2, for gccgo available only since gcc-5.0 (Fedora 22).
Current Python pretty printers + helper commands /usr/lib/golang/src/runtime/runtime-gdb.py work only partially now:
- written for old/incompatible PythonGDB API
- written for old/incompatible gc
- incompatible with gccgo
Go Delve Debugger
Delve is written in Go based on DWARF information. Therefore it suffers the same debug info problems like GDB. It cannot walk the stack frames.
break|b - Set break point at the entry point of a function, continue|c - Run until breakpoint or program termination. step|si - Single step through program. next|n - Step over to next source line. threads - Print out info for every traced thread. clear - Deletes breakpoint. goroutines - Print out info for every goroutine. print|p - Evaluate a variable. info - Provides info about source, locals, args, or funcs.
-O0 -g
gccgo features debugger-friendly mode by: -O0 -g
gc can reduce some optimizations by: go build -gcflags '-N -l'
flag -N' currently cannot be used due to: runtime.atomicstorep: nosplit stack overflow
Pretty Printing
Maps
gccgo - missing DWARF:
(gdb) p *state $5 = {__descriptor = 0x496480 <__go_map_MN3_int__N3_int>, __element_count = 4, __bucket_count = 5, __buckets = 0xc2080141e0} (gdb) ptype state.__buckets type = void **
gc - compatible with #gc runtime-gdb.py Bug:
(gdb) p state $2 = map[int]int = {[0]= 85, [2]= 10}
But typedef-ed (type in Go) types do not get recognized by GDB.
Channels
Maybe provide an xmethod to access channel’s goroutine?
gccgo - missing DWARF:
(gdb) p reads $1 = (__go_channel **) 0xc208006060 (gdb) p **reads $2 = {<No data fields>} DW_TAG_structure_type: DW_AT_byte_size: 0
gc - incompatible runtime-gdb.py + wrong DWARF for key (it is integer while it should be pointer to integer):
(gdb) p ’&reads’ $1 = (chan *main.readOp *) 0xc208048018 (gdb) ptype ’&reads’ type = struct hchan<*main.readOp> { (gdb) p *((*’&reads’).sendq.first[0]).elem $6 = {key = 833357914640, resp = 0xc20803e120} (gdb) x/gx ((*’&reads’).sendq.first[0]).elem.key 0xc20800a210: 0x0000000000000002 (gdb) p **(struct ’hchan<*main.readOp>’ **)’&reads’ $13 = struct hchan<*main.readOp>
gc Missing CFI
gccgo works OK.
gc has no .cfi_* or .eh_frame/.debug_frame support
assembler from 'Plan 9': /usr/lib/golang/pkg/tool/linux_amd64/6a
linker from 'Plan 9': /usr/lib/golang/pkg/tool/linux_amd64/6l
(gdb) bt #0 runtime.rt0_go () at /usr/lib/golang/src/runtime/asm_am #1 0x3424e1ffe0 in __libc_start_main (main=0x4489c0 <main> fini=<optimized out>, rtld_fini=<optimized out>, stack_ #2 0x403659 in _start () (gdb) bt #0 runtime.epollwait () at /usr/lib/golang/src/runtime/sys #1 0x41c353 in runtime.netpoll (block=true, gp=0x0) at /us [...] #7 0x43bdf4 in runtime.mstart () at /usr/lib/golang/src/ru #8 0x445e4c in runtime.rt0_go () at /usr/lib/golang/src/ru #9 0x3 in ?? ()
(gdb) bt #0 crosscall_amd64 () at /builddir/build/BUILD/go/src/runt #1 0x404513 in threadentry (v=<optimized out>) at /builddi #2 0x342560752a in start_thread (arg=0x7ffff7e2f700) at pt #3 0x3424f0079d in clone () at ../sysdeps/unix/sysv/linux/ (gdb) bt #0 runtime.futex () at /usr/lib/golang/src/runtime/sys_lin [...] #6 0x43bdf4 in runtime.mstart () at /usr/lib/golang/src/ru #7 0x404753 in crosscall_amd64 () at /builddir/build/BUILD #8 0x7ffff7e2f9c0 in ?? () ??? #13 0x43bd50 in runtime.starttheworld () at /usr/lib/golang #14 0x7ffff7e2f700 in ?? () ???
- Possible CFI fixes:
Implement .cfi_* into Go assembler.
Write .eh_frame as a relocated section.
Implement gc-specific GDB frame sniffer either hard-coded arch+function+offset in .c or a command: set unwind i386:x86-64 runtime.goexit 112
Switch to gccgo.
gc Wrong DW_TAG_variable
docker-1.4.1/daemon/daemon.go func NewDaemonFromDirectory(config *Config, eng *engine.E config.Root = realRoot
gccgo - correct:
(gdb) p config.Root $1 = 0xc208001170 "/var/lib/docker"
gc - incorrect:
(gdb) p '&config'.Root $2 = 0xc208159b10 "/var/lib/docker" DW_TAG_subprogram: DW_TAG_variable: DW_AT_name: &config
Missing Modules/Namespaces
No DW_TAG_imported_* anywhere:
docker-1.4.1/daemon/graphdriver/driver.go var ( DefaultDriver string docker-1.4.1/daemon/daemon.go import ( "github.com/docker/docker/daemon/graphdriver" graphdriver.DefaultDriver = config.GraphDriver ^^^^^^^^^^^^^^^^^^^^^^^^^
gccgo:
(gdb) p 'github_com_docker_docker_daemon_graphdriver.DefaultDriver' $4 = 0xc9d1a4 "" DW_TAG_compile_unit: DW_TAG_variable: DW_AT_name: graphdriver.DefaultDriver DW_AT_linkage_name: github_com_docker_docker_daemon_graphdriver.Defaul .symtab: github_com_docker_docker_daemon_graphdriver.DefaultDriver
gc:
(gdb) p 'github.com/docker.docker.daemon/graphdriver.DefaultDriver' $6 = 0x0 "" DW_TAG_compile_unit: DW_TAG_variable: DW_AT_name: github.com/docker.docker.daemon/graphdriver.DefaultDriver .symtab: github.com/docker.docker.daemon/graphdriver.DefaultDriver
Fedora Packaging
Split DWARF to *-debuginfo.rpm - currently it is embedded: %global debug_package %{nil}
- Provide build-ids, current build-id workaround:
# *** ERROR: No build ID note found in /.../BUILDROOT/etcd-2.0.0-1.rc1.fc22.x86_64/usr/bin/etcd # build-id gets later regenerated by debugedit. function gobuild { go build -a -ldflags "-B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n')" -v -x "$@"; }
gccgo Bug
gccgo overrides gc by default, see: alternatives --display go
Use: alternatives --set go /usr/lib/golang/bin/linux_amd64/go
gc runtime-gdb.py Bug
info goroutines, goroutine commands and Maps pretty printer fix:
gc variable references Bug
Fix #gc Wrong DW_TAG_variable; not completely clean fix:
gc downloaded testsuite Bug
gc fails to rebuild outside of mock.
dockerinit Bug
Docker is not packageable as it contains embedded checksum of /usr/libexec/docker/dockerinit binary. This prevents debuginfo splitting and also prelink.
DWZ Bug
DWZ will crash on gc-produced binaries. This does not prevent the packages to be built, just the DWZ optimization is not applied.
dwz: dwz.c:1984: checksum_die: Assertion `((!(multifile_mode & MULTIFILE_MODE_OP) && !(multifile_mode & MULTIFILE_MODE_RD) && !(multifile_mode & MULTIFILE_MODE_FI)) || cu != die_cu (ref)) && (!(multifile_mode & MULTIFILE_MODE_OP) || cu->cu_chunk == die_cu (ref)->cu_chunk)' failed.
At least a reduced level of DWZ optimization can be achieved by:
# https://bugzilla.redhat.com/show_bug.cgi?id=995136#c12 %global _dwz_low_mem_die_limit 0
debugedit Bug
Filenames of source files are invalid in *-debuginfo.rpm, they are not rewritten into /usr/src/debug/** subdirectory.
TODO list for gc in Fedora
Critical path:
#debugedit Bug - done, not yet accepted
#gc runtime-gdb.py Bug - 50% done, nothing accepted yet
#gc variable references Bug - done, a bit hacky, not yet accepted
#Channels - channels pretty printer in runtime-gdb.py
interfaces pretty printer fix in runtime-gdb.py
Optional TODOs:
GDB frame sniffer for #gc Missing CFI
- Make build-id default for compilations by Fedora gc
#dockerinit Bug: Remove dockerinit checksum so that docker has its *-debuginfo.rpm.