【go/方法记录】cgo静态库编译以及使用dlv定位cgo崩溃问题
目录
- 说在前面
- 文件树
- 静态库编译
- cgo使用
- 崩溃模拟
- 使用dlv定位崩溃
- 参考
说在前面
- 测试环境:WSL2
- go版本:go version go1.23.1 linux/amd64
- gcc版本:gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
- cmake版本:3.22.1
文件树
├── buffer # go package
│ ├── buffer.go
│ ├── buffer_go.h
│ └── libbuffer.a
├── c # c/c++源代码
│ ├── CMakeLists.txt # cmake
│ ├── buffer # c/c++源代码
│ │ ├── buffer.h
│ │ ├── buffer_go.cpp
│ │ └── buffer_go.h
│ ├── lib # 静态库目录
│ │ └── libbuffer.a
│ └── main.cpp
└── main.go
静态库编译
- 这部分和
go
无关,按照正常的静态库编译走就行,这里我使用cmake
进行编译 buffer.h
#ifndef __BUFFER_H__ #define __BUFFER_H__ #include <string>struct Buffer {std::string* s_;Buffer(int size) {this->s_ = new std::string(size, char('\0'));}~Buffer() {delete this->s_;}int Size() const {return this->s_->size();}char* Data() {return (char*)this->s_->data();} };#endif
- 然后我们需要对其进行封装,这部分可以参考这里
buffer_go.h
#define DLLIMPORT#ifdef __cplusplus extern "C" { #endiftypedef struct Buffer_T Buffer_T;Buffer_T* NewBuffer(int size); void DeleteBuffer(Buffer_T* p); int BufferSize(Buffer_T* p);#ifdef __cplusplus } #endif
buffer_go.cpp
#include "buffer.h" #include "buffer_go.h"#ifdef __cplusplus extern "C" { #endifstruct Buffer_T: Buffer {Buffer_T(int size): Buffer(size) {}~Buffer_T() {} };DLLIMPORT Buffer_T* NewBuffer(int size) {auto p = new Buffer_T(size);return p; }DLLIMPORT void DeleteBuffer(Buffer_T* p) {delete p; }DLLIMPORT int BufferSize(Buffer_T* p) {return p->Size(); }#ifdef __cplusplus } #endif
- 然后就是
cmake
cmake_minimum_required(VERSION 3.2) project(Buffer) set(CMAKE_BUILD_TYPE "RELEASE") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")# 设置编译后库文件目录 set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)include_directories(${PROJECT_SOURCE_DIR}/buffer) # 添加编译可执行文件 aux_source_directory(${PROJECT_SOURCE_DIR}/buffer SRC)add_library(buffer STATIC ${SRC}) add_executable(buffer_exemain.cpp)# 链接主程序 target_link_libraries(buffer_exePRIVATEbuffer)
- 执行编译
动态库将生成在目录cd ./c cmake . make
./c/lib
cgo使用
- 首先将
buffer_go.h
、libbuffer.a
拷贝到./buffer
目录下,并创建buffer.go
文件。注意,以下注释中的#include "buffer_go.h"
和import "C"
不要有空行 buffer.go
package buffer// #cgo CFLAGS: -I. // #cgo CXXFLAGS: -std=c++11 // #cgo LDFLAGS: -L./ -lbuffer -lstdc++ // // #include "buffer_go.h" import "C"type BufferT C.Buffer_Tfunc NewBuffer(size int) *BufferT {p := C.NewBuffer(C.int(size))return (*BufferT)(p) }func DeleteBuffer(p *BufferT) {C.DeleteBuffer((*C.Buffer_T)(p)) }func BufferSize(p *BufferT) C.int {return C.BufferSize((*C.Buffer_T)(p)) }
- 然后是
main.go
package mainimport ("fmt" )func main() {b := buffer.NewBuffer(2)fmt.Println(buffer.BufferSize(b))buffer.DeleteBuffer(b) }
- 执行程序输出
~/cgotest$ go run main.go 2
崩溃模拟
-
正常
go
中的崩溃,例如空指针调用等是可以通过recover
处理的,例如func main() {go func() {defer func() {if err := recover(); err != nil {fmt.Println("err: ", string(debug.Stack()))}}()time.Sleep(5 * time.Second)var b uint32var a uint32_ = b / a}()var i intfor {time.Sleep(time.Second)i++fmt.Println(i)} }
可以看到进程可以继续运行
~/cgotest$ go run main.go 1 2 3 4 err: goroutine 18 [running]: runtime/debug.Stack()/usr/local/go/src/runtime/debug/stack.go:26 +0x5e main.main.func1.1()/home/xx/cgotest/main.go:14 +0x2a panic({0x49cb60?, 0x54d840?})/usr/local/go/src/runtime/panic.go:785 +0x132 main.main.func1()/home/xx/cgotest/main.go:23 +0x3f created by main.main in goroutine 1/home/xx/cgotest/main.go:11 +0x1a5 6
-
而对于
cgo
中的崩溃,目前go
是没法进行recover
的,会导致进程直接崩溃package mainimport ("cgotest/cgotest/buffer""fmt""runtime/debug""time" )func main() {go func() {defer func() {if err := recover(); err != nil {fmt.Println("err: ", string(debug.Stack()))}}()time.Sleep(5 * time.Second)b := buffer.NewBuffer(2)buffer.DeleteBuffer(b)b = nilfmt.Println(buffer.BufferSize(b))}()var i intfor {time.Sleep(time.Second)i++fmt.Println(i)} }
~/cgotest$ go run main.go 1 2 3 4 SIGSEGV: segmentation violation PC=0x4930b4 m=5 sigcode=1 addr=0x0 signal arrived during cgo executiongoroutine 6 gp=0xc000007dc0 m=5 mp=0xc000100008 [syscall]: runtime.cgocall(0x492550, 0xc000076750)goroutine 6 gp=0xc000007dc0 m=5 mp=0xc000100008 [syscall]: runtime.cgocall(0x492550, 0xc000076750)/usr/local/go/src/runtime/cgocall.go:167 +0x4b fp=0xc000076728 sp=0xc0000766f0 pc=0x462f8b cgotest/cgotest/buffer._Cfunc_BufferSize(0x0)_cgo_gotypes.go:52 +0x47 fp=0xc000076750 sp=0xc000076728 pc=0x475b87 main.main.func1.BufferSize.3(0x0)/home/xx/cgotest/buffer/buffer.go:22 +0x3b fp=0xc000076788 sp=0xc000076750 pc=0x4923fb cgotest/cgotest/buffer.BufferSize(...)/home/xx/cgotest/buffer/buffer.go:22 main.main.func1()/home/xx/cgotest/main.go:29 +0x6c fp=0xc0000767e0 sp=0xc000076788 pc=0x49234c runtime.goexit({})/usr/local/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000767e8 sp=0xc0000767e0 pc=0x46e601 created by main.main in goroutine 1/home/xx/cgotest/main.go:12 +0x1a
-
可以看到进程退出并输出了堆栈信息
使用dlv定位崩溃
- 虽然崩溃时的堆栈信息有标准输出,但是有时标准输出中的堆栈信息可能会被覆盖掉,少了最前面的信息,这个时候可以开启coredump并使用dlv来定位
- 启用
coredump
在进程崩溃后会生成ulimit -c unlimited GOTRACEBACK=crash go run main.go
coredump
文件 - 查看
coredump
文件目录
可以看到文件生成在~/cgotest$ cat /proc/sys/kernel/core_pattern /mnt/wslg/dumps/core.%e
/mnt/wslg/dumps/
~/cgotest$ ll /mnt/wslg/dumps/ total 6684 -rw------- 1 le le 83562496 Sep 21 16:04 core.main
- 安装
dlv
可以在gopath文件夹下找到go install github.com/go-delve/delve/cmd/dlv@latest
~/cgotest$ /home/xx/go/bin/ dlv gopls staticcheck
- 使用
结果如下# dlv core 二进制程序 coredump文件 ~/go/bin/dlv core cgotest /mnt/wslg/dumps/core.main
~/cgotest$ ~/go/bin/dlv core cgotest /mnt/wslg/dumps/core.main Type 'help' for list of commands. (dlv) bt0 0x000000000046fde1 in runtime.raiseat /usr/local/go/src/runtime/sys_linux_amd64.s:1541 0x000000000044b625 in runtime.dieFromSignalat /usr/local/go/src/runtime/signal_unix.go:9422 0x000000000044bc86 in runtime.sigfwdgoat /usr/local/go/src/runtime/signal_unix.go:11543 0x000000000044a625 in runtime.sigtrampgoat /usr/local/go/src/runtime/signal_unix.go:4324 0x000000000046fde1 in runtime.raiseat /usr/local/go/src/runtime/sys_linux_amd64.s:1535 0x000000000044b625 in runtime.dieFromSignalat /usr/local/go/src/runtime/signal_unix.go:9426 0x000000000044b1a6 in runtime.crashat /usr/local/go/src/runtime/signal_unix.go:1031 Sending output to pager...0 0x000000000046fde1 in runtime.raiseat /usr/local/go/src/runtime/sys_linux_amd64.s:1541 0x000000000044b625 in runtime.dieFromSignalat /usr/local/go/src/runtime/signal_unix.go:9422 0x000000000044bc86 in runtime.sigfwdgoat /usr/local/go/src/runtime/signal_unix.go:11543 0x000000000044a625 in runtime.sigtrampgoat /usr/local/go/src/runtime/signal_unix.go:4324 0x000000000046fde1 in runtime.raiseat /usr/local/go/src/runtime/sys_linux_amd64.s:1535 0x000000000044b625 in runtime.dieFromSignalat /usr/local/go/src/runtime/signal_unix.go:9426 0x000000000044b1a6 in runtime.crashat /usr/local/go/src/runtime/signal_unix.go:10317 0x000000000044b1a6 in runtime.sighandlerat /usr/local/go/src/runtime/signal_unix.go:8068 0x000000000044a726 in runtime.sigtrampgoat /usr/local/go/src/runtime/signal_unix.go:4909 0x00000000004930b4 in ???at ?:-1 10 0x000000000049256b in C._cgo_a4c0d8419d5e_Cfunc_BufferSizeat /tmp/go-build/buffer.cgo2.c:55 11 0x000000000046e284 in runtime.asmcgocallat /usr/local/go/src/runtime/asm_amd64.s:923 12 0x0000000000000000 in ???at ?:-1 13 0x0000000000462fb5 in runtime.cgocallat /usr/local/go/src/runtime/cgocall.go:185 14 0x0000000000475b87 in cgotest/cgotest/buffer._Cfunc_BufferSizeat _cgo_gotypes.go:52 15 0x00000000004923fb in main.main.func1.BufferSize.3at ./buffer/buffer.go:22 16 0x0000000000492345 in cgotest/cgotest/buffer.BufferSizeat ./buffer/buffer.go:22 17 0x0000000000492345 in main.main.func1at ./main.go:29 18 0x000000000046e601 in runtime.goexitat /usr/local/go/src/runtime/asm_amd64.s:1700
参考
- dlv安装
相关文章:

