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.
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.
In time, a more Go-centric debugging architecture may be required.
于是作者调查发现目前市面上用的更多的是dlv调试,不仅支持gdb所有的功能,还对go routinue有很好的支持,大家知道调试的时候,单线程是最好调试的,dlv就有这样的优点,下面我们来看下怎么玩起来。
$ go get github.com/derekparker/delve/cmd/dlv
ps. 默认会安装到$GOPATH/src/github.com/下面
$ vim ~/.bash_profile
alias dlv="~/go/bin/dlv" (一般安装完了会在$GOPATH/bin下生成二进制可运行文件)
$ source ~/.bash_profile
$ dlv debug --help
,出现一些命令说明成功dlv.go
):package main
import (
"fmt"
"sync"
"time"
)
func doing(wg *sync.WaitGroup, i int) {
fmt.Printf("start goroutine id %d\n", i)
time.Sleep(2 * time.Second)
fmt.Printf("finish goroutine id %d\n", i)
wg.Done()
}
func main() {
var wg sync.WaitGroup
workers := 10
wg.Add(workers)
for i := 0; i < workers; i++ {
go doing(&wg, i)
}
wg.Wait()
}
$ dlv debug dlv.go
powerdeMBP:interface power$ dlv debug dlv.go
Type 'help' for list of commands.
(dlv)
(dlv) break main.main
Breakpoint 1 set at 0x10b27c3 for main.main() ./dlv.go:16
(dlv)
(dlv) continue
> main.main() ./dlv.go:16 (hits goroutine(1):1 total:1) (PC: 0x10b27c3)
11: time.Sleep(2 * time.Second)
12: fmt.Printf("finish goroutine id %d\n", i)
13: wg.Done()
14: }
15:
=> 16: func main() {
17: var wg sync.WaitGroup
18: workers := 10
19:
20: wg.Add(workers)
21: for i := 0; i < workers; i++ {
(dlv)
(dlv) next
> main.main() ./dlv.go:17 (PC: 0x10b27d1)
12: fmt.Printf("finish goroutine id %d\n", i)
13: wg.Done()
14: }
15:
16: func main() {
=> 17: var wg sync.WaitGroup
18: workers := 10
19:
20: wg.Add(workers)
21: for i := 0; i < workers; i++ {
22: go doing(&wg, i)
(dlv) next
> main.main() ./dlv.go:18 (PC: 0x10b27fa)
13: wg.Done()
14: }
15:
16: func main() {
17: var wg sync.WaitGroup
=> 18: workers := 10
19:
20: wg.Add(workers)
21: for i := 0; i < workers; i++ {
22: go doing(&wg, i)
23: }
(dlv) n
> main.main() ./dlv.go:20 (PC: 0x10b2803)
15:
16: func main() {
17: var wg sync.WaitGroup
18: workers := 10
19:
=> 20: wg.Add(workers)
21: for i := 0; i < workers; i++ {
22: go doing(&wg, i)
23: }
24: wg.Wait()
25:
(dlv) p workers
10
(dlv) break doing
Breakpoint 2 set at 0x10b2598 for main.doing() ./dlv.go:9
(dlv) c
> main.doing() ./dlv.go:9 (hits goroutine(10):1 total:4) (PC: 0x10b2598)
> main.doing() ./dlv.go:9 (hits goroutine(6):1 total:4) (PC: 0x10b2598)
> main.doing() ./dlv.go:9 (hits goroutine(5):1 total:4) (PC: 0x10b2598)
> main.doing() ./dlv.go:9 (hits goroutine(14):1 total:4) (PC: 0x10b2598)
4: "fmt"
5: "sync"
6: "time"
7: )
8:
=> 9: func doing(wg *sync.WaitGroup, i int) {
10: fmt.Printf("start goroutine id %d\n", i)
11: time.Sleep(2 * time.Second)
12: fmt.Printf("finish goroutine id %d\n", i)
13: wg.Done()
14: }
(dlv)
(dlv) n
> main.doing() ./dlv.go:10 (PC: 0x10b25af)
5: "sync"
6: "time"
7: )
8:
9: func doing(wg *sync.WaitGroup, i int) {
=> 10: fmt.Printf("start goroutine id %d\n", i)
11: time.Sleep(2 * time.Second)
12: fmt.Printf("finish goroutine id %d\n", i)
13: wg.Done()
14: }
15:
(dlv) p i
9
(dlv)
ps. 我们发现可以单独对其中一个go routinue进行调试,也就是可以在多线程中对某个线程(在go语言中应该叫协程),更棒的还在后面,dlv还能对运行之中的程序进行调试。
dlv.go
),将time.sleep设置大一些,这样有时间操作package main
import (
"fmt"
"sync"
"time"
)
func doing(wg *sync.WaitGroup, i int) {
fmt.Printf("start goroutine id %d\n", i)
// 这里设置大一些
time.Sleep(100 * time.Second)
fmt.Printf("finish goroutine id %d\n", i)
wg.Done()
}
func main() {
var wg sync.WaitGroup
workers := 10
wg.Add(workers)
for i := 0; i < workers; i++ {
go doing(&wg, i)
}
wg.Wait()
}
我们打开两个终端,一个用来运行,一个用来调试运行中的程序
第一个终端编译并且运行:
$ go build dlv.go && ./dlv
power:PKUChain power$ ps
PID TTY TIME CMD
15426 ttys000 0:00.00 ./dlv
attach
命令进入程序中进行调试:powerdeMBP:PKUChain power$ dlv attach 15426
Type 'help' for list of commands.
(dlv)
time.Sleep(100 * time.Second)
阻塞了,我们在这句话运行完之前在下面一行打好断点等待。(dlv) break doing:3
Breakpoint 1 set at 0x10931ff for main.doing() /Users/power/Desktop/my/go_learn/interface/dlv.go:12
(dlv) continue
> main.doing() /Users/power/Desktop/my/go_learn/interface/dlv.go:12 (hits goroutine(12):1 total:4) (PC: 0x10931ff)
Warning: debugging optimized function
> main.doing() /Users/power/Desktop/my/go_learn/interface/dlv.go:12 (hits goroutine(6):1 total:4) (PC: 0x10931ff)
Warning: debugging optimized function
> main.doing() /Users/power/Desktop/my/go_learn/interface/dlv.go:12 (hits goroutine(5):1 total:4) (PC: 0x10931ff)
Warning: debugging optimized function
> main.doing() /Users/power/Desktop/my/go_learn/interface/dlv.go:12 (hits goroutine(7):1 total:4) (PC: 0x10931ff)
Warning: debugging optimized function
7: )
8:
9: func doing(wg *sync.WaitGroup, i int) {
10: fmt.Printf("start goroutine id %d\n", i)
11: time.Sleep(100 * time.Second)
=> 12: fmt.Printf("finish goroutine id %d\n", i)
13: wg.Done()
14: }
15:
16: func main() {
17: var wg sync.WaitGroup
(dlv)
ps
. break (函数名): (函数第几行)
[1] go语言安装配置
[2] delve 官方文档