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)
3.dlv debug 常用命令
- b 打断点,例如使用
b main.main
来打断点 - p 打印变量
- n: 执行到下一行
- c: 跳过此断点
- args: 打印所有的方法参数
- locals 打印出所有的本地变量
- l 列出断点最近几行的代码
- bp: 展示出所有的断点
- q: 退出