前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go调试利器,手把手入门dlv (上)

Go调试利器,手把手入门dlv (上)

作者头像
用户1072003
发布2022-12-02 20:56:42
2.3K0
发布2022-12-02 20:56:42
举报
文章被收录于专栏:码上读书码上读书

祝大家国庆节快乐。

说到调试器,首先让人想到大名鼎鼎的GDB,在mac上对应的有lldb,dlv是针对Go语言单独开发的调试利器,而且dlv也是用go语言开发的。在windows平台也可以同样运行。今天我们简单介绍一下dlv如何调试go程序的。

首先我们创建一个main.go文件,main函数先通过一个for循环来初始化一个切片,再打印出切片的内容:

代码语言:javascript
复制
package main

import "fmt"

// dlv 调试器

func main() {
  nums := make([]int, 5)
  for i := 0; i < len(nums); i++ {
    nums[i] = i * i
  }
  fmt.Println(nums)
}

在命令行输入 dlv debug 开始进行调试。

代码语言:javascript
复制
➜  Delve git:(master) ✗ dlv debug
Type 'help' for list of commands.
(dlv)

如果不知道如何使用,有哪些命令,可以输入help查看命令列表:

代码语言:javascript
复制


(dlv) help
The following commands are available:


Running the program:
    call ------------------------ Resumes process, injecting a function call (EXPERIMENTAL!!!)
    continue (alias: c) --------- Run until breakpoint or program termination.
    next (alias: n) ------------- Step over to next source line.
    rebuild --------------------- Rebuild the target executable and restarts it. It does not work if the executable was not built by delve.
    restart (alias: r) ---------- Restart process.
    step (alias: s) ------------- Single step through program.
    step-instruction (alias: si)  Single step a single cpu instruction.
    stepout (alias: so) --------- Step out of the current function.


Manipulating breakpoints:
    break (alias: b) ------- Sets a breakpoint.
    breakpoints (alias: bp)  Print out info for active breakpoints.
    clear ------------------ Deletes breakpoint.
    clearall --------------- Deletes multiple breakpoints.
    condition (alias: cond)  Set breakpoint condition.
    on --------------------- Executes a command when a breakpoint is hit.
    toggle ----------------- Toggles on or off a breakpoint.
    trace (alias: t) ------- Set tracepoint.
    watch ------------------ Set watchpoint.


Viewing program variables and memory:
    args ----------------- Print function arguments.
    display -------------- Print value of an expression every time the program stops.
    examinemem (alias: x)  Examine raw memory at the given address.
    locals --------------- Print local variables.
    print (alias: p) ----- Evaluate an expression.
    regs ----------------- Print contents of CPU registers.
    set ------------------ Changes the value of a variable.
    vars ----------------- Print package variables.
    whatis --------------- Prints type of an expression.


Listing and switching between threads and goroutines:
    goroutine (alias: gr) -- Shows or changes current goroutine
    goroutines (alias: grs)  List program goroutines.
    thread (alias: tr) ----- Switch to the specified thread.
    threads ---------------- Print out info for every traced thread.


Viewing the call stack and selecting frames:
    deferred --------- Executes command in the context of a deferred call.
    down ------------- Move the current frame down.
    frame ------------ Set the current frame, or execute command on a different frame.
    stack (alias: bt)  Print stack trace.
    up --------------- Move the current frame up.


Other commands:
    config --------------------- Changes configuration parameters.
    disassemble (alias: disass)  Disassembler.
    dump ----------------------- Creates a core dump from the current process state
    edit (alias: ed) ----------- Open where you are in $DELVE_EDITOR or $EDITOR
    exit (alias: quit | q) ----- Exit the debugger.
    funcs ---------------------- Print list of functions.
    help (alias: h) ------------ Prints the help message.
    libraries ------------------ List loaded dynamic libraries
    list (alias: ls | l) ------- Show source code.
    source --------------------- Executes a file containing a list of delve commands
    sources -------------------- Print list of source files.
    transcript ----------------- Appends command output to a file.
    types ---------------------- Print list of types


Type help followed by a command for full documentation.
(dlv)

