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

本文涉及的产品
Serverless 应用引擎 SAE,800核*时 1600GiB*时
应用实时监控服务ARMS - 应用监控,每月50GB免费额度
简介: 【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工具等等,对于在某些场景的深度问题定位和功能开发有帮助。

目录
相关文章
|
8月前
|
NoSQL 小程序 Cloud Native
你是使用什么工具调试 golang 程序的?
你是使用什么工具调试 golang 程序的?
|
NoSQL IDE 编译器
|
Cloud Native 关系型数据库 MySQL
探索 Golang 云原生游戏服务器开发,硬核实战之调试 NanoServer 生产级麻将游戏服务器
探索 Golang 云原生游戏服务器开发,硬核实战之调试 NanoServer 生产级麻将游戏服务器
479 0
探索 Golang 云原生游戏服务器开发,硬核实战之调试 NanoServer 生产级麻将游戏服务器
|
编译器 Go
使用 vscode 调试 golang 短暂进程
背景使用 vscode 调试 golang 程序相信大家并不陌生,但当我们要调试的程序有以下特点的话,是不是会变得很棘手?要调试的程序并不由我们直接触发要调试的程序是短暂进程(调试中难以捕获进程 id)本文将以 git-hooks(proc-receive)的调试为例介绍一种针对这种场景的调试方案程序编译本文示例代码地址:https://code.aone.alibaba-inc.com/agit
使用 vscode 调试 golang 短暂进程
|
Go
go-spew golang最强大的调试助手,没有之一
go内置的fmt.sprintf已经很强大了,但是和spew比起来还是相形见绌,这里来一个例子. import ( "fmt" "github.com/davecgh/go-spew/spew" ) func main() { scs := spew.
2222 0
|
NoSQL Go
使用Delve进行Golang代码的调试
追踪代码中的错误可能是一件非常头疼的事情。这在高度依赖goroutine的Golang代码调试中更加的突出。我来介绍一个专门为 Go而生的 debug 工具,解决开发者在使用 GDB 调试中遇到的各种各样的问题。
34243 0
|
2月前
|
监控 算法 Go
Golang深入浅出之-Go语言中的服务熔断、降级与限流策略
【5月更文挑战第4天】本文探讨了分布式系统中保障稳定性的重要策略:服务熔断、降级和限流。服务熔断通过快速失败和暂停故障服务调用来保护系统;服务降级在压力大时提供有限功能以保持整体可用性;限流控制访问频率,防止过载。文中列举了常见问题、解决方案,并提供了Go语言实现示例。合理应用这些策略能增强系统韧性和可用性。
134 0
|
2月前
|
前端开发 Go
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
【5月更文挑战第3天】Go语言通过goroutines和channels实现异步编程,虽无内置Future/Promise,但可借助其特性模拟。本文探讨了如何使用channel实现Future模式,提供了异步获取URL内容长度的示例,并警示了Channel泄漏、错误处理和并发控制等常见问题。为避免这些问题,建议显式关闭channel、使用context.Context、并发控制机制及有效传播错误。理解并应用这些技巧能提升Go语言异步编程的效率和健壮性。
79 5
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
|
2月前
|
Prometheus 监控 Cloud Native
Golang深入浅出之-Go语言中的分布式追踪与监控系统集成
【5月更文挑战第4天】本文探讨了Go语言中分布式追踪与监控的重要性,包括追踪的三个核心组件和监控系统集成。常见问题有追踪数据丢失、性能开销和监控指标不当。解决策略涉及使用OpenTracing或OpenTelemetry协议、采样策略以及聚焦关键指标。文中提供了OpenTelemetry和Prometheus的Go代码示例,强调全面可观测性对微服务架构的意义,并提示选择合适工具和策略以确保系统稳定高效。
175 5