Delve目的就是为了解决开发者在使用 GDB 调试中遇到的各种各样的问题。我们开始详细的介绍一些使用Delve 调试代码的例子。
安装首先默认你已经安装了 Go 环境,安装命令很简单,一句话。
go install github.com/go-delve/delve/cmd/dlv
GO15VENDOREXPERIMENT=1
调试代码
dlv
package main
import (
"fmt"
"sync"
"time"
)
func dostuff(wg *sync.WaitGroup, i int) {
fmt.Printf("goroutine id %d\n", i)
time.Sleep(300 * time.Second)
fmt.Printf("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 dostuff(&wg, i)
}
wg.Wait()
}
goroutinegoroutineDelvegoroutine
dlv debug test-debug.go
attachdebug session
首先我们在main函数上设置一个断点。
(dlv) break main.main
Breakpoint 1 set at 0x22d3 for main.main() ./test-debug.go:16
continue
(dlv) continue
> main.main() ./test-debug.go:16 (hits goroutine(1):1 total:1) (PC: 0x22d3)
11: time.Sleep(300 * time.Second)
12: fmt.Printf("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)
next
(dlv) next
> main.main() ./test-debug.go:17 (PC: 0x22d7)
12: fmt.Printf("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 dostuff(&wg, i)
(dlv)
> main.main() ./test-debug.go:18 (PC: 0x22f1)
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 dostuff(&wg, i)
23: }
(dlv)
> main.main() ./test-debug.go:20 (PC: 0x22fa)
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 dostuff(&wg, i)
23: }
24: wg.Wait()
25: }
(dlv)
print
(dlv) print wg
sync.WaitGroup {
state1: [12]uint8 [0,0,0,0,0,0,0,0,0,0,0,0],
sema: 0,}
(dlv) print workers
10
(dlv)
同时你也可以输出一个表达式
(dlv) print workers < 100
true
dostuff
(dlv) break dostuff
Breakpoint 2 set at 0x2058 for main.dostuff() ./test-debug.go:9
continuenext
(dlv) next
goroutine id 3
> main.dostuff() ./test-debug.go:10 (PC: 0x205f)
5: "sync"
6: "time"
7: )
8:
9: func dostuff(wg *sync.WaitGroup, i int) {
=> 10: fmt.Printf("goroutine id %d\n", i)
11: time.Sleep(300 * time.Second)
12: fmt.Printf("goroutine id %d\n", i)
13: wg.Done()
14: }
15:
(dlv)
可以看到Delve会告诉你目前的goroutine id,我们试试输出一下i和wg.
(dlv) print i
4
(dlv) print wg
*sync.WaitGroup {
state1: [12]uint8 [1,0,0,0,10,0,0,0,0,0,0,0],
sema: 0,}
我们创建了10个goroutine,如果你继续使用next,你会发现你还是在同一个goroutine下。这样就避免了被调试器跳转到了另外的goroutine下导致不必要的调试错误。可见还是为 Go 而生的调试器才是真爱啊。
进阶调试daemonattachattach
go build test-debug.go
./test-debug
然后使用ps查看正在运行的程序pid
501 40994 549 0 12:08AM ttys003 0:00.00 ./test-debug
attach
dlv attach 40994
debug seesion
(dlv) break dostuff
Breakpoint 1 set at 0x2058 for main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:9
(dlv) break dostuff:3
Breakpoint 2 set at 0x2144 for main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12
continue
(dlv) continue
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(18):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(19):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(26):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(23):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(24):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(20):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(21):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(25):1 total:8) (PC: 0x2144)
7: )
8:
9: func dostuff(wg *sync.WaitGroup, i int) {
10: fmt.Printf("goroutine id %d\n", i)
11: time.Sleep(300 * time.Second)
=> 12: fmt.Printf("goroutine id %d\n", i)
13: wg.Done()
14: }
15:
16: func main() {
17: var wg sync.WaitGroup
(dlv)
print
(dlv) print i
7
(dlv) print wg
*sync.WaitGroup {
state1: [12]uint8 [1,0,0,0,10,0,0,0,0,0,0,0],
sema: 0,}
attach