栈windows linux,Linux+Windows: 程序崩溃时,在 C++ 代码中,如何获取函数调用栈信息...

2fda6bf9384f9d4afd6d0ea436045453.png

一、前言

程序在执行过程中 crash 是非常严重的问题,一般都应该在测试阶段排除掉这些问题,但是总会有漏网之鱼被带到 release 阶段。

因此,程序的日志系统需要侦测这种情况,在代码崩溃的时候获取函数调用栈信息,为 debug 提供有效的信息。

这篇文章的理论知识很少,直接分享 2 段代码:在 Linux 和 Windows 这 2 个平台上,如何用C++ 来捕获函数调用栈里的信息。

二、Linux 平台

1. 注册异常信号的处理函数

需要处理哪些异常信号

#include 

#include 

#include 

const std::map Signals = {

{SIGINT, "SIGINT"},

{SIGABRT, "SIGABRT"},

{SIGFPE, "SIGFPE"},

{SIGILL, "SIGILL"},

{SIGSEGV, "SIGSEGV"}

// 可以添加其他信号

};

注册信号处理函数

struct sigactionaction;

sigemptyset(&action.sa_mask);

action.sa_sigaction = &sigHandler;

action.sa_flags = SA_SIGINFO;

for(const auto &sigPair : Signals)

