Go编程语言的调试器Delve | Goland远程连接Linux开发调试(go远程开发)

文章目录

  • Go编程语言的调试器
    • 一、什么是Delve
    • 二、delve 安装
      • 安装报错
          • cgo: C compiler "gcc" not found: exec: "gcc": executable file not found in $PATH解决
    • 三、delve命令行使用
      • delve 常见的调试模式
      • 常用调试方法todo
      • 调试程序
        • 代码与动态库加载
        • 程序运行
        • 断点
        • 跟踪点
        • 变量和类型
        • 协程和线程
        • 内存和寄存器
        • 寄存器和汇编
    • 其他常用
      • 构建应用时禁用编译器优化
      • 逃逸分析
      • dlv trace追踪调用轨迹
    • 五、Goland远程连接Linux开发调试(goland+dlv远程调试)
    • 远程调试Debug优点
      • 首先,配置文件sftp同步映射
      • 服务器上开启Delve 服务
      • 利用IDE goland开始远程调试
    • 纯命令行远程调试

Go编程语言的调试器

调试go 程序的方法有 delve 或者 gdb

Golang 支持使用 gdb 来进行调试,这与 C 语言几乎是一致的。但 GDB 是一个通用性调试工具,不非常能直接地反映出 Golang 的特点,所以,推荐使用 delve(https://github.com/go-delve/delve),可以理解为是 Golang 版本的 GDB,使用方式大致与 gdb 一致。

Delve它类似于 GDB,但是更关注 Go 的运行时、数据结构以及其他内部的机制。

一、什么是Delve

Delve是Go编程语言的调试器。Delve 是用 Go 写的。

Delve 是一个针对 Go 程序的调试器。它类似于 GDB,但是更关注 Go 的运行时、数据结构以及其他内部的机制。

delve是golang推荐的专门go语言调试工具,用来替代gdb,因为:golang组织说delve能更好的理解go语言。

https://golang.org/doc/gdb
Note that Delve is a better alternative to GDB when debugging Go programs built with the standard toolchain. It understands the Go runtime, data structures, and expressions better than GDB. Delve currently supports Linux, OSX, and Windows on amd64. For the most up-to-date list of supported platforms, please see the Delve documentation.

GDB does not understand Go programs well. The stack management, threading, and runtime contain aspects that differ enough from the execution model GDB expects that they can confuse the debugger and cause incorrect results even when the program is compiled with gccgo. As a consequence, although GDB can be useful in some situations (e.g., debugging Cgo code, or debugging the runtime itself), it is not a reliable debugger for Go programs, particularly heavily concurrent ones. Moreover, it is not a priority for the Go project to address these issues, which are difficult.

请注意,当使用标准工具链构建的GO程序时,Delve是更好的GDB替代方案。它比GDB更加了解GO运行时,数据结构和表达式。DELVE目前支持AMD64上的Linux,OSX和Windows。有关支持平台最新列表,请参阅DELVE文档。

GDB不太了解GO程序。堆栈管理,线程和运行时包含从执行模型GDB中差异的方面,因此它们可以混淆调试器并使使用GCC Go编译程序时,即使程序编译。结果,虽然GDB在某些情况下有用(例如,调试CGO代码或调试运行时本身),但它不是用于GO程序的可靠调试器,特别是并发。此外,它不是去项目解决这些问题的优先事项,这很困难。

二、delve 安装

$ git clone https://github.com/go-delve/delve
$ cd delve
$ go install github.com/go-delve/delve/cmd/dlv

或者,在GO版本1.16或更高版本:

# Install the latest release:
$ go install github.com/go-delve/delve/cmd/dlv@latest# Install at tree head:
$ go install github.com/go-delve/delve/cmd/dlv@master# Install at a specific version or pseudo-version:
$ go install github.com/go-delve/delve/cmd/dlv@v1.7.3
$ go install github.com/go-delve/delve/cmd/dlv@v1.7.4-0.20211208103735-2f13672765fe

查看是否安装成功:

root@cka-k8s-master:~# dlv version
Delve Debugger
Version: 1.8.2
Build: $Id: dbb493ec14d1e7753504d016b1e1ef1665b75b16 $
root@cka-k8s-master:~#

官方参考: https://github.com/go-delve/delve/tree/master/Documentation/installation

安装报错

cgo: C compiler “gcc” not found: exec: “gcc”: executable file not found in $PATH解决
 apt install build-essential

三、delve命令行使用

基本用法
先通过输入dlv或dlv --help来查看支持的命令

dlv --help

从调试命令上看,dlv的调试命令和gdb相似,如果对于gdb调试比较熟悉,对于dlv也会比较容易上手,例如常用的命令及缩写:step(s)、continue©、break(b)。
调试工具,需要经常使用才会越用越熟!!!

可以通过描述看出每个dlv command所具有的功能,也可通过dlv [command] --help来查看每个命令所具有的功能。

delve 常见的调试模式

delve 常见的调试模式:

  • debug 模式:调试源代码。
    dlv debug:运行dlv debug test.go会先编译go源文件,同时执行attach命令进入调试模式,该命令会在当前目录下生成一个名为debug的可执行二进制文件,退出调试模式会自动被删除。
  • exec 模式:调试二进制执行文件。
    dlv exec executable_file :直接从二进制文件启动调试模式。如果要带参数执行需要添加–,如dlv exec executable_file -- -f xxx.conf
  • attach 模式:调试远程进程。
    dlv attach pid:类似与gdb attach pid,可以对正在运行的进程直接进行调试(pid为进程号)。

1、编译并开始调试当前目录下的包或者指定的包
在应用根目录(main.go 同级)下直接以 debug 模式启动应用,启动后会进入 Delve 的交互模式。

dlv debug xxx.go

// 注意:项目的main不在项目目录下的时候,直接在项目目录下dlv debug会报错

2、项目已运行,使用attach
// 找到项目运行的进程id,attach上去

ps aux | grep 项目名
dlv attach 进程id

在生产环境运行调试器可能需要额外的权限,所以与你的团队提前沟通是很明智的。

常用调试方法todo

TODO
https://www.cnblogs.com/realjimmy/p/13418508.html

调试程序

  • exec
# dlv exec [可执行程序]
  • attach
# dlv attach [pid]
  • debug
# dlv debug main.go
  • 调试core文件
# dlv core [可执行程序] [core文件]
  • 退出调试器
(dlv) exit
代码与动态库加载
  • 查看加载的动态库
(dlv) libraries
  • 列出所有的函数符号
(dlv) funcs
  • 打印所有的类型信息
(dlv) types
  • 列出所有源码文件
(dlv) sources
程序运行
  • 往下运行
(dlv) continue 
continue 可缩写为 c
  • 单步调试(进入某个函数)
(dlv) step

step 可缩写为 s

  • next 单步和多步
(dlv) next   # 向下执行一行
(dlv) next [n] 可以多行

next 可缩写为 n

  • 退出函数
(dlv) stepout

stepout可缩写为 so

断点
  • 查看断点
(dlv) bp
  • 函数断点
    包名.方法名
(dlv) b setting.Setup()  # 需要加上包名
  • 行号断点
    文件名:行号
(dlv) b main.go:8
  • 条件断点
    比如,下面代码是一段循环:
package mainimport "fmt"func main() { for i := 0; i < 10000; i++ {fmt.Println("i: ", i)}
}
(dlv) b main.go:7Breakpoint 1 (enabled) at 0x49774a for main.main() ./main.go:7 (0)
(dlv) cond 1 i == 100
  • 删除断点
(dlv) clear [breakpoint number]
(dlv) clearall  # 删除所有断点
  • 断点启用/禁用
(dlv) toggle 3
  • on 当断点命中的时候执行
跟踪点

设置一个跟踪点,这个跟踪点也是一个断点,只不过运行时候不会断住程序,只是打印一行信息,这个命令在某些场景是很有用的,比如你断住程序就会影响逻辑(业务有超时),而你仅仅是想打印某个变量而已,那么用这种类型的断点就行:

调用栈

  • 查看当前调用栈
(dlv) bt
  • 切换调用栈
(dlv) frame [number]
  • 上溯调用栈
(dlv) up

下一层调用栈

(dlv) down
  • 查看当前函数参数
(dlv) args
  • 查看当前函数局部参数
(dlv) locals
变量和类型
  • 打印变量
p arg

有时,我们需要打印的字符串过长,dlv 输出显示more,这时,我们可以通过配置max-string-len,来控制输出的长度。

(dlv) config max-string-len 99999
(dlv) config -listmax-string-len     9999...
  • 查看变量类型
(dlv) whatis [variables]
  • 查看所属包的所有变量
(dlv) vars [package name]
协程和线程
  • 显示所有的协程
(dlv) goroutines 

goroutines 可缩写为grs

  • 切换协程
(dlv) goroutine [goroutine number]

goroutine 可缩写为gr,然后bt可以查看协程栈

  • 查看所有线程
(dlv) threads
  • 切换线程
(dlv) thread [thread number]

thread 可缩写为tr

内存和寄存器
  • 显示内存
(dlv) examinemem [-fmt <format>] [-count|-len <count>] [-size <size>] <address>

examinemem 可缩写为x,format 可选为hex,
举例:

(dlv) x -fmt hex -count 20 -size 1 0xc00008af38
(dlv) x -fmt hex -count 20 -size 1 -x 0xc00008af38 + 8
(dlv) x -fmt hex -count 20 -size 1 -x &myVar
(dlv) x -fmt hex -count 20 -size 1 -x myPtrVar
寄存器和汇编
  • 反汇编
(dlv) disassemble
  • 单条执行机器指令
(dlv) step-instruction

step-instruction 可缩写为si

  • 打印寄存器
(dlv) regs [-a]

其他常用

构建应用时禁用编译器优化

为了保证进行 debug 时实际运行的代码与源代码相同,需要使用下面的命令构建应用以禁止编译器在编译时对代码进行优化。

go build 可以用 -gcflags 给 go 编译器传入参数

go build -gcflags="all=-N -l" -o bin/app

-N disable optimizations # 禁用优化
-l disable inlining # 禁用内联优化

查看详细的编译命令

go build -x ...

逃逸分析

变量在内存中的位置是堆还是栈?
go编译器中优化算法尽可能将函数中的局部变量分配到栈上。如果编译器无法确认函数返回后,有么有其他对象引用该变量,或者该变量非常大,或者变量大小无法判断(interface{}),那么编译器就会在堆上分配该变量。

可以使用编译器参数来对变量进行逃逸分析。逃逸分析主要涉及2个参数:

  • -m: 打印出逃逸分析的优化策略,可以同时使用多个,-m -m
  • -l: 禁用函数内联(inline)功能,这样能更好的观察逃逸情况。

比如,用下面命令对main.go 进行变量逃逸分析:

go build -gcflags "-l -m" .\main.go

dlv trace追踪调用轨迹

文件名为:hello.go
代码内容如下

package main 
import ( "fmt" "time" 
) 
func Test() { fmt.Println("hello") time.Sleep(1000 * 1000 * 100) 
} 
func Test2() { fmt.Println("world") time.Sleep(1000 * 1000 * 100) 
} 
func main() { for i := 0; i < 2; i++ { go Test() go Test2() } time.Sleep(1000 * 1000 * 2000) fmt.Println("end") 
}

dlv trace追踪调用轨迹

dlv trace hello.go
[root@3faf80b4461e go-example]# dlv trace hello.go 
world
hello
world
hello
end

dlv trace hello.go Test

[root@3faf80b4461e go-example]# dlv trace hello.go Test
world
> goroutine(9): main.Test2()
hello
> goroutine(6): main.Test()
world
> goroutine(7): main.Test2()
hello
> goroutine(8): main.Test()=> ()=> ()=> ()=> ()
end

五、Goland远程连接Linux开发调试(goland+dlv远程调试)

远程调试有两个方面,如何将本地编辑的代码保存到远端,如何在本地调试远程程序。

整体思路:

  1. Golang->SFTP 自动同步代码到linux开发服务器
  2. 需要先dlv 服务器端启动项目,
  3. 再在Goland中配置go remote启动连接到dlv服务器端,打断点调试

远程调试Debug优点

  • 极大的加快开发速度,减少给在代码中使用大量log来定位错误.
  • 最大程度的使用linux远程服务器环境, 极大的简化本地部署模拟服务器环境
  • 可以绕过数据库内网的限制
  • 不用依赖日志来定位错误(开发效率太低)
  • 完美的解决一些不支持windows开发的依赖

首先,配置文件sftp同步映射

  1. 打开Goland,选择File=》Plugins=》Install JetBrains plugins

搜索Remote Hosts Access,点击Install
在这里插入图片描述
在这里插入图片描述
2. 配置

Settings=》build, execution, deployment=》deployment

注意: 最新版本的 GoLand 不需要自己安装插件了,已经默认集成了。在Tools–> Deployment --> Configureation
在这里插入图片描述Goland SFTP 本地代码目录映射
在这里插入图片描述
勾选自动上传Goland菜单: Tools -> Deployment -> Auto Upload(Always)

当然,这块还有个简便的方案就是使用 smb。IDE直接操作就是linux上的go文件,也比较好用,也可以推荐。

服务器上开启Delve 服务

工具代码以及文件下载地址:delve 下载地址

然后自行编译代码或者直接使用文件夹中编译好的linux 上可用的二进制文件 dlv,然后在~/.bash_profile 中添加工具别名。

alias dlvdebug='/golang/bin/dlv debug --headless --listen=:2345 --api-version=2 --accept-multiclient'
  • –listen string 调试服务器监听地址
  • –headless 仅在headless模式下运行调试服务器. 启动的时候的–headless参数,会屏蔽掉系统的信号量。dlv启动停止的时候直接利用Ctrl-C无法停止项目
  • –accept-multiclient
  /golang/bin/dlv debug --help

在禁用优化的情况下编译程序,启动并附加到程序。

默认情况下,如果没有参数,Delve将在当前目录编译main包,并开始调试它。或者,您可以指定包名和Delve将编译该包,并开始新的调试。

dlv debug:运行dlv debug test.go会先编译go源文件,同时执行attach命令进入调试模式,该命令会在当前目录下生成一个名为debug的可执行二进制文件,退出调试模式会自动被删除。

利用IDE goland开始远程调试

注意保证服务器和客户端的代码一致!

服务器上开启Delve 服务之后,然后是在 本地goland IDE配置

右上角edit Configurations, + → Go Remote → 添加ip地址与端口

在这里插入图片描述

设置断点,进行调试
在 Goland 中左键点击即可打断点,再通过接口访问,即可触发对应的远程调试。

利用GoLand中的debug功能里的go remote一项,可以调试一个指定的host:port的项目。

纯命令行远程调试

  1. 服务端
    服务器命令行输入:
# dlv --headless --log --listen=:8181 attach $(pidof <server>)
  1. 调试机
    在调试机上准备好源码,执行:
#  dlv connect <ip>:8181
  1. dlv命令
打断点: b main.go:10
运行: c
单步运行: n
打印变量:p <vars>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/11051.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常用的简单友好的工单系统(免费)- WGCAT

最近在项目中&#xff0c;有工单系统的需求场景&#xff0c;所以想寻找一款轻量简单的运维工单软件&#xff0c;主要用来记录和处理工作中的一些故障、维护&#xff0c;主要用来记录设备的维护状态&#xff0c;包括服务器、主机、交换机那些 WGCAT&#xff0c;是一款简单轻量的…

知从科技战略客户经理张志强受邀出席2024 AutoSec中国汽车网络安全与数据安全峰会

4月11-12日&#xff0c;AutoSec8周年年会暨中国汽车网络安全及数据安全合规峰会在上海成功举办。此次峰会吸引了来自全球各地的头部汽车网络安全企业、OEM厂商、安全专家和学者等齐聚盛会&#xff0c;零距离共话智能网联汽车产业的新发展、新趋势。 知从科技董事长成云霞亲自带…

mapreduce | 自定义Partition分区(案例1)

1.需求 将学生成绩&#xff0c;按照各个成绩降序排序&#xff0c;各个科目成绩单独输出。 # 自定义partition 将下面数据分区处理&#xff1a; 人名 科目 成绩 张三 语文 10 李四 数学 30 王五 语文 20 赵6 英语 40 张三 数据 50 李四 语文 10 张三 英语 70 李四 英语…

MapReduce | 二次排序

1.需求 主播数据--按照观众人数降序排序&#xff0c;如果观众人数相同&#xff0c;按照直播时长降序 # 案例数据 用户id 观众人数 直播时长 团团 300 1000 小黑 200 2000 哦吼 400 7000 卢本伟 100 6000 八戒 250 5000 悟空 100 4000 唐僧 100 3000 # 期望结果 哦吼 4…

字典是如何实现的?Rehash 了解吗?

字典是 Redis 服务器中出现最为频繁的复合型数据结构。除了 hash 结构的数据会用到字典外&#xff0c;整个 Redis 数据库的所有 key 和 value 也组成了一个 全局字典&#xff0c;还有带过期时间的 key 也是一个字典。(存储在 RedisDb 数据结构中) 字典结构是什么样的呢&#xf…

vue3 自定义国际化、elementPlus 国际化

自定义国际化 1. 引入 vue-i18n 插件 pnpm install vue-i18nnext 2. 页面添加语言文件目录&#xff0c;添加自定义的语言文件 3.语言目录里添加 index.ts&#xff0c; 内容如下 import { createI18n } from "vue-i18n";// 自定义语言文件 import zhCN from "…

【C/C++】内存分布

本文第一部分主要介绍了程序内存区域的划分以及数据的存储。第二部分有一段代码和一些题目&#xff0c;全面直观得分析了程序中的数组在内存中的存储。 因为不同的数据有不同的存储需求&#xff0c;各区域满足不同的需求&#xff0c;所以程序内存会有区域的划分。 根据需求的不…

MFC重要的初始化函数InitInstance

MFC应用程序最早处理的类的初始化函数通常是CWinApp类的构造函数。CWinApp类是MFC应用程序的主类&#xff0c;负责整个应用程序的初始化和管理。 在MFC应用程序中&#xff0c;通常会创建一个派生自CWinApp类的应用程序类&#xff0c;例如CMyApp。在应用程序启动时&#xff0c;…

【数据结构(邓俊辉)学习笔记】二叉树01——二叉树表示与实现

文章目录 0.概述1.树1.1 应用1.2 有根树1.3 有序树1.4 路径环路1.5 深度 层。1.6 树的表示 2. 二叉树的概述3 二叉树实现3.1 二叉树节点3.2 二叉树节点操作接口3.3 二叉树的实现 0.概述 介绍下二叉树的表示与实现。 1.树 1.1 应用 后缀表达式。 相对于线性结构O&#xff08…

力扣HOT100 - 121. 买卖股票的最佳时机

解题思路&#xff1a; 每次遍历price&#xff0c;更新最小的cost和最大的profit class Solution {public int maxProfit(int[] prices) {int cost Integer.MAX_VALUE, profit 0;for (int price : prices) {cost Math.min(cost, price);profit Math.max(profit, price - c…

MFC的句柄概念以及句柄类型

在MFC&#xff08;Microsoft Foundation Class&#xff09;桌面应用程序中&#xff0c;窗口是通过句柄&#xff08;Handle&#xff09;来进行管理和操作的。 句柄是一个标识符&#xff0c;用于唯一标识和引用窗口、控件、设备上下文等对象。在MFC桌面应用程序中&#xff0c;常…

LeetCode100题总结

LeetCode100题总结 前言LeetCode100题总结题型梳理双指针11. 盛最多水的容器234.回文链表75.颜色分类206.反转链表142.环形链表215.三数之和 滑动窗口3. 无重复字符的最长子串209. 长度最小的子数组438. 找到字符串中所有字母异位词 广搜102. 二叉树的层序遍历200. 岛屿数量617…

一对一WebRTC视频通话系列(六)——部署到公网

本系列博客主要记录一对一WebRTC视频通话实现过程中的一些重点&#xff0c;代码全部进行了注释&#xff0c;便于理解WebRTC整体实现。 本专栏知识点是通过<零声教育>的音视频流媒体高级开发课程进行系统学习&#xff0c;梳理总结后写下文章&#xff0c;对音视频相关内容感…

leetcode--560和为k的子数组

问题 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1], k 2 输出&#xff1a;2示例 2&#xff1a; 输入&#xff1a;nums [1,2…

