Uso de go debugger delve(dlv) (con ejemplos y explicaciones de comandos comunes)

Prefacio

GoLos depuradores actuales incluyen lo siguiente:

  • GDBLa primera herramienta de depuración rara vez se utiliza ahora.
  • LLDB macOSLas herramientas de depuración estándar recomendadas por el sistema Gotienen soporte limitado para algunas funciones propietarias.
  • DelveGoLas herramientas de depuración creadas específicamente para el lenguaje son las más utilizadas.

Este artículo explica brevemente cómo utilizar Delveherramientas para depurar Goprogramas, la versión utilizada delvees 1.20.1.

Instalar

  1. Go1.16y después:
# 最新版本:
$ go install github.com/go-delve/delve/cmd/dlv@latest

# 指定分支:
$ go install github.com/go-delve/delve/cmd/dlv@master

# 特定版本或伪版本:
$ go install github.com/go-delve/delve/cmd/[email protected]
$ go install github.com/go-delve/delve/cmd/[email protected]
  1. Puedes descargar el código fuente tú mismo.build
$ git clone https://github.com/go-delve/delve
$ cd delve
$ go install github.com/go-delve/delve/cmd/dlv

Ejemplo

Hablemos de dos métodos comúnmente utilizados:

  • dlv debug
  • dlv attach

depuración dlv

  1. Crear main.goarchivo:
package main

import (
    "fmt"
)

func main() {
    
    
    nums := make([]int, 5)
    for i := 0; i <len(nums); i++ {
    
    
        nums[i] = i * i
    }
    fmt.Println(nums)
}
  1. Ingrese el directorio donde se encuentra el paquete en la línea de comando y luego ingrese dlv debugel comando para ingresar a la depuración
$ dlv debug
Type 'help' for list of commands.

#设置断点:main.main
(dlv)b main.main 
Breakpoint 1 set at 0xff3c0a for main.main() ./main.go:7

# 查看已设置的所有断点,我们发现除了我们自己设置的 main.main 函数断点外,Delve 内部已经为 panic 异常函数设置了一个断点。
(dlv) bp 
Breakpoint runtime-fatal-throw (enabled) at 0xc97940 for runtime.throw() d:/go1.18/go/src/runtime/panic.go:982 (0)
Breakpoint unrecovered-panic (enabled) at 0xc97ce0 for runtime.fatalpanic() d:/go1.18/go/src/runtime/panic.go:1065 (0)
        print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0xd03c0a for main.main() ./main.go:7 (0)

# 查看全局变量(可通过正则参数过滤)
(dlv) vars main
runtime.main_init_done = chan bool nil
runtime.mainStarted = false

# 运行到下个断点处
(dlv) c
> main.main() ./main.go:7 (hits goroutine(1):1 total:1) (PC: 0xd03c0a)
     2:
     3: import (
     4:     "fmt"
     5: )
     6:
=>   7: func main() {
    
    
     8:     nums := make([]int, 5)
     9:     for i := 0; i <len(nums); i++ {
    
    
    10:         nums[i] = i * i
    11:     }
    12:     fmt.Println(nums)
	
# 单步执行
(dlv) n
> main.main() ./main.go:8 (PC: 0xd03c18)
     3: import (
     4:     "fmt"
     5: )
     6:
     7: func main() {
    
    
=>   8:     nums := make([]int, 5)
     9:     for i := 0; i <len(nums); i++ {
    
    
    10:         nums[i] = i * i
    11:     }
    12:     fmt.Println(nums)
    13: }

# 查看传入函数的参数
(dlv) args
(no args) # 这里main函数没有参数

# 查看局部变量
(dlv) locals
(no locals) # 这里还没初始化nums

# 再下一步,初始化nums了,可以看到有局部变量了
(dlv) n
> main.main() ./main.go:9 (PC: 0xd03c43)
     4:     "fmt"
     5: )
     6:
     7: func main() {
    
    
     8:     nums := make([]int, 5)
=>   9:     for i := 0; i <len(nums); i++ {
    
    
    10:         nums[i] = i * i
    11:     }
    12:     fmt.Println(nums)
    13: }
(dlv) locals
nums = []int len: 5, cap: 5, [...]

# 组和使用 break 和 condition 命令设置条件断点
(dlv) b main.go:10
Breakpoint 2 set at 0xd03c62 for main.main() ./main.go:10
(dlv) bp
Breakpoint runtime-fatal-throw (enabled) at 0xc97940 for runtime.throw() d:/go1.18/go/src/runtime/panic.go:982 (0)
Breakpoint unrecovered-panic (enabled) at 0xc97ce0 for runtime.fatalpanic() d:/go1.18/go/src/runtime/panic.go:1065 (0)
        print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0xd03c0a for main.main() ./main.go:7 (1) # Breakpoint 1(这个 1 是断点的编号,设置条件断点,清理断点等时候会用到)