{

if (sigaction(sigPair.first, &action,NULL) 

fprintf(stderr, "Error: sigaction failed! \n");

}

2. 捕获异常,获取函数调用栈信息

void sigHandler(intsignum, siginfo_t *info, void *ctx)

{

const size_t dump_size = 50;

void *array[dump_size];

intsize= backtrace(array, dump_size);

char**symbols = backtrace_symbols(array,size);

std::ostringstream oss;

for(inti = 0; i 

{

char*mangleName = 0;

char*offsetBegin = 0;

char*offsetEnd = 0;

for(char*p = symbols[i]; *p; ++p)

{

if ('('== *p)

{

mangleName = p;

}

elseif ('+'== *p)

{

offsetBegin = p;

}

elseif (')'== *p)

{

offsetEnd = p;

break;

}

}

if (mangleName && offsetBegin && offsetEnd && mangleName 

{

*mangleName++ = '\0';

*offsetBegin++ = '\0';

*offsetEnd++ = '\0';

intstatus;

char*realName = abi::__cxa_demangle(mangleName, 0, 0, &status);

if (0 == status)

oss <

else

oss <

oss <

free(realName);

}

else

{

oss <

}

}

free(symbols);

oss <

std::cout <

}

三、Windwos 平台

在 Windows 平台下的代码实现,参考了国外某个老兄的代码,如下:

1. 设置异常处理函数

#include 

#include 

SetUnhandledExceptionFilter(exceptionHandler);

2. 捕获异常,获取函数调用栈信息

void exceptionHandler(LPEXCEPTION_POINTERS info)

{

CONTEXT *context = info->ContextRecord;

std::shared_ptr RaiiSysCleaner(nullptr, [&](void *) {

SymCleanup(GetCurrentProcess());

});

const size_t dumpSize = 64;

std::vector frameVector(dumpSize);

DWORD machine_type = 0;

STACKFRAME64 frame = {};

frame.AddrPC.Mode = AddrModeFlat;

frame.AddrFrame.Mode = AddrModeFlat;

frame.AddrStack.Mode = AddrModeFlat;

#ifdef _M_IX86

frame.AddrPC.Offset = context->Eip;

frame.AddrFrame.Offset = context->Ebp;

frame.AddrStack.Offset = context->Esp;

machine_type = IMAGE_FILE_MACHINE_I386;

#elif _M_X64

frame.AddrPC.Offset = context->Rip;

frame.AddrFrame.Offset = context->Rbp;

frame.AddrStack.Offset = context->Rsp;

machine_type = IMAGE_FILE_MACHINE_AMD64;

#elif _M_IA64

frame.AddrPC.Offset = context->StIIP;

frame.AddrFrame.Offset = context->IntSp;

frame.AddrStack.Offset = context->IntSp;

machine_type = IMAGE_FILE_MACHINE_IA64;

frame.AddrBStore.Offset = context.RsBSP;

frame.AddrBStore.Mode = AddrModeFlat;

#else

frame.AddrPC.Offset = context->Eip;

frame.AddrFrame.Offset = context->Ebp;

frame.AddrStack.Offset = context->Esp;

machine_type = IMAGE_FILE_MACHINE_I386;

#endif

for(size_tindex= 0;index

{

if (StackWalk64(machine_type,

GetCurrentProcess(),

GetCurrentThread(),

&frame,

context,

NULL,

SymFunctionTableAccess64,

SymGetModuleBase64,

NULL)) {

frameVector[index] = frame.AddrPC.Offset;

} else{

break;

}

}

std::string dump;

const size_t kSize = frameVector.size();

for(size_tindex= 0;index

dump += getSymbolInfo(index, frameVector);

dump += "\n";

}

std::cout <

}

主要是利用了 StackWalk64 这个函数,从地址转换为函数名称。

利用以上几个神器,基本上可以获取到程序崩溃时的函数调用栈信息,定位问题,有如神助!

【编辑推荐】

【责任编辑:姜华 TEL:(010)68476606】

点赞 0

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

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

相关文章

python vbs库_Python语言之requests库

发送请求、传递URL参数、定制headers、接受数据&#xff0c;处理数据等在Java中用httpclient jar包&#xff0c;在Python中用requests库&#xff0c;即使没有事先下载&#xff0c;在Pycharm开发工具中&#xff0c;出现提示时刻&#xff0c;同意安装即可1) 发送请求urlhttp://ba…

Linux中fdisk对应的c函数,linux下fdisk命令实战案例之详解

一、fdisk命令中参数介绍&#xff1a;1.查看硬盘使用情形#fdisk -l 观察硬盘之实体使用情形2.fdisk /dev/sda&#xff0c;进入硬盘分割模式1. 输入 m 显示所有命令列示。2. 输入 p 显示硬盘分割情形。3. 输入 a 设定硬盘启动区。4. 输入 n 设定新的硬盘分割区。4.1. 输入 e 硬盘…

cvs有机添加剂检测_美国ECI CVS 电镀添加剂分析仪QL-10EX

美国ECI CVS 电镀添加剂分析仪型 号&#xff1a;QL-10EX价 格&#xff1a;美国ECI CVS 电镀添加剂分析仪QL-10EXQL-5EX, QL-10EX,旧型号&#xff1a;QL-5E,QL-5, QL-10E,QL-10,QP-4000,QLC-5000产品介绍别名&#xff1a;电镀分析仪 循环剥离伏安测试仪 CVS测试仪 电镀成份分…

linux多台主机对比文件大小,Linux主机df和du出来的文件和磁盘大小不相同

df 查看磁盘大小和使用空间的命令 常用的是df -hdu 查看文件或者文件夹大小的命名 常用的是du -sh *一、问题现象的陈述1、先列出df的结果# df -hFilesystem Size Used Avail Use% Mounted on/dev/xvda1 20G 17G 2.3G 88% /tmpfs 1.9G 0 1.9G …

oracle rollup分组没有数据时为0_数据库周刊19│GBASE适配鲲鹏;MySQL窗口函数;OGG双向数据同步……...

摘要&#xff1a;墨天轮数据库周刊第19期发布啦&#xff0c;每周1次推送本周数据库相关热门资讯、精选文章、干货文档。本周分享GBASE适配鲲鹏&#xff1b; 疫情激活COBOL语言&#xff1b;TiDB数据库的未来&#xff1b;Oracle与double write&#xff1b;MySQL8.0 窗口函数&…

c语言中语句作用,学习C语言的用途~

原标题&#xff1a;学习C语言的用途~C是基础的语言C语言被广泛用于操作系统和编译器的开发功能非常强虽然现在不是最流行但是最基础的东西是也比较好学的语言如:金山的创始人江明从30多岁开始学语言学的就是C对C的评价相当高C语言是一种计算机程序设计语言。它既有高级语言的特…

c语言字符型计算器,求用c语言编程四则混合运算计算器?

#include#include#includechar token[61]; /*存放表达式字符串的数组*/int n0;void error(void) /*报告错误函数*/{printf("ERROR!\n");exit(1);}void match(char expected) /*检查字符匹配的函数*/{if(token[n]expected)token[n]getchar();else error();}double ter…

qt写python教程视频_GitHub - qtg666/codeparkshare: Python初学者(零基础学习Python、Python入门)书籍、视频、资料、社区推荐...

PythonSharePython初学者(零基础学习Python、Python入门)书籍、视频、资料、社区推荐本文 主要 针对 零基础 想学习Python者。本文本文由史江歌(shijianggegmail.com QQ:499065469)根据互联网资料收集整理而成&#xff0c;感谢互联网&#xff0c;感谢各位的分享。鸣谢&#xff…

攻击linux的samba,Samba 中间人攻击漏洞(CVE-2015-5296)

Samba 中间人攻击漏洞(CVE-2015-5296)发布日期&#xff1a;2015-12-19更新日期&#xff1a;2016-01-01受影响系统&#xff1a;Samba Samba 4.x-4.1.22Samba Samba 4.3.x-4.3.3Samba Samba 4.2.x-4.2.7Samba Samba 3.x描述&#xff1a;CVE(CAN) ID: CVE-2015-5296Samba是在Linux…

C语言如何编辑资源文件,用C语言做个简单的计算机,上面是代码,请教上资源文件在哪里编写,要新建什么文件...

当前位置:我的异常网 C语言 用C语言做个简单的计算机&#xff0c;上面是代码&#xff0c;请教上资源用C语言做个简单的计算机&#xff0c;上面是代码&#xff0c;请教上资源文件在哪里编写&#xff0c;要新建什么文件www.myexceptions.net 网友分享于&#xff1a;2013-07-30 …

换发型算法_GitHub - fredliu168/yry: yry(颜如玉)—— 一个实现人脸融合的算法,可以接近腾讯天天P图疯狂变脸功能的效果...

颜如玉颜如玉 —— python 人脸融合程序&#xff0c;可实现类似天天P图疯狂换脸、face人脸融合效果项目描述最近随着各种技术的发展&#xff0c;图像方面的人脸处理技术越来越广泛。各大相机软件都有美颜、贴图、换发型、变脸等功能。天天P图与Face也都推出人脸处理的 API&…

单片机c语言 外部中断,单片机C语言代码:外部中断,按下中断按键LED不亮,LED1正常亮...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼* 名称&#xff1a;外部中断* 日期&#xff1a;2013-9-10* 晶振:11.0592MHZ******************************************************************/#include //包含头文件&#xff0c;对IO进行定义&#xff0c;可以选中后右击&…

电脑生成siri语音_Siri for Mac:苹果电脑也有语音助手

今天&#xff0c;美国专利和商标局公布了苹果的一项长达92页的专利申请&#xff0c;描述了一种功能和复杂程度远远超过目前 Mac 听写功能的技术&#xff0c;这些功能介绍可以被简单的总结成 Siri for Mac。这项专利被称为“桌面环境下的智能数字助理”。苹果 Siri 在2011年登陆…

c语言 手动实现sizeof,sizeof究竟是怎样实现的?

sizeof&#xff0c;是在编译的时候&#xff0c;查找符号表&#xff0c;判断类型&#xff0c;然后根据基础类型来取值的&#xff0c;如果是struct则是看类型声明符号表来判定&#xff0c;如果字符串则是通过常量表来判断&#xff0c;具体可以参考编译原理的符号表管理章节&#…

python bytes转换为string_Python3 中 bytes 和 string 之间的互相转换

Table of ContentsPython3 最重要的新特性大概要算是对文本(text)和二进制数据(binary data)作了更为清晰的区分。文本总是 Unicode&#xff0c;由 str 类型表示。二进制数据则由 bytes 类型表示。那么什么是 bytes、什么是 Unicode 呢&#xff1f;首先计算机能存储的唯一东西就…

c语言中如何打出草花图案,C语言程序设计程设计题目1.doc

C语言程序设计程设计题目1通信工程10级C语言课程设计任务书各位同学可以自由组合&#xff0c;不超过以下题目中所规定的人数进行选题(不允许重复选题)。辅导时间&#xff1a;另定地点&#xff1a;软件中心(语音楼8楼)答辩检查时间&#xff1a;18周星期五上午8&#xff1a;00起1…

android 字体像素转换工具类_android工具类,转换大小写,保留小数点处理方法

import java.text.DecimalFormat;import java.util.Scanner;/*** 金额转换** author Administrator*/public class ConvertMoney {// 大写数字private final static String[] STR_NUMBER {"零", "壹", "贰", "叁", "肆", &…

android 百度地图开发 怎么减小包的大小,最新的百度地图Android开发包中,如何隐藏右下角的放大缩小控件...

2016-02-24 回答// 隐藏缩放控件int childcount mmapview.getchildcount();view zoom null;for (int i 0; i < childcount; i) {view child mmapview.getchildat(i);if (child instanceof zoomcontrols) {zoom child;break;}}zoom.setvisibility(view.gone);// 隐藏比例…

python换源还是不行_浅析Python3 pip换源问题

pip安装源背景#在实际开发中, 可能要大量使用第三方模块(包), 更换至国内下载源, 可大幅提升下载速度"""1、采用国内源&#xff0c;加速下载模块的速度2、常用pip源&#xff1a;-- 豆瓣&#xff1a;https://pypi.douban.com/simple-- 阿里&#xff1a;https://m…

vs2017 cmake android,CMake构建VS2017工程

1 安装VS2017/cmake2 工程开发3 生成VS2017工程4 参考资料1 安装VS2017/cmake软件安装&#xff1a;Visual Studio官网下载Visual Studio Community 2017,该版本是适用于学生、开源和个人开发人员的功能完备的免费IDE。Visual Studio Community 2017还可以免费安装Incredibuild&…