数据分析需要注意哪些法律法规

数据分析 前言一、数据处理过程二、数据收集阶段的法律规则数据收集应具备合法、正当、透明原则数据收集应坚持最小必要原则数据收集应遵守知情-同意规则数据收集应遵守目的明确性要求 三、数据储存的法律规则四、数据使用与处理的阶段的法律规则数据安全保护义务按照数据分级分…

【荣耀笔试题汇总】2024-05-11-荣耀春招笔试题-三语言题解(CPP/Python/Java)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新小米近期的春秋招笔试题汇总&#xff5e; &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f49…

【漏洞复现】泛微OA E-Cology portalTsLogin文件读取漏洞

漏洞描述&#xff1a; 泛微E-Cology是一款面向中大型组织的数字化办公产品&#xff0c;它基于全新的设计理念和管理思想&#xff0c;旨在为中大型组织创建一个全新的高效协同办公环境。泛微OA E-Cology portalTsLogin存在任意文件读取漏洞&#xff0c;允许未经授权的用户读取服…

了解当前经济,VBA一键获取不同货币实时汇率

了解当前经济数据,VBA一键获取不同货币间实时汇率 当下较火的经济新闻:黄金价格、日元贬值、美元加息等,咱们不去分析了解这些经济变动背后的动机及原因,做一点本份的事,如何用VBA获取不同货币之间的实时汇率。这肯定是需要联网的,现从“外汇查询” 网站(https://www.wa…

UnitTest / pytest 框架

文章目录 一、UnitTest框架1. TestCase使用2. TestSuite 和 TestRunner3. TestLoader4. Fixture装置5. UnitTest断言1. 登录案例 6. 参数化1. parameterized插件 7. unitTest 跳过 二、pytest 框架1. 运行方式3.读取配置文件(常用方式) 2. pytest执行用例的顺序1. 分组执行(冒烟…

重学JavaScript核心知识点(二)—— 详解Js中的模块化

详解Js中的模块化 1. 模块化的背景2. 来看一个例子3. 优雅的做法 —— 创建模块对象4. 模块与类&#xff08;class&#xff09;5. 合并模块6. 动态加载模块 1. 模块化的背景 JavaScript 在诞生之初是体积很小的&#xff0c;早期&#xff0c;它们大多被用来执行独立的脚本任务&…