每个Go程序的入口是main.main()函数,可以用break命令在此设置一个断点:

代码语言:javascript
复制
(dlv) break main.main
Breakpoint 1 set at 0x10ad04a for main.main() ./delve.go:7

后通过breakpoints命令 缩写bp 查看已经设置的所有断点:

代码语言:javascript
复制
(dlv) bp
Breakpoint runtime-fatal-throw (enabled) at 0x1033f60 for runtime.throw() /usr/local/go/src/runtime/panic.go:982 (0)
Breakpoint unrecovered-panic (enabled) at 0x1034320 for runtime.fatalpanic() /usr/local/go/src/runtime/panic.go:1065 (0)
        print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0x10ad04a for main.main() ./delve.go:7 (0)

通过实验我们发现除了我们刚才设置的main的断点,dlv还自己设置了一个panic的断点。

如果想查看有哪些包级变量可以用vars 命令

代码语言:javascript
复制
vars main
runtime.main_init_done = chan bool nil
runtime.mainStarted = false

如果想让程序运行到下一个断点可以用命令continue 缩写c

代码语言:javascript
复制
(dlv) c
> main.main() ./delve.go:7 (hits goroutine(1):1 total:1) (PC: 0x10ad04a)
     2:
     3: import "fmt"
     4:
     5: // dlv 调试器
     6:
=>   7: func main() {
     8:         nums := make([]int, 5)
     9:
    10:         for i := 0; i < len(nums); i++ {
    11:                 nums[i] = i * i
    12:         }

我们可以看到它运行到main函数停下来了。

接下来我们单步执行进入main函数内部,可以用命令 next 缩写 n。

代码语言:javascript
复制
(dlv) n
> main.main() ./delve.go:8 (PC: 0x10ad058)
     3: import "fmt"
     4:
     5: // dlv 调试器
     6:
     7: func main() {
=>   8:         nums := make([]int, 5)
     9:
    10:         for i := 0; i < len(nums); i++ {
    11:                 nums[i] = i * i
    12:         }
    13:

进入到函数内部后可以通过args, locals来查看参数 和 局部变量。

代码语言:javascript
复制
(dlv) args
(no args)
(dlv) locals
(no locals)

现在看还是都是空的。

因为函数main 没有参数,所以args 是空的。

而locals命令

我们单步执行一下,再来看下变量。

代码语言:javascript
复制
(dlv) n
> main.main() ./delve.go:10 (PC: 0x10ad083)
     5: // dlv 调试器
     6:
     7: func main() {
     8:         nums := make([]int, 5)
     9:
=>  10:         for i := 0; i < len(nums); i++ {
    11:                 nums[i] = i * i
    12:         }
    13:
    14:         fmt.Println(nums)
    15: }
(dlv) locals
nums = []int len: 5, cap: 5, [...]

这时候可以看到局部变量 nums 长度5 容量5了。

有的时候我们需要在循环中到达, 指定的条件才进行断点。

下面我们通过组合使用break和condition这2个命令,在循环内部设置一个条件断点,当循环中变量i == 3的时候,断点生效。

然后我们通过cotinue命令执行到设置的断点。

代码语言:javascript
复制
(dlv) break delve.go:11
Breakpoint 2 set at 0x10ad0a2 for main.main() ./delve.go:11
(dlv) condition 2 i==3
(dlv) c
> main.main() ./delve.go:11 (hits goroutine(1):1 total:1) (PC: 0x10ad0a2)
     6:
     7: func main() {
     8:         nums := make([]int, 5)
     9:
    10:         for i := 0; i < len(nums); i++ {
=>  11:                 nums[i] = i * i
    12:         }
    13:
    14:         fmt.Println(nums)
    15: }

这时候我们再用locals命令查看变量,发现i已经是3了。打印了一下nums发现前面3个数,已经填充好了。

代码语言:javascript
复制
(dlv) locals
nums = []int len: 5, cap: 5, [...]
i = 3
(dlv) p nums
[]int len: 5, cap: 5, [0,1,4,0,0]

好了,今天的dlv 就介绍到这里了,下一篇我们继续介绍用dlv 调试汇编程序。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-10-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码上读书 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档