【go/方法记录】cgo静态库编译以及使用dlv定位cgo崩溃问题
目录 说在前面文件树静态库编译cgo使用崩溃模拟使用dlv定位崩溃参考 说在前面 测试环境:WSL2go版本:go version go1.23.1 linux/amd64gcc版本:gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0cmake版本:3.22.1 文件树 ├── buffer …...

(笔记自用)位运算总结+LeetCode例题:颠倒二进制位+位1的个数
一.位运算总结: 在解题之前理解一下为什么需要位运算?它的本质是什么? 力扣上不少位运算相关的题,并且很多题也会用到位运算的技巧。这又是为什么? 位运算的由来 在计算机里面,任何数据最终都是用数字来表示的&…...

024.PL-SQL进阶—游标
课 程 推 荐我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈虚 拟 环 境 搭 建 :…...

从零开始使用树莓派debian系统使用opencv4.10.0进行人脸识别(保姆级教程)
一、总体架构 本文主要是使用树莓派自带的csi摄像头,搭配上opencv4.10.0进行物体的识别。本文使用的环境是python3.7.3,环境不一样有可能安装的opencv的过程也会很不一样,但是python的环境我们可以自己自行安装。 二、树莓派系统的安装 本文…...

golang qq邮件发送验证码
验证码的使用场景 注册/登录:使用验证码可以有效减少垃圾账号注册和恶意登录;短信接口保护:高效减少防止短信接口被刷情况;提交/投票:有效减少恶意刷单、恶意提交、恶意投票等情况;密码找回:用…...

