DLV
在 Go 编程语言中,DLV (Delve) 是一种用于调试 Go 代码的工具。DLV 是一个开源的调试器,它可以帮助开发者在编写和调试 Go 程序时识别和解决问题。以下是关于使用 DLV 进行 Go 代码调试的一些重要信息:
-
设置断点: 开发者可以在他们的 Go 代码中设置断点,以便在程序执行时停止并检查变量、堆栈跟踪和其他调试信息。
-
单步执行: DLV 允许用户逐行或逐过程地执行代码,以便一步一步地跟踪程序的执行流程。
-
查看变量: 开发者可以使用 DLV 查看当前执行上下文中的变量的值,以便了解程序的状态。
-
检查堆栈: DLV 允许用户查看当前函数的调用堆栈,以识别可能的错误或异常。
-
多线程调试: Go 支持并发编程,DLV 也可以用于调试多线程应用程序,以帮助解决并发问题。
-
远程调试: DLV 支持远程调试,这意味着您可以在远程服务器上调试运行中的 Go 代码。
-
集成编辑器: DLV 可以与一些流行的集成开发环境(IDE)和文本编辑器集成,例如 Visual Studio Code(VS Code)和 GoLand。
安装
使用install
安装,之后会安装在GOPATH
目录下
go install github.com/go-delve/delve/cmd/dlv
如果在/etc/profile
下设置了PATH
则可以直接使用,没有则需要设置全局变量
export PATH=$PATH:/c/Users/54225/go/bin/
运行
这里展示一个运行demo
#cat main.go
package main
import "fmt"
func main() {
i := []int{1, 2, 3, 4, 5, 6, 7, 8}
j := "this is dlv"
for _, v := range i {
fmt.Println(v)
}
fmt.Println(j)
}
执行debug
运行,执行完毕后就是这个样子,此时程序还没有被运行
$ dlv.exe debug ch19/main.go
Type 'help' for list of commands.
(dlv)
执行c
运行程序,发现程序立刻执行完毕了,这里的c
是命令call
简写
$ dlv.exe debug ch19/main.go
Type 'help' for list of commands.
(dlv) c
1
2
3
4
5
6
7
8
this is dlv
Process 20804 has exited with status 0
执行b
标记断点,断点表示执行到这边停顿
$ dlv.exe debug ch19/main.go
Type 'help' for list of commands.
(dlv) b main.go:5
Breakpoint 1 set at 0xf49812 for main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:5
在标记断点后,需要运行程序才可以触发断点
$ dlv.exe debug ch19/main.go
Type 'help' for list of commands.
(dlv) b main.go:5
Breakpoint 1 set at 0xf49812 for main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:5
(dlv) c
> main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:5 (hits goroutine(1):1 total:1) (PC: 0xf49812)
1: package main
2:
3: import "fmt"
4:
=> 5: func main() {
6: i := []int{1, 2, 3, 4, 5, 6, 7, 8}
7: j := "this is dlv"
8:
9: for _, v := range i {
10: fmt.Println(v)
显示在main.go
第5
行停顿,此时按n
继续
(dlv) n
> main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:6 (PC: 0xf49829)
1: package main
2:
3: import "fmt"
4:
5: func main() {
=> 6: i := []int{1, 2, 3, 4, 5, 6, 7, 8}
7: j := "this is dlv"
8:
9: for _, v := range i {
10: fmt.Println(v)
11: }
发现执行到下一行了,此时打印i
变量看看,发现没有找到这个变量,那是因为这一行没执行,需要到下一行打印才能生效
(dlv) p i
Command failed: could not find symbol value for i
在下一行打印生效了
(dlv) n
> main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:7 (PC: 0xf498dc)
2:
3: import "fmt"
4:
5: func main() {
6: i := []int{1, 2, 3, 4, 5, 6, 7, 8}
=> 7: j := "this is dlv"
8:
9: for _, v := range i {
10: fmt.Println(v)
11: }
12:
(dlv) p i
[]int len: 8, cap: 8, [1,2,3,4,5,6,7,8]
一直按n
到fmt.Println(v)
这一行,这是一个包函数,可以按s
进入下一层
(dlv) n
> main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:10 (PC: 0xf49965)
5: func main() {
6: i := []int{1, 2, 3, 4, 5, 6, 7, 8}
7: j := "this is dlv"
8:
9: for _, v := range i {
=> 10: fmt.Println(v)
11: }
12:
13: fmt.Println(j)
14: }
(dlv) s
> fmt.Println() C:/Users/54225/AppData/Roaming/MobaXterm/home/go1.20.5.windows-amd64/go/src/fmt/print.go:313 (PC: 0xf444ca)
308: }
309:
310: // Println formats using the default formats for its operands and writes to standard output.
311: // Spaces are always added between operands and a newline is appended.
312: // It returns the number of bytes written and any write error encountered.
=> 313: func Println(a ...any) (n int, err error) {
314: return Fprintln(os.Stdout, a...)
315: }
316:
317: // Sprintln formats using the default formats for its operands and returns the resulting string.
318: // Spaces are always added between operands and a newline is appended.
进入下一层后,看到想看的逻辑了,想要返回到主函数,需要按n
,结束这一次返回
(dlv) n
> fmt.Println() C:/Users/54225/AppData/Roaming/MobaXterm/home/go1.20.5.windows-amd64/go/src/fmt/print.go:314 (PC: 0xf444ff)
309:
310: // Println formats using the default formats for its operands and writes to standard output.
311: // Spaces are always added between operands and a newline is appended.
312: // It returns the number of bytes written and any write error encountered.
313: func Println(a ...any) (n int, err error) {
=> 314: return Fprintln(os.Stdout, a...)
315: }
316:
317: // Sprintln formats using the default formats for its operands and returns the resulting string.
318: // Spaces are always added between operands and a newline is appended.
319: func Sprintln(a ...any) string {
(dlv) n
1
> main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:10 (PC: 0xf49a05)
Values returned:
n: 2
err: error nil
5: func main() {
6: i := []int{1, 2, 3, 4, 5, 6, 7, 8}
7: j := "this is dlv"
8:
9: for _, v := range i {
=> 10: fmt.Println(v)
11: }
12:
13: fmt.Println(j)
14: }
想要结束此次任务,不看断点了,可以按c
(dlv) n
1
> main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:10 (PC: 0xf49a05)
Values returned:
n: 2
err: error nil
5: func main() {
6: i := []int{1, 2, 3, 4, 5, 6, 7, 8}
7: j := "this is dlv"
8:
9: for _, v := range i {
=> 10: fmt.Println(v)
11: }
12:
13: fmt.Println(j)
14: }
(dlv) c
2
3
4
5
6
7
8
this is dlv
Process 20716 has exited with status 0
此时程序已经执行完毕了,但是debug
模式没有退出,可以按r
重新启动
(dlv) r
Process restarted with PID 25312
(dlv) c
> main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:5 (hits goroutine(1):1 total:1) (PC: 0xf49812)
1: package main
2:
3: import "fmt"
4:
=> 5: func main() {
6: i := []int{1, 2, 3, 4, 5, 6, 7, 8}
7: j := "this is dlv"
8:
9: for _, v := range i {
10: fmt.Println(v)
如果下次执行不希望有断点了,可以按clear 1
,删除第一个断点也可以clearall
删除全部断点,按b
查看断点
(dlv) b
Breakpoint 5 set at 0x7ff948b60911 for :0
(dlv) clear 5
Breakpoint 5 cleared at 0x7ff948b60911 for :0
(dlv) clearall
Breakpoint 4 cleared at 0x0 for :0
Breakpoint 2 cleared at 0xf49812 for main.main() C:/Users/54225/AppData/Roaming/MobaXterm/home/project/learning/ch19/main.go:5