2019年8月

golang调试

golang程序调试工具有gdb、godebug、delve等,gdb原生支持c/c++程序,对golang语法支持比较差,godebug专为golang调试开发,目前功能尚不完善,不支持attach等,delve工具可以说是golang的gdb,支持golang在调试模式下运行、attach、调试core等,所以目前采用delve工具调试golang是最佳选择

  • delve安装

delve项目地址:github.com/go-delve/delve/,克隆到GOPATH目录下,然后执行make install,最后把dlv所在目录加到PATH路径即可

由于delve对golang的版本有要求,我的golang版本是1.8.3,编译最新的delve出错,所以尝试几个老版本,亲测devle的1.2.0版本可正常安装,所以需要checkout到1.2.0,然后再编译安装

  • delve使用

delve的帮助与gdb类似,dlv --help 可查看delve有哪些子命令,具体子命令用法例如debug,可输入dlv debug --help
dlv debug 可直接调试golang源文件
dlv exec 调试golang二进制程序
dlv attach 可对正在运行的程序截取快照进行调试
dlv core 可调试崩溃文件

  • golang崩溃

go程序在崩溃时,其崩溃所在的goroutine会执行每个栈帧对应的defer函数,若执行recover函数获取panic信息,可避免进程异常退出,仅仅其所在的goroutine退出,但通常情况下程序出现异常是需要进程退出,否则会出现未知逻辑错误

在程序异常退出时,若在defer函数中采用runtime.Stack()获取栈信息,则需要在每个goroutine中都要加defer函数,比较麻烦,若截获SIGSEGV等异常信号,golang又不像c语言那样可设定每个信号的handler,一旦异常信号出现采用golang的notify机制却捕获不到,即使采用defer或者c语言的handler方式,采集到的栈信息已经不在崩溃点,所以异常信息只能采用coredump来解决,而golang在崩溃时,默认仅产生当前goroutine的崩溃信息,并没有产生core文件,因此需要修改其运行时环境,让其产生core文件

  • GOTRACEBACK

GOTRACEBACK是golang运行时环境变量之一,用于控制go程序崩溃时的处理,有以下几种取值

GOTRACEBACK=none,仅产生panic信息,不产生栈信息
GOTRACEBACK=single,在none基础上,产生当前goroutine的栈信息
GOTRACEBACK=all,在none基础上,产生所有goroutine的栈信息
GOTRACEBACK=system,在all基础上,产生包括runtime的栈信息
GOTRACEBACK=core,在system基础上,产生core dump文件

默认是single,所以仅需要执行 env GOTRACEBACK=core ./xxx.exe,即可产生core文件,若采用sudo方式运行程序,由于sudoer账户在运行程序前会重置当前用户环境变量,所以需要修改/etc/sudoers文件,注释掉Defaults env_reset,添加Defaults !env_reset
更多运行时环境变量可参考https://dave.cheney.net/2015/11/29/a-whirlwind-tour-of-gos-runtime-environment-variables

系统默认产生core文件大小限制为0,即禁止产生core文件,需执行ulimit -c unlimited,若需要修改core文件名称为程序名.core.pid,则需要修改/etc/sysctl.conf文件,在文件后追加kernel.core_pattern =%e.core.%p
kernel.core_uses_pid = 0
然后执行sysctl -p生效