這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
首先需要注意的是:golang1.3之後的版本,對於支援gdb調試存在很大的問題。產生這個問題的原因是,golang的runtime沒有完整的被gdb支援。
最新比較完整支援gdb調試的版本是golang 1.2.2,但是也有個別問題存在。
為什麼會出現以上種種問題,golang官網給出的解釋是:
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.
翻譯一下:
GDB不能很好的理解GO程式。堆棧管理、線程和runtime包含了非常不一樣的執行模式,這不是GDB期望的,他們會擾亂調試器,即使go程式是使用gccgo編譯的。結果就是,雖然GDB在某些場合下是有用的,但是對go程式來說並不是一個可靠的調試器。尤其是在大量並發的時候。而且,這不是Golang項目優先考慮的事情,這很困難。總而言之,下面的操作手冊,只是當GDB正常工作的時候,引導你如何使用GDB,不能保證總是成功。
並且從google group討論群組和stackoverflow中,可以看到golang的多個版本對於GDB的支援都有這樣那樣的問題。不過既然官方的手冊都這麼說了,我們也只有在合適的場合使用GDB吧。
預設情況下,編譯過的二進位檔案已經包含了 DWARFv3 調試資訊,只要 GDB7.1 以上版本都可以進行調試。 在OSX下,如無法執行調試指令,可嘗試用sudo方式執行gdb。
在編譯go程式的時候,需要關閉內聯最佳化:** -gcflags “-N -l”**。可以在go get/build/test的時候指定這個參數。
有兩種方式可以下斷點:
- gdb命令運行之後,使用break file:lineno
- 使用runtime.BreakPoint()
示範環境:Ubuntu 14.04 LTS amd64 / Golang 1.2.2 / GDB 7.7
package mainimport ( "fmt" "runtime")func test(s string, x int) (r string) { r = fmt.Sprintf("test: %s %d", s, x) runtime.Breakpoint() return r}func main() { s := "haha" i := 1234 println(test(s, i))}
啟動GDB:
➜ ~ gdb ./testGNU gdb (Ubuntu 7.7-0ubuntu3) 7.7Copyright (C) 2014 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:.Find the GDB manual and other documentation resources online at:.For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from ./test...done.**Loading Go Runtime support.**(gdb)
以模組名的方式查看源碼:
(gdb) l main.main9 r = fmt.Sprintf("test: %s %d", s, x)10 runtime.Breakpoint()11 return r12 }1314 func main() {15 s := "haha"16 i := 123417 println(test(s, i))
以檔案名稱加行號的方式查看源碼:
(gdb) l /home/roy/test.go:11 package main23 import (4 "fmt"5 "runtime"6 )78 func test(s string, x int) (r string) {9 r = fmt.Sprintf("test: %s %d", s, x)10 runtime.Breakpoint()
設定斷點:
(gdb) b main.mainBreakpoint 2 at 0x400d80: file /home/roy/test.go, line 14.(gdb) b test.go:18Breakpoint 3 at 0x400e0e: file /home/roy/test.go, line 18.
啟動進程,觸發斷點:(n 逐步執行,c執行到下一個斷點)
(gdb) runStarting program: /home/roy/testBreakpoint 2, main.main () at /home/roy/test.go:1414 func main() {
查看goroutines:
(gdb) info goroutines* 1 running runtime.gosched* 2 syscall runtime.notetsleepg
查看指定goroutine的呼叫堆疊:
(gdb) goroutine 1 btPython Exception Cannot access memory at address 0x8:Error occurred in Python command: Cannot access memory at address 0x8
當我們想查看goroutine呼叫堆疊的時候,gdb報告無法訪問記憶體。Cannot access memory at address 0x8,這句是說無法訪問0x8位置的記憶體,所以接下來,gdb收到了一個SIGSEGV的訊號,說明觸發了段錯誤:
(gdb) nProgram received signal SIGSEGV, Segmentation fault.0x000000000041529b in runtime.gosched () at /home/roy/go/src/pkg/runtime/proc.c:13681368 runtime·mcall(runtime·gosched0);
此時,我們需要重啟gdb的調試,否則執行任何命令都會報告段錯誤。
列印棧幀資訊:
(gdb) info frameStack level 0, frame at 0x7ffff7e2ef48: rip = 0x400d80 in main.main (/home/roy/test.go:14); saved rip = 0x412e1f source language go. Arglist at 0x7ffff7e2ef38, args: Locals at 0x7ffff7e2ef38, Previous frame's sp is 0x7ffff7e2ef48 Saved registers: rip at 0x7ffff7e2ef40
查看局部變數:
(gdb) info localsi = 1234s = "haha"
以Pretty-Print的方式列印變數:
(gdb) p s$1 = "haha"
擷取對象的長度,即cap:
(gdb) p $len(s)$3 = 4
查看物件類型:
(gdb) whatis itype = int(gdb) whatis stype = struct string
輸入n逐步執行到進入test函數,查看傳遞給函數的參數:
(gdb) nmain.test (s="haha", x=1234, r="test: haha 1234") at /home/roy/test.go:1111 return r(gdb) info argss = "haha"x = 1234r = "test: haha 1234"
輸入q,或者Ctrl-D退出:
(gdb) qA debugging session is active. Inferior 1 [process 6079] will be killed.Quit anyway? (y or n) y