python通过ctypes调用C/C++ SDK,当SDK异常时,同时打印C/C++/Python的栈信息

2024-05-14 20:28

本文主要是介绍python通过ctypes调用C/C++ SDK,当SDK异常时,同时打印C/C++/Python的栈信息,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

python通过ctypes调用C/C++ SDK,当SDK异常时,同时打印C/C++/Python的栈信息

  • 一.复现步骤
  • 二.输出

本文演示了python通过ctypes调用C/C++ SDK,当SDK异常时,同时打印C/C++/Python的栈信息.基于traceback、addr2line、PyErr_SetString、backtrace_symbols

一.复现步骤

cat > print_backtrace.h <<-'EOF'
#ifndef __PRINT_BACKTRACE_H__
#define __PRINT_BACKTRACE_H__
#ifdef __cplusplus
extern "C" {
#endif
void print_backtrace();
#ifdef __cplusplus
}
#endif
#endif // __PRINT_BACKTRACE_H__
EOFcat > print_backtrace.cpp <<-'EOF'
#include "print_backtrace.h"
#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <stdexcept>
#include <Python.h>#define MAX_FRAMES   128
#define BUFFER_SIZE  512void print_backtrace()
{// 1.打印调用栈void *buff[MAX_FRAMES] = { 0 };unsigned int depth = backtrace(buff, MAX_FRAMES);char **strings = backtrace_symbols(buff, depth);printf("-----------------------print_backtrace(c/c++)--------------------\n");for (int i = 0; i < MAX_FRAMES; i++){if (i >= depth) {break;}// 1.1 将地址转换为代码路径和行号{char cmdline[BUFFER_SIZE] = {0};snprintf(cmdline, BUFFER_SIZE, "bash ./parser.sh \"%s\"", strings[i]);FILE *pFd = popen(cmdline, "r");if ( pFd == nullptr ){printf("popen failed\n");return ;}char buf[BUFFER_SIZE] = {0};fread(buf, sizeof(buf)/sizeof (buf[0]), 1, pFd);printf("%s", buf);pclose(pFd); }        }free(strings);// 2.触发python异常if (!Py_IsInitialized()) {Py_Initialize();}        PyGILState_STATE gstate;gstate = PyGILState_Ensure();PyErr_SetString(PyExc_RuntimeError, "print_backtrace trigger_error");PyGILState_Release(gstate);
}
EOFcat > api.c <<-'EOF'
#include <stdio.h>
#include <stdlib.h>
#include "print_backtrace.h"int function_a() {printf("%s %d\n",__FILE__,__LINE__);print_backtrace();return 0;
}int function_b() {printf("%s %d\n",__FILE__,__LINE__);function_a();return 0;
}int function_c() {printf("%s %d\n",__FILE__,__LINE__);function_b();return 0;
}int function_d() {printf("%s %d\n",__FILE__,__LINE__);function_c();return 0;
}int function_e() {printf("%s %d\n",__FILE__,__LINE__);function_d();return 0;
}
EOFcat > parser.sh <<-'EOF'
#!/bin/bashline=`echo $1 | awk '{print $1}' | sed 's/[()]/ /g'`
so_path=`echo $line | awk '{print $1}'`if [ ! -f $so_path ];thenexit 0
fiaddr_path=`echo $line | awk '{print $2}'`
function_name=`echo $addr_path | awk -F+ '{print $1}'`
offset=`echo $addr_path | awk -F+ '{print $2}'`if [ $function_name ];thenfunction_base=`nm $so_path | grep -w "$function_name" | awk '{print $1}'`abs_addr=`echo "$function_base $offset" | gawk --non-decimal-data '{A="0x"$1;B=$2;printf "0x%x\n",A+B}'`debug_info=`addr2line -f $abs_addr -e $so_path`
elsedebug_info=`addr2line -f $offset -e $so_path`
fiecho $debug_info
EOFcat > main.py <<-'EOF'
import ctypes
import tracebackdef function_a():print("function_a")lib = ctypes.CDLL('./libapi.so')function_e = lib.function_efunction_e()def function_b():print("function_b")function_a()def function_c():print("function_c")function_b()def function_d():print("function_d")function_c()try:function_d()
except:print("-----------------------print_backtrace(python)--------------------")traceback.print_exc()
EOFg++ -fPIC -g -shared -o libprint_backtrace.so print_backtrace.cpp \-I /home/anaconda3/envs/demo/include/python3.10 \/home/anaconda3/envs/demo/lib/libpython3.10.so \-Wl,-rpath=/home/anaconda3/envs/demo/lib/gcc -fPIC -g -shared -o libapi.so api.c  -L . -lprint_backtrace -Wl,-rpath=.
python3 main.py

二.输出

function_d
function_c
function_b
function_a
api.c 30
api.c 24
api.c 18
api.c 12
api.c 6
-----------------------print_backtrace(c/c++)--------------------
print_backtrace /home/print_backtrace.cpp:18
function_a /home/api.c:8
function_b /home/api.c:14
function_c /home/api.c:20
function_d /home/api.c:26
function_e /home/api.c:32
ffi_call_unix64 :?
ffi_call_int ffi64.c:?
ffi_call ??:?
addr2line: DWARF error: can't find .debug_ranges section.
_ctypes_callproc.cold :?
addr2line: DWARF error: can't find .debug_ranges section.
PyCFuncPtr_call.cold :?
nm: /lib/x86_64-linux-gnu/libc.so.6: no symbols
?? ??:0
-----------------------print_backtrace(python)--------------------
RuntimeError: print_backtrace trigger_errorThe above exception was the direct cause of the following exception:Traceback (most recent call last):File "/home/main.py", line 39, in <module>function_d()File "/home/main.py", line 36, in function_dfunction_c()File "/home/main.py", line 32, in function_cfunction_b()File "/home/main.py", line 28, in function_bfunction_a()File "/home/main.py", line 24, in function_afunction_e()
SystemError: <_FuncPtr object at 0x7f10c6d4cdc0> returned a result with an exception set

这篇关于python通过ctypes调用C/C++ SDK,当SDK异常时,同时打印C/C++/Python的栈信息的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/989770

相关文章

Django开发时如何避免频繁发送短信验证码(python图文代码)

《Django开发时如何避免频繁发送短信验证码(python图文代码)》Django开发时,为防止频繁发送验证码,后端需用Redis限制请求频率,结合管道技术提升效率,通过生产者消费者模式解耦业务逻辑... 目录避免频繁发送 验证码1. www.chinasem.cn避免频繁发送 验证码逻辑分析2. 避免频繁

精选20个好玩又实用的的Python实战项目(有图文代码)

《精选20个好玩又实用的的Python实战项目(有图文代码)》文章介绍了20个实用Python项目,涵盖游戏开发、工具应用、图像处理、机器学习等,使用Tkinter、PIL、OpenCV、Kivy等库... 目录① 猜字游戏② 闹钟③ 骰子模拟器④ 二维码⑤ 语言检测⑥ 加密和解密⑦ URL缩短⑧ 音乐播放

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Python安装Pandas库的两种方法

《Python安装Pandas库的两种方法》本文介绍了三种安装PythonPandas库的方法,通过cmd命令行安装并解决版本冲突,手动下载whl文件安装,更换国内镜像源加速下载,最后建议用pipli... 目录方法一:cmd命令行执行pip install pandas方法二:找到pandas下载库,然后

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录