鸿蒙 OS 开发单词打卡 APP 项目实战 20240922 笔记和源码分享
配套有完整的录播课, 需要的私信. 零基础入门级别, 有点前端基础都能学会. 效果截图: 代码截图: 页面完整代码: import { AnswerStatus } from ../enums/AnswerStatus import { PracticeStatus } from ../enums/PracticeStatus import { getRandomQuestions, Question …...

力扣P1706全排列问题 很好的引入暴力 递归 回溯 dfs
代码思路是受一个洛谷题解里面大佬的启发。应该算是一个dfs和回溯的入门题目,很好的入门题目了下面我会先给我原题解思路我想可以很快了解这个思路。下面是我自己根据力扣大佬写的。 我会进行详细讲解并配上图辅助理解大家请往下看 #include<iostream> #inc…...

使用Python Pandas导入数据库和文件数据
大家好,在数据分析过程中,数据的导入是第一步,也是最重要的一步。Python的Pandas提供了强大的数据读取功能,支持从多种数据源导入数据,包括CSV、Excel、JSON、SQL数据库、网页等。Pandas库不仅能够处理常见的文件格式&…...

lef 中antenna解释
这些规则主要涉及集成电路设计中的天线效应(Antenna Effect)和通孔(Via)设计规则。 ANTENNAAREADIFFREDUCEPWL 这条规则指定了一个分段线性函数,用于根据连接到切割层的扩散区面积来计算cut_area的缩减因子。扩散区面积值应从0开始单调增加。如果没有定义此规则,PAR(mi)方程中的…...

初试Bootstrap前端框架
文章目录 一、Bootstrap概述二、Bootstrap实例1、创建网页2、编写代码3、代码说明4、浏览网页,查看结果5、登录按钮事件处理6、浏览网页,查看结果 三、实战小结 一、Bootstrap概述 大家好,今天我们将一起学习一个非常流行的前端框架——Boot…...

mysql数据库:超键、候选键、主键与外键
mysql数据库:超键、候选键、主键与外键 1、超键(Superkey)2、候选键(Candidate Key)3、主键(Primary Key)4、外键(Foreign Key) 💖The Begin💖点点…...

音频转MP3格式困难?如何轻松实现wav转mp3?
格式多样化为我们带来了灵活性和创意的无限可能,但同时,不同格式间的转换也成为了不少用户面临的难题。尤其是当你手握珍贵的WAV音频文件,却希望它们能在更多设备上流畅播放或节省存储空间时,wav转mp3的需求便应运而生。WAV以其无…...

基于vue框架的大连盐业有限公司生产管理系统的设计与实现3hk5y(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
系统程序文件列表 项目功能:计划员,工艺员,生产建模,生产计划,生产信息,生产监视,工艺质量,盐政信息 开题报告内容 一、引言 随着信息技术的飞速发展和市场竞争的日益激烈,传统盐业企业如大连盐业有限公司正面临着转型升级的迫切需求。传统管理模式下…...

《深入理解JAVA虚拟机(第2版)》- 第13章 - 学习笔记【终章】
第13章 线程安全与锁优化 13.1 概述 面向过程的编程思想 将数据和过程独立分开,数据是问题空间中的客体,程序代码是用来处理数据的,这种站在计算机角度来抽象和解决问题的思维方式,称为面向对象的编程思想。 面向对象的编程思想…...

网络工程师学习笔记——网络互连与互联网(三)
TCP三次握手 建立TCP连接是通过三次握手实现的,采用三报文握手主要是为了防止已失效的连接请求报文突然又传送到了,因而产生错误 主动发起TCP连接建立的称为客户端 被动等待的为TCP服务器,二者之间需要交换三个TCP报文段 首先是客户端主动…...

【Tomcat】常见面试题整理 共34题
文章目录 1. 简述什么是Tomcat?2. Tomcat的缺省端口是多少,怎么修改?3. 简述Tomcat 目录结构及作用4. 简述Tomcat有几种部署方式?5. 简述Tomcat容器是如何创建servlet类实例?6. Tomcat有哪几种Connector运行模式&#…...

到时间没回家又不接电话?如何迅速确定孩子的位置?
当孩子未按时回家且无法通过电话联系时,家长往往会感到焦虑。此时,如何迅速确定孩子的位置成为许多家长迫切需要解决的问题。 利用智能手机定位技术是最常见的方法之一。大多数智能手机都内置GPS定位功能,通过“查找设备”应用,家…...

接口自动化--commons内容详解-02
上篇文章主要讲解了接口自动化主要架构框架,这篇文庄主要讲解commons中的内容 1. requests_utils.py 首先讲解这个工具类,主要是因为在接口自动化中,基本都有的接口都是发送请求,获取响应结果,唯一不同的是࿰…...

WanFangAi论文写作研究生论文写作神器在线生成真实数据,标注参考文献位置,表格公式代码流程图查重20以内,研究生论文写作技巧
WanFangAi是一个专业的学术论文辅助平台,它提供了一系列工具来帮助用户提升论文写作的效率和质量。以下是WanFangAi的一些核心功能:1.主题探索与文献搜索:用户可以输入关键词和研究领域,WanFangAi会迅速推荐合适的论文主题并提供相关的文献搜索服务。系统…...

cv2.waitkey(30) 按键盘无效
cv2.imshow("detection", color_image) # 窗口显示,显示名为 Capture_Videok cv2.waitKey(100) & 0xFF # 每帧数据延时 1ms,延时不能为 0,否则读取的结果会是静态帧 if k ord(s): # 键盘按一下s, 保存当前照片和机械臂位姿…...

【洛谷】P10417 [蓝桥杯 2023 国 A] 第 K 小的和 的题解
【洛谷】P10417 [蓝桥杯 2023 国 A] 第 K 小的和 的题解 题目传送门 题解 CSP-S1 补全程序,致敬全 A 的答案,和神奇的预言家。 写一下这篇的题解说不定能加 CSP 2024 的 RP 首先看到 k k k 这么大的一个常数,就想到了二分。然后写一个判…...

Ubuntu24.04 安装ssh开启22端口及允许root用户远程登录
1、安装openssh-server插件开启22端口访问 # 安装ssh会默认启动服务并开启22端口 apt update apt install openssh-server 2、开启root用户远程访问 激活root用户,设置root用户登录密码 hunterlocalhost:/$ sudo passwd root New password: Retype new password…...

STM32基础学习笔记-DHT11单总线协议面试基础题7
第七章、DHT11: 单总线协!议 常见问题 1、DHT11是什么 ?有什么特性 ? 2、单总线协议是什么 ?原理 ?DHT11的单总线协议的组成 ? ## 1、DHT11定义 单总线协议是一种用于在多个设备之间进行通信的协议,所有…...

Redisson分布式锁的概念和使用
Redisson分布式锁的概念和使用 一 简介1.1 什么是分布式锁?1.2 Redisson分布式锁的原理1.3 Redisson分布式锁的优势1.4 Redisson分布式锁的应用场景 二 案例2.1 锁竞争案例2.2 看门狗案例2.3 参考文章 前言 这是我在这个网站整理的笔记,有错误的地方请指出ÿ…...

uniapp小程序持续获取用户位置信息,后台位置获取
做一个小程序持续获取用户位置信息的功能,即使小程序切换到后台也能继续获取,getLocation这个api只有小程序在前台才能获取位置,所以不用这个 先申请一个腾讯地图key 在uniapp项目配置源码视图里加上这个代码 先获取权限,再开启…...
优化算法(五)—梯度下降算法(附MATLAB程序)
梯度下降算法(Gradient Descent)是一种常用的优化算法,用于寻找函数的局部最小值。它通过沿着函数梯度的反方向迭代地调整变量,以逐步找到最优解。梯度下降广泛应用于机器学习和深度学习中,特别是在训练模型时优化损失…...

TypeScript 设计模式之【单例模式】
文章目录 **单例模式**: 独一无二的特工我们为什么需要这样的特工?单例模式的秘密:如何培养这样的特工?特工的利与害代码实现单例模式的主要优点单例模式的主要缺点单例模式的适用场景总结 单例模式: 独一无二的特工 单例模式就像是一个秘密组织里的特殊特工。这…...

UDP与TCP那个传输更快
UDP(用户数据报协议)和 TCP(传输控制协议)是互联网协议栈中常用的两种传输层协议。它们在设计和应用上存在一些显著的差异,导致在传输速度和可靠性等方面表现不同。以下是它们之间的比较,特别是关于传输速度…...

如何把PDF样本册转换为网址链接
随着互联网的普及,将纸质或PDF格式的样本册转化为网址链接,以便于在线浏览和分享,变得越来越重要。本文将为您详细讲解如何将PDF样本册转换为网址链接,让您轻松实现线上展示和分享。 一、了解PDF样本册与网址链接 1. PDF样本册…...

centos7 semanage 离线安装 SELinux
centos7 semanage 离线安装 还是参考一下 换成阿里云的源 之后 ,在线更新不,不要用离线安装 centos7 更新 yum源 为 阿里云 LTS https://blog.csdn.net/wowocpp/article/details/142517908 CentOS7安装时使用"基础服务器"选项安装, 后发现没…...