在golang中调试时的指令和使用技巧

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
应用实时监控服务-用户体验监控,每月100OCU免费额度
简介: 【7月更文挑战第4天】 本文介绍 Go调试工具`dlv`常用命令概览及其使用技巧。

1 简介

本文汇总 Go调试工具dlv常用命令概览

  • dlv attach: 连接并调试运行中的进程
  • dlv connect: 终端连接无头调试服务器
  • dlv core: 分析核心转储文件
  • dlv dap: 启动DAP服务器
  • dlv debug: 编译并调试主包
  • dlv exec: 从二进制文件启动调试
  • dlv test: 编译调试测试二进制
  • dlv trace: 开始跟踪程序
  • dlv version: 显示版本信息

调试技巧:

  • break设置断点,如break main.main
  • condition设定断点条件,如condition 2 i = 3
  • continue执行到下一个断点
  • next单步执行
  • args, locals检查变量
  • stack查看栈帧
  • goroutinegoroutines检查goroutine状态
  • disassemble反汇编代码
  • step-instruction单步执行汇编
  • regs查看寄存器状态
  • print检查内存地址数据
  • quit退出调试

treeoflife6.png

dlv提供深入调试支持,包括汇编和goroutine分析,助于复杂问题定位。

2 golang调试 常用指令

附加到正在运行的进程并开始调试。

          dlv attach 

使用终端客户端连接到无头调试服务器。

dlv connect 

检查核心转储

dlv core  

启动通过调试适配器协议 (DAP) 进行通信的无头 TCP 服务器。

dlv dap 

编译并开始调试当前目录或指定包中的主包。

dlv debug  

执行预编译的二进制文件,并开始调试会话。

dlv exec 

重播 rr 跟踪。

dlv replay 

已弃用的命令。请改用“调试”。

dlv run  

编译测试二进制文件并开始调试程序。

dlv test 

编译并开始跟踪程序。

dlv trace  

打印版本。

dlv version 

关于日志记录标志的帮助

dlv log   

关于--backend标志的帮助

dlv backend 

查看全部包级别的变量。 因为最终目标程序可能含有大量全局变量。

  vars main  

在main函数入口设置一个 断点

  break main.main 

程序继续运行到下一个断点。

continue   

指令单步执行进入 main() 函数

 next  

进入函数后

  args  // 查看局部变量
  locals  //查看全局变量

3 调试的组合指令:调试循环条件,和例程 状态

break 和 condition 组合命令 用于在函数循环 内部设置条件断点
比如 在 main.go 10 行设置断点

    break main.go 10

    Breakpoint 2 set at main.main

为断点2 设置条件 当 i = 3 生效

     condition 2 i = 3 

然后 continue 运行到 该条件,查看输出。

如果发现循环变量i为3时,切片的前3个元素已经正确初始化,那么可以通过 stack 查看当前函数执行的栈帧信息

        stack
        0  0x000000000084d1e7 in main.main
           at  /main.go:49
        1  0x00000000001b1428 in runtime.main
           at /go/src/runtime/proc.go:250
        2  0x00000000001ddac1 in runtime.goexit
           at /go/src/runtime/asm_amd64.s:1594

或者通过 goroutine 和 goroutines 查看当前 goroutine 相关信息

    goroutine
    Thread 8244 at d:/gospace/strtech/main.go:49
    Goroutine 1:
            Runtime:  /main.go:49 main.main (0x84d1e7)
            User:  /main.go:49 main.main (0x84d1e7)
            Go: <autogenerated>:1 runtime.newproc (0x1dfeec)     
            Start: /go/src/runtime/proc.go:145 runtime.main (0x1b1260)

    (dlv) goroutines
    * Goroutine 1 - User:  /main.go:49 main.main (0x84d1e7) (thread 8244)
      Goroutine 2 - User: /go/src/runtime/proc.go:364 runtime.gopark (0x1b181d) [force gc (idle)]
      Goroutine 3 - User: /go/src/runtime/proc.go:364 runtime.gopark (0x1b181d) [GC sweep wait]
      ...

查看当前代码 ,命令(在命令行界面中)将具有以下结果:

 list main.main 

   (dlv) list main.main
        Showing  ./goid_stored/main.go:116 (PC: 0xb2b76a)
           111:                 }(i)
           112:         }
           113:         wg.Wait()
           114: }
           115:
           116: func main() {
           117:         fmt.Printf("gls:%#v \n", gls)
           118:         UsageGls()
           119: }

4 调试时反汇编单步

