1、编译选项
go build -gcflags=all="-N -l" ## 必须这样编译,才能用gdb打印出变量,第二个是小写的L,不是大写的i
需要加编译选项,类似gcc中的 -g选项,加入调试信息。关于如何安装dlv,请自行百度或者谷歌。
2、使用dlv调试
dlv的功能介绍
Usage:
dlv [command]
Available Commands:
attach Attach to running process and begin debugging.
connect Connect to a headless debug server.
core Examine a core dump.
debug Compile and begin debugging main package in current directory, or the package specified.
exec Execute a precompiled binary, and begin a debug session.
help Help about any command
run Deprecated command. Use 'debug' instead.
test Compile test binary and begin debugging program.
trace Compile and begin tracing program.
version Prints version.
由于dlv的功能比较多,我只介绍我常用的几个,包括 attach、debug、exec、core、test,这5个。
1、dlv attach
这个相当于gdb -p 或者 gdb attach ,即跟踪一个正在运行的程序。这中用法也是很常见,对于一个后台程序,它已经运行很久了,此时你需要查看程序内部的一些状态,只能借助attach.
dlv attach $PID ## 后面的进程的ID
2、dlv debug
dlv debug main/hundredwar.go ## 先编译,后启动调试
3、dlv exec
dlv exec ./HundredsServer ## 直接启动调试
dlv exec ./HundredsServer -- -port 8888 -c /home/config.xml ## 后面加参数启动调试
与dlv debug区别就是,dlv debug 编译一个临时可执行文件,然后启动调试,类似与go run。
4、dlv core
用来调试core文件,但是想让go程序生成core文件,需要配置一个环境变量,默认go程序不会产生core文件。
export GOTRACEBACK=crash
只有定义这个环境变量,go程序才会coredump。如果在协程入口定义defer函数,然后recover也不会产生core文件。
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("panic error\n")
}
}()
var p *int = nil
fmt.Printf("p=%d\n", *p) // 访问nil指责
}() // 这个协程不会生产core文件
因为recover的作用就是捕获异常,然后进行错误处理,所以不会产生coredump,这个需要注意。这个也是golang的一大特色吧,捕获异常,避免程序coredump。
调试coredump文件
关于调试core文件,其实和C/C++差不多,最后都是找到发生的函数帧,定位到具体某一行代码。但是golang稍有不同,对于golang的core文件需要先定位到时哪一个goroutine发生了异常。
dlv core ./Server core.26945 ## 启动
Type 'help' for list of commands.
(dlv) goroutines ## 查看所有goroutine
[12 goroutines]
Goroutine 1 - User: /usr/local/go/src/runtime/time.go:102 time.Sleep (0x440d16)
Goroutine 2 - User: /usr/local/go/src/runtime/proc.go:292 runtime.gopark (0x42834a)
Goroutine 3 - User: /usr/local/go/src/runtime/proc.go:292 runtime.gopark (0x42834a)
Goroutine 4 - User: /usr/local/go/src/runtime/proc.go:292 runtime.gopark (0x42834a)
Goroutine 5 - User: /usr/local/go/src/runtime/time.go:102 time.Sleep (0x440d16)
Goroutine 6 - User: /usr/local/go/src/runtime/time.go:102 time.Sleep (0x440d16)
Goroutine 7 - User: /usr/local/go/src/runtime/time.go:100 time.Sleep (0x440ccd)
Goroutine 8 - User: ./time.go:114 main.main.func2 (0x4a33cb) (thread 21239)
Goroutine 9 - User: /usr/local/go/src/runtime/lock_futex.go:227 runtime.notetsleepg (0x40ce42)
Goroutine 17 - User: /usr/local/go/src/runtime/proc.go:292 runtime.gopark (0x42834a)
Goroutine 33 - User: /usr/local/go/src/runtime/proc.go:292 runtime.gopark (0x42834a)
Goroutine 49 - User: /usr/local/go/src/runtime/proc.go:292 runtime.gopark (0x42834a)
上面,可以看到所以的goroutine,需要找到自己的业务代码所在的goroutine,这里需要判断,不像C/C++的core文件,可以定义定位到所在的函数栈。这里的是 Goroutine 8 。
需要进入 8 号 goroutine。
(dlv) goroutine 8 ## 切换到 8 号 goroutine
Switched from 0 to 8 (thread 21239)
(dlv) bt ## 查看栈帧
0 0x0000000000450774 in runtime.raise
at /usr/local/go/src/runtime/sys_linux_amd64.s:159
1 0x000000000044cea0 in runtime.systemstack_switch
at /usr/local/go/src/runtime/asm_amd64.s:363
2 0x00000000004265ba in runtime.dopanic
at /usr/local/go/src/runtime/panic.go:597
3 0x00000000004261f1 in runtime.gopanic
at /usr/local/go/src/runtime/panic.go:551
4 0x00000000004250ce in runtime.panicmem
at /usr/local/go/src/runtime/panic.go:63
5 0x0000000000438baa in runtime.sigpanic
at /usr/local/go/src/runtime/signal_unix.go:388
6 0x00000000004a33cb in main.main.func2
at ./time.go:114 ## 显然6号栈是自己的业务代码
7 0x000000000044f6d1 in runtime.goexit
at /usr/local/go/src/runtime/asm_amd64.s:2361
(dlv) frame 6 ## 进入6号栈帧
> runtime.raise() /usr/local/go/src/runtime/sys_linux_amd64.s:159 (PC: 0x450774)
Warning: debugging optimized function
Frame 6: ./time.go:114 (PC: 4a33cb)
109: // if r := recover(); r != nil {
110:
111: // }
112: // }()
113: var p *int = nil
=> 114: fmt.Printf("p=%d\n", *p) ## 这里发生了异常
115: }()
116:
117: time.Sleep(10000000)
118: }
5、dlv test
dlv test 也很有特色,是用来调试测试代码的。因为测试代码都是某一个包里面,是以包为单位的。
dlv test $packname ## 包名
[KentZhang@LOCAL-192-168-97-2 src]$ dlv test db ## 调试db包内部的测试用例
Type 'help' for list of commands.
(dlv) b TestMoneyDbGet ## 打断点,不用加包名了
Breakpoint 1 set at 0x73c15b for db.TestMoneyDbGet() ./db/moneydb_test.go:9
(dlv) c
> db.TestMoneyDbGet() ./db/moneydb_test.go:9 (hits goroutine(5):1 total:1) (PC: 0x73c15b)
4: "logger"
5: "testing"
6: )
7:
8: //日志不分离
=> 9: func TestMoneyDbGet(t *testing.T) {
10: logger.Init("testlog", ".", 1000, 3, logger.DEBUG_LEVEL, false, logger.PUT_CONSOLE)
11: c := MoneydbConnect("192.168.202.92:12515")
12: if nil == c {
13: t.Error("Init() failed.")
14: return
(dlv)
3、调试命令
关于dlv内的调试命令,和gdb差不多,可以使用help查看所有命令。
help
(dlv) help
The following commands are available:
args -------------------------------- Print function arguments.
break (alias: b) -------------------- Sets a breakpoint.
breakpoints (alias: bp) ------------- Print out info for active breakpoints.
call -------------------------------- Resumes process, injecting a function call (EXPERIMENTAL!!!)
check (alias: checkpoint) ----------- Creates a checkpoint at the current position.
checkpoints ------------------------- Print out info for existing checkpoints.
clear ------------------------------- Deletes breakpoint.
clear-checkpoint (alias: clearcheck) Deletes checkpoint.
clearall ---------------------------- Deletes multiple breakpoints.
condition (alias: cond) ------------- Set breakpoint condition.
config ------------------------------ Changes configuration parameters.
continue (alias: c) ----------------- Run until breakpoint or program termination.
disassemble (alias: disass) --------- Disassembler.
down -------------------------------- Move the current frame down.
edit (alias: ed) -------------------- Open where you are in $DELVE_EDITOR or $EDITOR
exit (alias: quit | q) -------------- Exit the debugger.
frame ------------------------------- Set the current frame, or execute command on a different frame.
funcs ------------------------------- Print list of functions.
goroutine --------------------------- Shows or changes current goroutine
goroutines -------------------------- List program goroutines.
help (alias: h) --------------------- Prints the help message.
list (alias: ls | l) ---------------- Show source code.
locals ------------------------------ Print local variables.
next (alias: n) --------------------- Step over to next source line.
on ---------------------------------- Executes a command when a breakpoint is hit.
print (alias: p) -------------------- Evaluate an expression.
regs -------------------------------- Print contents of CPU registers.
restart (alias: r) ------------------ Restart process from a checkpoint or event.
rewind (alias: rw) ------------------ Run backwards until breakpoint or program termination.
set --------------------------------- Changes the value of a variable.
source ------------------------------ Executes a file containing a list of delve commands
sources ----------------------------- Print list of source files.
stack (alias: bt) ------------------- Print stack trace.
step (alias: s) --------------------- Single step through program.
step-instruction (alias: si) -------- Single step a single cpu instruction.
stepout ----------------------------- Step out of the current function.
thread (alias: tr) ------------------ Switch to the specified thread.
threads ----------------------------- Print out info for every traced thread.
trace (alias: t) -------------------- Set tracepoint.
types ------------------------------- Print list of types
up ---------------------------------- Move the current frame up.
vars -------------------------------- Print package variables.
whatis ------------------------------ Prints type of an expression.
help [command]
使用 help command 打印出具体命令的用法,例如:
(dlv) help set
Changes the value of a variable.
[goroutine <n>] [frame <m>] set <variable> = <value>
(dlv) help on
Executes a command when a breakpoint is hit.
on <breakpoint name or id> <command>.
4、config
(dlv) config -list
aliases map[]
substitute-path []
max-string-len <not defined>
max-array-values <not defined>
max-variable-recurse <not defined>
show-location-expr false
source-list-line-color 34
debug-info-directories [/usr/lib/debug/.build-id]
使用p打较长的字符串时,会显示不全,需要配置更长的长度:
(dlv) config max-string-len 99999
5、修改变量值
set num = 1
## 这种修改string变量的,必须使用 call , set 不行
call ctx.Setting.Password = "gQx%7TUB#1cF"
## call 其实调用函数
call len(arr)
6、dlv的不足之处
dlv和gdb相比,除了支持协程这一优势之外,其他的地方远不如gdb。比如
- dlv 的print 不支持十六进制打印,gdb就可以,p /x number
- dlv不支持变量、函数名的自动补全
- dlv的on 功能与gdb的commands类似,可惜的是dlv只支持print, stack and goroutine三个命令,竟然不支持continue
还有一个特殊情况,如果一个函数有定义,但是没在任何地方调用,那么dlv打断点打不到。
今天的文章go dlv 调试_vscode配置go开发环境「建议收藏」分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/69372.html