1.dlv 简介
• dlv(delve 的简写) 是一个用于 Go 源代码级调试器。
• dlv 通过控制进程的执行、计算变量、提供线程/协程的状态、CPU寄存器状态等信息,可以方便地与程序进行交互。
• 这个工具的目标是为调试 Go 程序提供一个简单但功能强大的界面。
• dlv 将标志传递给正在调试的程序,例如:
dlv exec ./hello -- server --config conf/config.toml
• macOs 使用 brew install dlv 命令下载安装即可。
2.dlv 调试代码
2.1 dlv 剖析 strings.Contains 函数
新建 a.go 文件,文件内容如下:
package main
import (
"fmt"
"strings"
)
func main() {
str := "Go语言是世界上最好的语言"
if strings.Contains(str,"世界") {
fmt.Println("字符串中包含","世界")
}else {
fmt.Println("字符串中不包含","世界")
}
}
使用 dlv debug a.go 命令可以开始对上述代码进行断点调试:
qinshixian@qinshixiandeMacBook-Pro qinshixian % dlv debug a.go
Type 'help' for list of commands.
(dlv) b main.main
Breakpoint 1 set at 0x10acd6f for main.main() ./a.go:8
(dlv) c
main.main() ./a.go:8 (hits goroutine(1):1 total:1) (PC: 0x10acd6f)
3: import (
4: "fmt"
5: "strings"
6: )
7:
=> 8: func main() {
9: str := "Go语言是世界上最好的语言"
10: if strings.Contains(str,"世界") {
11: fmt.Println("字符串中包含","世界")
12: }else {
13: fmt.Println("字符串中不包含","世界")
(dlv) n
main.main() ./a.go:9 (PC: 0x10acd86)
4: "fmt"
5: "strings"
6: )
7:
8: func main() {
=> 9: str := "Go语言是世界上最好的语言"
10: if strings.Contains(str,"世界") {
11: fmt.Println("字符串中包含","世界")
12: }else {
13: fmt.Println("字符串中不包含","世界")
14: }
(dlv) n
main.main() ./a.go:10 (PC: 0x10acd9b)
5: "strings"
6: )
7:
8: func main() {
9: str := "Go语言是世界上最好的语言"
=> 10: if strings.Contains(str,"世界") {
11: fmt.Println("字符串中包含","世界")
12: }else {
13: fmt.Println("字符串中不包含","世界")
14: }
15: }
(dlv) p str
"Go语言是世界上最好的语言"
(dlv) s strings.Contains
strings.Contains() /Users/qinshixian/.g/go/src/strings/strings.go:61 (PC: 0x10ac1e6)
56: s = s[i+len(substr):]
57: }
58: }
59:
60: // Contains reports whether substr is within s.
=> 61: func Contains(s, substr string) bool {
62: return Index(s, substr) >= 0
63: }
64:
65: // ContainsAny reports whether any Unicode code points in chars are within s.
66: func ContainsAny(s, chars string) bool {
(dlv) n
strings.Contains() /Users/qinshixian/.g/go/src/strings/strings.go:62 (PC: 0x10ac20d)
57: }
58: }
59:
60: // Contains reports whether substr is within s.
61: func Contains(s, substr string) bool {
=> 62: return Index(s, substr) >= 0
63: }
64:
65: // ContainsAny reports whether any Unicode code points in chars are within s.
66: func ContainsAny(s, chars string) bool {
67: return IndexAny(s, chars) >= 0
(dlv) b Contains
Breakpoint 2 set at 0x10ac1e6 for strings.Contains() /Users/qinshixian/.g/go/src/strings/strings.go:61
(dlv) p s
"Go语言是世界上最好的语言"
(dlv) p substr
"世界"
(dlv) s Index
strings.Index() /Users/qinshixian/.g/go/src/strings/strings.go:1024 (PC: 0x10ac32f)
1019: // One string is empty. Are both?
1020: return s == t
1021: }
1022:
1023: // Index returns the index of the first instance of substr in s, or -1 if substr is not present in s.
=>1024: func Index(s, substr string) int {
1025: n := len(substr)
1026: switch {
1027: case n == 0:
1028: return 0
1029: case n == 1:
(dlv) n
strings.Index() /Users/qinshixian/.g/go/src/strings/strings.go:1025 (PC: 0x10ac36f)
1020: return s == t
1021: }
1022:
1023: // Index returns the index of the first instance of substr in s, or -1 if substr is not present in s.
1024: func Index(s, substr string) int {
=>1025: n := len(substr)
1026: switch {
1027: case n == 0:
1028: return 0
1029: case n == 1:
1030: return IndexByte(s, substr[0])
(dlv) n
strings.Index() /Users/qinshixian/.g/go/src/strings/strings.go:1027 (PC: 0x10ac380)
1022:
1023: // Index returns the index of the first instance of substr in s, or -1 if substr is not present in s.
1024: func Index(s, substr string) int {
1025: n := len(substr)
1026: switch {
=>1027: case n == 0:
1028: return 0
1029: case n == 1:
1030: return IndexByte(s, substr[0])
1031: case n == len(s):
1032: if substr == s {
(dlv) p n
6
(dlv) p len(s)
35
(dlv) n
strings.Index() /Users/qinshixian/.g/go/src/strings/strings.go:1029 (PC: 0x10ac3a4)
1024: func Index(s, substr string) int {
1025: n := len(substr)
1026: switch {
1027: case n == 0:
1028: return 0
=>1029: case n == 1:
1030: return IndexByte(s, substr[0])
1031: case n == len(s):
1032: if substr == s {
1033: return 0
1034: }
(dlv) n
strings.Index() /Users/qinshixian/.g/go/src/strings/strings.go:1031 (PC: 0x10ac403)
1026: switch {
1027: case n == 0:
1028: return 0
1029: case n == 1:
1030: return IndexByte(s, substr[0])
=>1031: case n == len(s):
1032: if substr == s {
1033: return 0
1034: }
1035: return -1
1036: case n > len(s):
(dlv)
strings.Index() /Users/qinshixian/.g/go/src/strings/strings.go:1036 (PC: 0x10ac494)
1031: case n == len(s):
1032: if substr == s {
1033: return 0
1034: }
1035: return -1
=>1036: case n > len(s):
1037: return -1
1038: case n <= bytealg.MaxLen:
1039: // Use brute force when s and substr both are small
1040: if len(s) <= bytealg.MaxBruteForce {
1041: return bytealg.IndexString(s, substr)
(dlv) n
strings.Index() /Users/qinshixian/.g/go/src/strings/strings.go:1038 (PC: 0x10ac4cf)
1033: return 0
1034: }
1035: return -1
1036: case n > len(s):
1037: return -1
=>1038: case n <= bytealg.MaxLen:
1039: // Use brute force when s and substr both are small
1040: if len(s) <= bytealg.MaxBruteForce {
1041: return bytealg.IndexString(s, substr)
1042: }
1043: c0 := substr[0]
(dlv) p bytealg.MaxLen
63
(dlv) n
strings.Index() /Users/qinshixian/.g/go/src/strings/strings.go:1040 (PC: 0x10ac4e7)
1035: return -1
1036: case n > len(s):
1037: return -1
1038: case n <= bytealg.MaxLen:
1039: // Use brute force when s and substr both are small
=>1040: if len(s) <= bytealg.MaxBruteForce {
1041: return bytealg.IndexString(s, substr)
1042: }
1043: c0 := substr[0]
1044: c1 := substr[1]
1045: i := 0
(dlv) p len(s)
35
(dlv) p bytealg.MaxBruteForce
64
(dlv) n
strings.Index() /Users/qinshixian/.g/go/src/strings/strings.go:1041 (PC: 0x10ac4ff)
1036: case n > len(s):
1037: return -1
1038: case n <= bytealg.MaxLen:
1039: // Use brute force when s and substr both are small
1040: if len(s) <= bytealg.MaxBruteForce {
=>1041: return bytealg.IndexString(s, substr)
1042: }
1043: c0 := substr[0]
1044: c1 := substr[1]
1045: i := 0
1046: t := len(s) - n + 1
(dlv) s bytealg.IndexString
internal/bytealg.IndexString() /Users/qinshixian/.g/go/src/internal/bytealg/index_amd64.s:18 (PC: 0x1002840)
Warning: debugging optimized function
13: MOVQ DI, R10
14: LEAQ ret+48(FP), R11
15: JMP indexbody<>(SB)
16:
17: TEXT ·IndexString(SB),NOSPLIT,$0-40
=> 18: MOVQ a_base+0(FP), DI
19: MOVQ a_len+8(FP), DX
20: MOVQ b_base+16(FP), R8
21: MOVQ b_len+24(FP), AX
22: MOVQ DI, R10
23: LEAQ ret+32(FP), R11
(dlv) bp
Breakpoint runtime-fatal-throw (enabled) at 0x1032e20 for runtime.throw() /Users/qinshixian/.g/go/src/runtime/panic.go:1188 (0)
Breakpoint unrecovered-panic (enabled) at 0x1033180 for runtime.fatalpanic() /Users/qinshixian/.g/go/src/runtime/panic.go:1271 (0)
print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0x10acd6f for main.main() ./a.go:8 (1)
Breakpoint 2 (enabled) at 0x10ac1e6 for strings.Contains() /Users/qinshixian/.g/go/src/strings/strings.go:61 (0)
(dlv)
//代码效果参考:http://www.mwgw.cn/sitemap/post.xml
3.dlv debug 常用命令
• b 打断点,例如使用 b main.main 来打断点
• p 打印变量
• n: 执行到下一行
• c: 跳过此断点
• args: 打印所有的方法参数
• locals 打印出所有的本地变量
• l 列出断点最近几行的代码
• bp: 展示出所有的断点
• q: 退出