disassemble 反汇编计数查看 main函数对应的汇编代码。

   Sending output to pager...
    TEXT main.main(SB) /main.go
            main.go:41      0x84d100        4c8d6424e8
       lea r12, ptr [rsp-0x18]
            main.go:41      0x84d105        4d3b6610
       cmp r12, qword ptr [r14+0x10]
            main.go:41      0x84d109        0f86ed000000
       jbe 0x84d1fc

step-instruction 单步执行汇编指令的命令。

使用break 设置断开,continue到断点停下,或继续

查看全部寄存器状态

  (div) regs
       Rip = 0x000000000084d1e7
       Rsp = 0x000000c0004c3ee0
       Rax = 0x0000000000c93100
       Rbx = 0x0000000000000006
       Rcx = 0x0000000000000000
       Rdx = 0x000000c000536230
       Rsi = 0x0000000000000000
       Rdi = 0x000000c00033cb00
       Rbp = 0x000000c0004c3f70
        R8 = 0x0000000000000000
        R9 = 0x000000000000034e
       R10 = 0x0000000000000000
       R11 = 0x0000000000000246
       R12 = 0x000000c0004c3ac8
       R13 = 0x0000000000000000
       R14 = 0x000000c000056000
       R15 = 0x0000000000000020
    Rflags = 0x0000000000000204     [PF IF IOPL=0]
        Cs = 0x0000000000000033
        Fs = 0x0000000000000053
        Gs = 0x000000000000002b

由此推断程序内部定义的 数据地址,然后使用print 可以查看 该地址的数据

   print *(*[5]byte)
  • 退出调试

    quit 
    

5 小结

本文简单介绍go程序调试的方式,相比c程序 gcc工具 和 python的pdb工具,go提供了更多层级的工具,比如内置的cgo汇编程序,伪汇编代码,应用级的dlv工具等等,对于在某些场景的深度问题定位和功能开发有帮助。

目录
相关文章
|
NoSQL 小程序 Cloud Native
你是使用什么工具调试 golang 程序的?
你是使用什么工具调试 golang 程序的?
171 0
|
5月前
|
编译器 Go C语言
通过例子学习在golang中调试程序
【7月更文挑战第4天】Go语言支持使用cgo进行汇编调试,官方文档在golang.org/doc/asm。注意,调试Go运行时可能遇到变量不可用或行号错误,需谨慎使用step命令。
74 1
通过例子学习在golang中调试程序
|
NoSQL IDE 编译器
|
Cloud Native 关系型数据库 MySQL
探索 Golang 云原生游戏服务器开发,硬核实战之调试 NanoServer 生产级麻将游戏服务器
探索 Golang 云原生游戏服务器开发,硬核实战之调试 NanoServer 生产级麻将游戏服务器
639 0
探索 Golang 云原生游戏服务器开发,硬核实战之调试 NanoServer 生产级麻将游戏服务器
|
编译器 Go
使用 vscode 调试 golang 短暂进程
背景使用 vscode 调试 golang 程序相信大家并不陌生,但当我们要调试的程序有以下特点的话,是不是会变得很棘手?要调试的程序并不由我们直接触发要调试的程序是短暂进程(调试中难以捕获进程 id)本文将以 git-hooks(proc-receive)的调试为例介绍一种针对这种场景的调试方案程序编译本文示例代码地址:https://code.aone.alibaba-inc.com/agit
使用 vscode 调试 golang 短暂进程
|
Go Windows 开发工具
解决golang windows调试问题:Could not determine version number: could not find symbol value for runtime.buildVersion
版本信息: go:1.8.3 windows: win7/64 idea-go-plugin:171.4694.61 在windows下,使用dlv进行调试的时候,如果golang程序引入了c模块,比如常用的sqlite模块,那么在调试的时候一定会发生这个错误: · Could not determine version number: could not find symbol value for runtime.buildVersion· 现在这个问题已经解决了,解决方法就是go build 的时候加入-ldflags="-linkmode internal" ,这样就可以正常调试了。
2183 0
|
Go
go-spew golang最强大的调试助手,没有之一
go内置的fmt.sprintf已经很强大了,但是和spew比起来还是相形见绌,这里来一个例子. import ( "fmt" "github.com/davecgh/go-spew/spew" ) func main() { scs := spew.
2265 0
|
NoSQL Go
使用Delve进行Golang代码的调试
追踪代码中的错误可能是一件非常头疼的事情。这在高度依赖goroutine的Golang代码调试中更加的突出。我来介绍一个专门为 Go而生的 debug 工具,解决开发者在使用 GDB 调试中遇到的各种各样的问题。
34351 0
|
3月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
125 4
Golang语言之管道channel快速入门篇