Breakpoint 2 (enabled) at 0xd03c62 for main.main() ./main.go:10 (0)
(dlv) cond 2 i==3 # 这里设置条件断点 i 等于 3

# 继续 continue 执行到刚设置的条件断点,输出局部变量
(dlv) c
> main.main() ./main.go:10 (hits goroutine(1):1 total:1) (PC: 0xd03c62)
     5: )
     6:
     7: func main() {
    
    
     8:     nums := make([]int, 5)
     9:     for i := 0; i <len(nums); i++ {
    
    
=>  10:         nums[i] = i * i
    11:     }
    12:     fmt.Println(nums)
    13: }
(dlv) locals
nums = []int len: 5, cap: 5, [...]
i = 3
(dlv) print nums
[]int len: 5, cap: 5, [0,1,4,0,0]

# 查看栈帧信息
(dlv) stack
0  0x0000000000d03c62 in main.main
   at ./main.go:10
1  0x0000000000c99f28 in runtime.main
   at d:/go1.18/go/src/runtime/proc.go:250
2  0x0000000000cc18a1 in runtime.goexit
   at d:/go1.18/go/src/runtime/asm_amd64.s:1571
   
# 退出
(dlv) q

adjuntar dlv

Este método se puede utilizar para la depuración de servicios comunes http.

  1. Crear main.goarchivo:
package main

import (
	"log"
	"net/http"
)

func main() {
    
    
	http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
    
    
		nums := make([]int, 5)
		for i := 0; i < len(nums); i++ {
    
    
			nums[i] = i * i
		}
		writer.Write([]byte("OK"))
	})

	err := http.ListenAndServe(":4781", nil)
	if err != nil {
    
    
		log.Fatalln(err)
	}
}
  1. go build -gcflags="all=-N -l" main.goGenerar main.exe, ** Nota: Debe agregarse aquí -gcflags="all=-N -l"; de lo contrario, el compilador puede optimizar el código y no se puede establecer el punto de interrupción.
  2. Ejecutar main.exey obtener el programa.PID
  3. dlv attach PIDIngrese a la depuración
$ dlv attach 22300
Type 'help' for list of commands.
(dlv) b main.go:12
Breakpoint 1 set at 0x6f34ee for main.main.func1() ./main.go:12
(dlv) c # 执行到这里之后,会卡住
  1. Visite la página web http://127.0.0.1:4781/helloy podrá ver que el punto de interrupción que acabamos de alcanzar ha entrado en vigor.
> main.main.func1() ./main.go:12 (hits goroutine(6):1 total:1) (PC: 0x6f34ee)
     7:
     8: func main() {
     9:         http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
    10:                 nums := make([]int, 5)
    11:                 for i := 0; i < len(nums); i++ {
=>  12:                         nums[i] = i * i
    13:                 }
    14:                 writer.Write([]byte("OK"))
    15:         })
    16:
    17:         err := http.ListenAndServe(":4781", nil)

El siguiente uso es consistente con dlv debugel uso mencionado anteriormente.

otro

Después de ingresar dlva la depuración, puede ingresar helppara ver la información de ayuda:

(dlv) help
The following commands are available:

Running the program:
    call ------------------------ 继续进程,注入函数调用(实验!!!)
    continue (alias: c) --------- 运行直到断点或程序终止。
    next (alias: n) ------------- 运行至下一行。
    rebuild --------------------- 重新生成可执行文件,若可执行文件不是delve生成的,则不能使用。
    restart (alias: r) ---------- 重新启动进程。
    step (alias: s) ------------- 单步执行程序。
    step-instruction (alias: si)  单步执行单个cpu指令。
    stepout (alias: so) --------- 跳出当前函数。

Manipulating breakpoints:
    break (alias: b) ------- 设置断点。
    breakpoints (alias: bp)  查看所有断点信息。
    clear ------------------ 删除断点。
    clearall --------------- 删除多个断点。
    condition (alias: cond)  设置断点条件。
    on --------------------- 命中断点时执行命令。
    toggle ----------------- 打开或关闭断点。
    trace (alias: t) ------- 设置跟踪点。
    watch ------------------ 设置观察点。

Viewing program variables and memory:
    args ----------------- 打印函数参数。
    display -------------- 每次程序停止时打印表达式的值。
    examinemem (alias: x)  检查给定地址的原始内存。
    locals --------------- 打印局部变量。
    print (alias: p) ----- 对表达式求值。
    regs ----------------- 打印CPU寄存器的内容。
    set ------------------ 更改变量的值。
    vars ----------------- 打印包变量。
    whatis --------------- 打印表达式的类型。

Listing and switching between threads and goroutines:
    goroutine (alias: gr) -- 显示或更改当前goroutine。
    goroutines (alias: grs)  列出程序所有goroutine。
    thread (alias: tr) ----- 切换到指定的线程。
    threads ---------------- 打印每个跟踪线程的信息。

