Debugging Go Program

栏目: C · 发布时间: 7年前

内容简介:定位Go是编译型语言,且如果程序比较复杂,需要反复增加日志输出才能找到问题原因。熟练的使用调试器能够提高我们面对这样问题的灵活性。此文就是介绍如何使用

定位 Go 程序的错误,通常有两种方式:

  • 打印日志
  • 调试

Go是编译型语言,且 IDE 对调试的支持不太好,绝大多数 Go 的初学者调试 Go 程序都是通过 log.Printf 等打印日志方式定位问题。通常过程如下:

  1. 程序 panic 或者报错
  2. 修改 Go 程序,添加打印调试日志代码
  3. 编译 Go 程序
  4. 重复错误出现时的操作,查看日志
    debug
    

如果程序比较复杂,需要反复增加日志输出才能找到问题原因。熟练的使用调试器能够提高我们面对这样问题的灵活性。此文就是介绍如何使用 delve 等调试器调试 Go 程序。本文重点是全面介绍调试相关知识,具体调试 工具 的操作网上相关资料已经很全面(见最后一章参考),不作为重点。

使用GDB调试 Go 程序

简介

GDB不能很好的理解 Go 程序。 Go 程序和 GDB 的 stack management 、 threading 、 runtime 模型差异很大,并可能导致调试器输出不正确的结果。因此,虽然 GDB 在某些场景下有用,比如调试 Cgo 代码、调试 runtime ,但是对于 Go 程序来说,尤其是高并发程序, GDB 不是一个可靠的调试器。而且,对于 Go 语言项目本身来说,解决这些的问题很困难,也不是一个高优先级的事情。

当你在 Linux 、 macOS 、 FreeBSD 、 NetBSD 上使用 gc 工具链编译和连接 Go 程序的时候,产生的二进制包含 DWARFv4 调试信息,最近版本的 GDB 调试器可以利用这些信息观察一个运行的进程或者 core dump 。

可以通过 -w 标记告诉连接器去掉这些调试信息,比如:

go build -ldflags "-w" .

gc编译器生成的程序包含 函数内联 和变量注册。这些优化可能会让 gdb 调试更加困难。如果你需要禁用这些优化,使用下面的参数构建程序:

go build -gcflags "all=-N -l" .

如果你想要使用 gdb 检查一个 core dump ,你可以在程序崩溃的时候触发一个dump。在支持dump的 OS 上,使用 GOTRACEBACK=crash 环境变量(参考 runtime package documentation )。

Go 1.11版本中,由于编译器会产生更多更准确的调试信息,为了减少二进制的大小, DWARF 调试信息编译时候会默认被压缩。这对于大多数 ELF 工具来说这是透明的,也得到 Delve 支持。但是macOS和Windows上一些工具不支持。如果要禁用 DWARF 压缩,可以在编译的时候传入参数 -ldflags "-compressdwarf=false" 。

Go 1.11添加了一个实验性的功能,允许在调试器中调用函数。目前这个特性仅得到 Delve (version 1.1.0及以上)的支持。

常用命令和教程

可以参考下面几篇文章,这里不做赘述:

使用LLDB调试Go程序

简介

Mac下如果你安装XCode,应该会自动安装了LLDB,LLDB是XCode的默认调试器。LLDB的安装方法可以参考 这里 。

GDB的命令格式非常自由,和GDB的命令不同,LLDB命令格式非常结构化(“严格”的婉转说法)。LLDB的命令格式如下:

<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]

解释一下:

  • <command> (命令)和 <subcommand> (子命令):LLDB调试命令的名称。命令和子命令按层级结构来排列:一个命令对象为跟随其的子命令对象创建一个上下文,子命令又为其子命令创建一个上下文,依此类推。
  • <action> :执行命令的操作
  • <options> :命令选项。需要注意的是,如果aguments的第一个字母是”-“, <options> 和 <arguments> 中间必须以”–”分隔开。所以如果你想启动一个程序,并给这个程序传入 -program_arg value 参数,可以输入 (lldb) process launch --stop-at-entry -- -program_arg value
  • <arguement> :命令的参数
  • [] :表示命令是可选的,可以有也可以没有

