网站首页 > 资源文章 正文
Delve是一个使用Go语言开发的专门用于Go语言的调试工具。Delve项目的地址是https://github.com/go-delve/delve, 这个项目的目标是为Go提供一个简单的、功能齐全、易于调用和使用的调试器。当前Go语言支持GDB、LLDB、Delve三种调试工具,LLDB是MacOS系统推荐的,已经成为了XCode默认调试器,但GDB和LLDB对Go的支持比不上Delve这个专门为Go设计和开发的调试工具。 Goland和Go for Visual Studio Code这种集成开发环境的调试功能也都是集成了delve的。 本文将学习Delve命令行的基本使用。
开发环境准备
Delve使用Go开发,支持Linux、MacOS、Windows平台,本文的学习环境基于Linux,首先构建一个golang-debug的Docker镜像,关于对Delve的学习过程都在这个镜像的容器中进行。 下面给出这个镜像构建的Dockerfile:
FROM alpine:3.14.2
ENV LANG=C.UTF-8
# Here we install GNU libc (aka glibc) and set C.UTF-8 locale as default.
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories &&\
ALPINE_GLIBC_BASE_URL="https://github.com/sgerrand/alpine-pkg-glibc/releases/download" && \
ALPINE_GLIBC_PACKAGE_VERSION="2.33-r0" && \
ALPINE_GLIBC_BASE_PACKAGE_FILENAME="glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
ALPINE_GLIBC_BIN_PACKAGE_FILENAME="glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
ALPINE_GLIBC_I18N_PACKAGE_FILENAME="glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
apk add --no-cache --virtual=.build-dependencies wget ca-certificates && \
echo \
"-----BEGIN PUBLIC KEY-----\
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApZ2u1KJKUu/fW4A25y9m\
y70AGEa/J3Wi5ibNVGNn1gT1r0VfgeWd0pUybS4UmcHdiNzxJPgoWQhV2SSW1JYu\
tOqKZF5QSN6X937PTUpNBjUvLtTQ1ve1fp39uf/lEXPpFpOPL88LKnDBgbh7wkCp\
m2KzLVGChf83MS0ShL6G9EQIAUxLm99VpgRjwqTQ/KfzGtpke1wqws4au0Ab4qPY\
KXvMLSPLUp7cfulWvhmZSegr5AdhNw5KNizPqCJT8ZrGvgHypXyiFvvAH5YRtSsc\
Zvo9GI2e2MaZyo9/lvb+LbLEJZKEQckqRj4P26gmASrZEPStwc+yqy1ShHLA0j6m\
1QIDAQAB\
-----END PUBLIC KEY-----" | sed 's/ */\n/g' > "/etc/apk/keys/sgerrand.rsa.pub" && \
wget \
"$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
"$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
"$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
apk add --no-cache \
"$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
"$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
"$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
\
rm "/etc/apk/keys/sgerrand.rsa.pub" && \
/usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true && \
echo "export LANG=$LANG" > /etc/profile.d/locale.sh && \
\
apk del glibc-i18n && \
\
rm "/root/.wget-hsts" && \
apk del .build-dependencies && \
rm \
"$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
"$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
"$ALPINE_GLIBC_I18N_PACKAGE_FILENAME"
RUN apk update --no-cache && apk add ca-certificates --no-cache && \
apk add tzdata --no-cache && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
RUN apk add --no-cache -X http://mirrors.aliyun.com/alpine/edge/community go
RUN apk add --no-cache binutils gdb vim &&\
apk add --no-cache -X http://mirrors.aliyun.com/alpine/edge/testing vim-go delve
上面的Dockerfile主要包含以下几个步骤:
- 以docker官方alpine:3.14.2作为基础镜像构建
- 第5~44行是在alpine镜像的基础上按照glibc
- 第51行为使用alpine community repository中当前最新的go package安装go语言
- 第54行安装了一些开发和调试工具,包括:
- binutils是一个二进制工具集,包含了ELF文件格式解析器readelf,可以解析Linux上可执行文件的文件格式
- gdb调试器
- vim文本编辑器
- vim-govim的go插件
- delve go语言调试器
ELF (Executable and Linkable Format)是一种为可执行文件,目标文件,共享链接库和内核转储(core dumps)准备的标准文件格式。 Linux和很多类Unix操作系统都使用这个格式。
使用上面的Dockerfile构建出golang-debug:latest这个容器镜像后,就可以启动容器作为我们的开发环境,这里没有使用docker,我的容器开发环境为nerdctl+containerd,在使用nerdctl启动containerd容器之前,创建一个volume用来存放我们开发的go代码。
nerdctl volume create go-projects
nerdctl volume ls
VOLUME NAME DIRECTORY
go-projects /var/lib/nerdctl/1935db59/volumes/default/go-projects/_data
下面使用nerdctl启动golang-debug:latest的容器,进入开发环境:
nerdctl run -it --rm --privileged -v go-projects:/root golang-debug:latest
上面的命令启动了Go开发环境的容器,将go-projects这个volume挂载到了容器中的/root目录,另外还需要注意为了在容器中使用delve调试器,需要以--privileged启动容器。
Delve简单使用
下面对Delve做一个简单使用,进入golang-debug容器的开发环境:
nerdctl run -it --rm --privileged -v go-projects:/root golang-debug:latest
进入到工作目录/root中,创建一个用于存放项目的目录:
cd /root
mkdir projects
cd projects
使用go mod创建一个名称为hello的go工程:
mkdir hello && cd hello
go mod init hello
使用vim编写一个如下main.go的文件:
package main
import "fmt"
var pi = 3.14
func main() {
s := []int{}
for i := 0; i < 5; i++ {
s = append(s, i)
}
fmt.Println(pi, s)
}
项目的目录结构如下:
hello
├── go.mod
└── main.go
在项目目录中(go.mod文件所在目录中)执行dlv debug命令进入调试:
dlv debug
Type 'help' for list of commands.
(dlv)
输入help命令就可以查看Delve进行调试可以使用的命令帮助:
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.
types ---------------------- Print list of types
Type help followed by a command for full documentation.
实际常用上面命令的别名,几个比较常用的如下:
- b可以打断点。dlv中打断点有多种方式,b后边可以跟一个*地址,包名.函数名,或者文件名:行号的形式
- bp打印当前启用的所有断点
- c表示continue,从当前断点跳转到下一个断点
- n表示next,从当前行代码行执行到下一步
- vars命令可以查看全部包级别的变量,一般通过正则表达式过滤查看,例如vars main查看main包中的变量。
- args命令可以查看函数的参数
- locals可以查看函数的局部变量
- p即print查看某个变量的具体值,或者评估一个表达式的值
- stack可以查看当前函数执行的栈帧信息
- goroutine查看当前的goroutine信息
- goroutines查看程序的goroutine列表
下面实操一下,在main.main函数上打一个断点:
(dlv) b main.main
Breakpoint 1 set at 0x49474f for main.main() ./main.go:7
(dlv)
下面通过bp命令查看当前已经启用的所有断点:
(dlv) bp
Breakpoint runtime-fatal-throw (enabled) at 0x432ca0 for runtime.throw() /usr/lib/go/src/runtime/panic.go:1188 (0)
Breakpoint unrecovered-panic (enabled) at 0x433000 for runtime.fatalpanic() /usr/lib/go/src/runtime/panic.go:1271 (0)
print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0x49474f for main.main() ./main.go:7 (0)
可以看到除了我们在main函数打的断点外,delve调试器还为我们在runtime包中的panic相关的两个函数上打上了断点。
下面查看一下main包中包级别的变量:
(dlv) vars main
runtime.main_init_done = chan bool nil
runtime.mainStarted = false
main.pi = 3.14
下面再在main.go的第10行打一个断点:
(dlv) b main.go:10
Breakpoint 2 set at 0x49479f for main.main() ./main.go:10
(dlv) bp
Breakpoint runtime-fatal-throw (enabled) at 0x432ca0 for runtime.throw() /usr/lib/go/src/runtime/panic.go:1188 (0)
Breakpoint unrecovered-panic (enabled) at 0x433000 for runtime.fatalpanic() /usr/lib/go/src/runtime/panic.go:1271 (0)
print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0x49474f for main.main() ./main.go:7 (1)
Breakpoint 2 (enabled) at 0x49479f for main.main() ./main.go:10 (0)
(dlv)
使用c命令从断点1直接跳转到断点2:
(dlv) c
> main.main() ./main.go:10 (hits goroutine(1):1 total:1) (PC: 0x49479f)
5: var pi = 3.14
6:
7: func main() {
8: s := []int{}
9: for i := 0; i < 5; i++ {
=> 10: s = append(s, i)
11: }
12: fmt.Println(pi, s)
13: }
(dlv)
查看一下函数的参数和本地局部变量:
(dlv) args
(no args)
(dlv) locals
s = []int len: 0, cap: 0, []
i = 0
(dlv)
下面就可以使用n命令一步步执行了:
(dlv) n
> main.main() ./main.go:9 (PC: 0x494811)
4:
5: var pi = 3.14
6:
7: func main() {
8: s := []int{}
=> 9: for i := 0; i < 5; i++ {
10: s = append(s, i)
11: }
12: fmt.Println(pi, s)
13: }
(dlv) n
> main.main() ./main.go:10 (hits goroutine(1):2 total:2) (PC: 0x49479f)
5: var pi = 3.14
6:
7: func main() {
8: s := []int{}
9: for i := 0; i < 5; i++ {
=> 10: s = append(s, i)
11: }
12: fmt.Println(pi, s)
13: }
(dlv) locals
s = []int len: 1, cap: 1, [...]
i = 1
(dlv)
查看一下当前s变量的值:
p s
[]int len: 1, cap: 1, [0]
查看一下当前执行函数的栈帧信息:
(dlv) stack
0 0x000000000049479f in main.main
at ./main.go:10
1 0x0000000000435273 in runtime.main
at /usr/lib/go/src/runtime/proc.go:255
2 0x000000000045f6c1 in runtime.goexit
at /usr/lib/go/src/runtime/asm_amd64.s:1581
(dlv)
查看一下当前的goroutine信息:
(dlv) gr
Thread 1540 at ./main.go:10
Goroutine 1:
Runtime: ./main.go:10 main.main (0x49479f)
User: ./main.go:10 main.main (0x49479f)
Go: <autogenerated>:1 runtime.newproc (0x461b89)
Start: /usr/lib/go/src/runtime/proc.go:145 runtime.main (0x435080)
(dlv)
查看一下所有的groutines:
(dlv) grs
* Goroutine 1 - User: ./main.go:10 main.main (0x49479f) (thread 1540)
Goroutine 2 - User: /usr/lib/go/src/runtime/proc.go:367 runtime.gopark (0x435692) [force gc (idle)]
Goroutine 3 - User: /usr/lib/go/src/runtime/proc.go:367 runtime.gopark (0x435692) [GC sweep wait]
Goroutine 4 - User: /usr/lib/go/src/runtime/proc.go:367 runtime.gopark (0x435692) [GC scavenge wait]
Goroutine 5 - User: /usr/lib/go/src/runtime/proc.go:367 runtime.gopark (0x435692) [finalizer wait]
[5 goroutines]
(dlv)
Delve子命令
前面我们通过一个例子简单演示了使用delve调试go程序的main包。
dlv提供了很多子命令应对不同的使用场景:
dlv attach - Attach to running process and begin debugging.
dlv connect - Connect to a headless debug server.
dlv core - Examine a core dump.
dlv dap - [EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP).
dlv debug - Compile and begin debugging main package in current directory, or the package specified.
dlv exec - Execute a precompiled binary, and begin a debug session.
dlv replay - Replays a rr trace.
dlv test - Compile test binary and begin debugging program.
dlv trace - Compile and begin tracing program.
dlv version - Prints version.
dlv log - Help about logging flags
dlv backend - Help about the --backend flag
例如我们还对go的测试调试需求,需要用到dlv test子命令,调试go的单元测试。 另外,还可以通过dlv实现远程调试。
参考
- https://github.com/go-delve/delve
猜你喜欢
- 2024-10-14 手机内存不足?不要胡乱清理了,学会了让手机空间瞬间释放!
- 2024-10-14 「GCTT 出品」Golang 中的微服务-第二部分-Docker 和 go-micro
- 2024-10-14 口袋妖怪Go新版本更新分析解读 0.23.1更新内容
- 2024-10-14 Oculus CTO: Quest仍然支持安装第三方APK
- 2024-10-14 Pokemongo虚拟定位教程 Pokemongo电脑版虚拟定位怎么设置?
- 2024-10-14 Pokemon go PC版安装教程 pokemongo电脑版gps模拟器安装
- 2024-10-14 口袋妖怪go手环最新消息 手环功能详解
- 2024-10-14 最简单的Go Dockerfile编写姿势,没有之一
- 2024-10-14 512MB内存都不卡 谷歌亲自为安卓开发手机管家
- 2024-10-14 干货分享:用 Go 从头实现一个迷你 Docker—Gocker
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- 电脑显示器花屏 (79)
- 403 forbidden (65)
- linux怎么查看系统版本 (54)
- 补码运算 (63)
- 缓存服务器 (61)
- 定时重启 (59)
- plsql developer (73)
- 对话框打开时命令无法执行 (61)
- excel数据透视表 (72)
- oracle认证 (56)
- 网页不能复制 (84)
- photoshop外挂滤镜 (58)
- 网页无法复制粘贴 (55)
- vmware workstation 7 1 3 (78)
- jdk 64位下载 (65)
- phpstudy 2013 (66)
- 卡通形象生成 (55)
- psd模板免费下载 (67)
- shift (58)
- localhost打不开 (58)
- 检测代理服务器设置 (55)
- frequency (66)
- indesign教程 (55)
- 运行命令大全 (61)
- ping exe (64)
本文暂时没有评论,来添加一个吧(●'◡'●)