Viewing the call stack and selecting frames:
    deferred --------- 在延迟调用的上下文中执行命令。
    down ------------- 向下移动当前帧。
    frame ------------ 设置当前帧,或在其他帧上执行命令。
    stack (alias: bt)  打印堆栈跟踪。
    up --------------- 向上移动当前帧。

Other commands:
    config --------------------- 更改配置参数。
    disassemble (alias: disass)  反汇编程序。
    dump ----------------------- 从当前进程状态创建核心转储
    edit (alias: ed) ----------- 自己指定编辑器编辑,读的环境变量 $DELVE_EDITOR 或者 $EDITOR
    exit (alias: quit | q) ----- 退出调试器。
    funcs ---------------------- 打印函数列表。
    help (alias: h) ------------ 打印帮助消息。
    libraries ------------------ 列出加载的动态库
    list (alias: ls | l) ------- 显示源代码。
    source --------------------- 执行包含 delve 命令的文件
    sources -------------------- 打印源文件列表。
    transcript ----------------- 将命令输出追加到文件。
    types ---------------------- 打印类型列表

Type help followed by a command for full documentation.

Si desea ver el uso específico del comando, puede hacerlo help 命令(ejemplo help call:).

Aquí hay algunas explicaciones de comandos comunes:

dlvinstrucción

Orden explicar
adjuntar Este comando hará que Delve tome el control de un proceso que ya se está ejecutando e inicie una nueva sesión de depuración. Al salir de una sesión de depuración, puede optar por mantener el proceso en ejecución o finalizarlo.
depurar De forma predeterminada, sin parámetros, Delve compilará el paquete "principal" en el directorio actual y comenzará la depuración. Alternativamente, puede especificar un nombre de paquete y Delve compilará el paquete e iniciará una nueva sesión de depuración.
ejecutivo Hace que Delve ejecute el binario y lo adjunte inmediatamente, iniciando una nueva sesión de depuración. Tenga en cuenta que si un binario se compila sin las optimizaciones desactivadas, puede resultar difícil depurarlo correctamente. Considere compilar archivos binarios de depuración con -gcflags="all=-N -l" en Go 1.10 o posterior, y -gcflags="-N -l" en versiones anteriores de Go.
prueba El comando de prueba le permite iniciar una nueva sesión de depuración en el contexto de las pruebas unitarias. De forma predeterminada, Delve depurará las pruebas en el directorio actual. Además, puede especificar el nombre de un paquete en el que Delve depurará las pruebas. Doble guión: se puede utilizar para pasar parámetros al programa de prueba.
versión Verifique la versión dlv

Ingrese dlvel comando después de la depuración

Orden abreviatura explicar
romper b Establecer punto de interrupción
puntos de interrupción pb Ver todos los puntos de interrupción actuales
claro / Eliminar punto de interrupción
limpiar todo / Eliminar múltiples puntos de interrupción
palanca / Activar o desactivar puntos de interrupción
continuar C Continuar la ejecución hasta un punto de interrupción o el final del programa.
próximo norte Ejecute la siguiente línea de código
Reanudar r Vuelva a ejecutar el programa
paso s Siguiente paso en la ejecución del código
instrucción paso a paso y Ejecute la siguiente línea de código de máquina.
salir entonces Salir de la función que se está ejecutando actualmente
argumentos / Entrada de función de impresión
mostrar / Imprima el valor de la variable agregada para mostrar cada vez que se ejecute la siguiente línea de código o el siguiente punto de interrupción
lugareños / Imprimir variables locales
imprimir pag Imprimir el resultado de una expresión.
colocar / Establecer el valor de una variable
vars / Ver variables globales
qué es / Ver tipo de variable
desmontar desalentar Ver código descompilado, código de máquina
salida salir/q abandonar
funciones / Imprimir todas las funciones utilizadas por el programa.
ayuda h información de ayuda
lista ls/l imprimir código
examinarme X Verifique la memoria sin procesar en la dirección dada

Depuración de puntos de interrupción de GoLand

GoLandTambién se utiliza delvepara la depuración. Utiliza --listenparámetros para iniciar un servicio. Este artículo no lo presentará en detalle.

1. go build -gcflags "all=-N -l" -o main.exe
2. dlv --listen=127.0.0.1:5739 --headless=true --api-version=2 --check-go-version=false --only-same-user=false exec main.exe --

GoLandDepuración usando

Resumir

delveLa herramienta es muy poderosa. Este artículo presenta su uso básico. Espero que pueda solucionar rápidamente los problemas cuando encuentre problemas. Si está instalado, también puede usarlo para GoLanddepurar Goland. Es relativamente más rápido, pero cuando encuentre algunos problemas, Necesito verificar el ensamblado. Al escribir código u otras aplicaciones de alta gama, aún no he descubierto GoLandcómo usarlo, por lo que delvees mejor comprender el uso del comando para que no se confunda cuando llegue el momento.

referencia

Supongo que te gusta

Origin blog.csdn.net/DisMisPres/article/details/128866995
Recomendado
Clasificación