当前位置: 首页 > news >正文

【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.hlibbuffer.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
    go install github.com/go-delve/delve/cmd/dlv@latest
    
    可以在gopath文件夹下找到
    ~/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定位崩溃参考 说在前面 测试环境&#xff1a;WSL2go版本&#xff1a;go version go1.23.1 linux/amd64gcc版本&#xff1a;gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0cmake版本&#xff1a;3.22.1 文件树 ├── buffer …...

(笔记自用)位运算总结+LeetCode例题:颠倒二进制位+位1的个数

一.位运算总结: 在解题之前理解一下为什么需要位运算&#xff1f;它的本质是什么&#xff1f; 力扣上不少位运算相关的题&#xff0c;并且很多题也会用到位运算的技巧。这又是为什么&#xff1f; 位运算的由来 在计算机里面&#xff0c;任何数据最终都是用数字来表示的&…...

024.PL-SQL进阶—游标

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…...

从零开始使用树莓派debian系统使用opencv4.10.0进行人脸识别(保姆级教程)

一、总体架构 本文主要是使用树莓派自带的csi摄像头&#xff0c;搭配上opencv4.10.0进行物体的识别。本文使用的环境是python3.7.3&#xff0c;环境不一样有可能安装的opencv的过程也会很不一样&#xff0c;但是python的环境我们可以自己自行安装。 二、树莓派系统的安装 本文…...

golang qq邮件发送验证码

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

鸿蒙 OS 开发单词打卡 APP 项目实战 20240922 笔记和源码分享

配套有完整的录播课, 需要的私信. 零基础入门级别, 有点前端基础都能学会. 效果截图: 代码截图: 页面完整代码: import { AnswerStatus } from ../enums/AnswerStatus import { PracticeStatus } from ../enums/PracticeStatus import { getRandomQuestions, Question …...

力扣P1706全排列问题 很好的引入暴力 递归 回溯 dfs

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

使用Python Pandas导入数据库和文件数据

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

lef 中antenna解释

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

初试Bootstrap前端框架

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

mysql数据库:超键、候选键、主键与外键

mysql数据库&#xff1a;超键、候选键、主键与外键 1、超键&#xff08;Superkey&#xff09;2、候选键&#xff08;Candidate Key&#xff09;3、主键&#xff08;Primary Key&#xff09;4、外键&#xff08;Foreign Key&#xff09; &#x1f496;The Begin&#x1f496;点点…...

音频转MP3格式困难?如何轻松实现wav转mp3?

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

基于vue框架的大连盐业有限公司生产管理系统的设计与实现3hk5y(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;计划员,工艺员,生产建模,生产计划,生产信息,生产监视,工艺质量,盐政信息 开题报告内容 一、引言 随着信息技术的飞速发展和市场竞争的日益激烈&#xff0c;传统盐业企业如大连盐业有限公司正面临着转型升级的迫切需求。传统管理模式下…...

《深入理解JAVA虚拟机(第2版)》- 第13章 - 学习笔记【终章】

第13章 线程安全与锁优化 13.1 概述 面向过程的编程思想 将数据和过程独立分开&#xff0c;数据是问题空间中的客体&#xff0c;程序代码是用来处理数据的&#xff0c;这种站在计算机角度来抽象和解决问题的思维方式&#xff0c;称为面向对象的编程思想。 面向对象的编程思想…...

网络工程师学习笔记——网络互连与互联网(三)

TCP三次握手 建立TCP连接是通过三次握手实现的&#xff0c;采用三报文握手主要是为了防止已失效的连接请求报文突然又传送到了&#xff0c;因而产生错误 主动发起TCP连接建立的称为客户端 被动等待的为TCP服务器&#xff0c;二者之间需要交换三个TCP报文段 首先是客户端主动…...

【Tomcat】常见面试题整理 共34题

文章目录 1. 简述什么是Tomcat&#xff1f;2. Tomcat的缺省端口是多少&#xff0c;怎么修改&#xff1f;3. 简述Tomcat 目录结构及作用4. 简述Tomcat有几种部署方式&#xff1f;5. 简述Tomcat容器是如何创建servlet类实例&#xff1f;6. Tomcat有哪几种Connector运行模式&#…...

到时间没回家又不接电话?如何迅速确定孩子的位置?

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

接口自动化--commons内容详解-02

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

WanFangAi论文写作研究生论文写作神器在线生成真实数据,标注参考文献位置,表格公式代码流程图查重20以内,研究生论文写作技巧

WanFangAi是一个专业的学术论文辅助平台&#xff0c;它提供了一系列工具来帮助用户提升论文写作的效率和质量。以下是WanFangAi的一些核心功能:1.主题探索与文献搜索:用户可以输入关键词和研究领域&#xff0c;WanFangAi会迅速推荐合适的论文主题并提供相关的文献搜索服务。系统…...

cv2.waitkey(30) 按键盘无效

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

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

在 Spring Boot 项目里,MYSQL中json类型字段使用

前言&#xff1a; 因为程序特殊需求导致&#xff0c;需要mysql数据库存储json类型数据&#xff0c;因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...