LLDB也减少了gdb中一些命令的特殊写法,让用户更加容易理解命令的意图。可以阅读 LLDB文档 中下面一段文字了解细节:

We also tried to reduce the number of special purpose argument parsers, which sometimes forces the user to be a little more explicit about stating their intentions.
……

LLDB的命令同样给很多命令提供了缩写形式,可以通过 (lldb) help 查看所有的缩写命令。

gdb和LLDB的命令之间的差别 可以访问这里查看。

常用命令

使用LLDB需要熟悉的常用命令如下:

帮助

(lldb) help help

Show a list of all debugger commands, or give details about a specific command.

Syntax: help [ ]

使用LLDB加载一个程序

$lldb /binary-path
Current executable set to '/binary-path'(x86_64).

$lldb
(lldb) file /binary-path
Current executable set to '/binary-path'(x86_64).

设置断点(breakpoints)

常见的设置断点的命令如下:

(lldb) breakpoint set --file source-file.go --line 11
Breakpoint 1: where = sample1`github.com/ethancai/go-debug-practice/sample1/model.(*MyStruct).Print + 19 at my_struct.go:11, address = 0x00000000010b2713

breakpoint 命令会创建一个 逻辑的 断点,一个逻辑的断点可以对应一个或者多个位置 location 。比如,通过 selector 设置的断点对应所有实现了 selector 的方法。

breakpoint 命令:

(lldb) help breakpoint
Commands for operating on breakpoints (see 'help b' for shorthand.)

Syntax: breakpoint <subcommand> [<command-options>]

...

设置观察点(Watchpoints)

watchpoint 命令:

(lldb) help watchpoint
  Commands for operating on watchpoints.

Syntax: watchpoint <subcommand> [<command-options>]

...

运行程序或者附着程序

process 命令:

(lldb) help process
  Commands for interacting with processes on the current platform.

Syntax: process <subcommand> [<subcommand-options>]

...

控制程序执行或者检查Thread状态

thread 命令

(lldb) help thread
  Commands for operating on one or more threads in the current process.

Syntax: thread <subcommand> [<subcommand-options>]

...

检查堆栈结构(Stack Frame)状态

frame 命令

(lldb) help frame
  Commands for selecting and examing the current thread's stack frames.

Syntax: frame <subcommand> [<subcommand-options>]

...

expression 命令

(lldb) help expression
  Evaluate an expression on the current thread.  Displays any returned value with LLDB's
  default formatting.  Expects 'raw' input (see 'help raw-input'.)

Syntax: expression <cmd-options> -- <expr>

...

操作教程

可以参考下面几篇文章:

使用Delve调试Go程序

可以参考下面几篇文章:

不要使用调试器

对于调试器,一众计算机大牛都给出了明确而且强烈的建议:不要使用调试器。

调试技术是一众纯手工的技术,诞生于计算机程序的规模还不是很大的时期。在当今软件规模不断扩展的情况下,调试无法解决软件质量问题。深入的思考、合理的架构、优美的代码、充分的单元测试才是提高软件质量的正确方向。调试应该仅作为调查问题最后一种办法。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

计数组合学(卷2)

计数组合学(卷2)

斯坦利 / 机械工业出版社 / 2004-11-15 / 59.00元

本书介绍了生成函数组合、树、代数生成函数、D有限生成函数、非交换生成函数和对称函数。关于对称函数的论述只适用于研究生的入门课程并着重于组合学方面,尤其是Robinson-Schensted-Knuth算法,还讨论了对称函数与表示论之间的联系。附录(由Sergey Fomin编写)中更深入地讨论了对称函数理论,包括jeu de taquin和Littlewood-richardson规则。另外,书中......一起来看看 《计数组合学(卷2)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

html转js在线工具
html转js在线工具

html转js在线工具