之前文章转载了 LINUX C/C++捕获段错误,打印出错的具体位置(精确到哪一行) , 但在arm-xilinx-linux-gnueabi-gcc 编译是无法通过,现在把能在arm-xilinx-linux-gnueabi-gcc下编译的源码发布如下:

/*
* 作者: leehomwu
* 日期: 2011-05-14
* 修订: 2011-06-11, 处理部分处理器会将出错时的 EIP 也入栈的情况
* 描述: 捕获段错误、浮点错误,输出发生错误时的具体位置、调用路径
* 使用: 在 main 函数所在文件包含该头文件即可
* 示例: 当发生段错误或浮点错误时,会向STDOUT打印调用路径上的指令地址,类似:signal[8] catched when running code at 80486f0signal[8] catched when running code at 80488easignal[8] catched when running code at 80488d9进一步运行命令行,解析指令地址:addr2line  80486f0 80488ea 80488d9 -s -C -f -e [可执行文件]得到输出:mainnewsig.cpp:14a()kk.cpp:23b()kk.cpp:19
*/#ifndef __SEGV_CATCH_H
#define __SEGV_CATCH_H#include <execinfo.h>
#include <signal.h>
#include <stdio.h>#ifndef __USE_GNU#define __USE_GNU#include <ucontext.h>#include <ucontext.h>#undef __USE_GNU
#else#include <ucontext.h>#include <sys/ucontext.h>
#endif#ifdef __cplusplusstatic void initSegvCatch(void);class C_SEGVCATCH{public:C_SEGVCATCH(){initSegvCatch();}};static C_SEGVCATCH C_segv_catch;
#elsestatic void initSegvCatch(void) __attribute__ ((constructor));
#endifstatic void OnSIGSEGV(int,siginfo_t*,void*);
static void initSegvCatch()
{struct sigaction act;sigemptyset(&act.sa_mask);act.sa_sigaction = OnSIGSEGV;act.sa_flags = SA_SIGINFO;if (sigaction(SIGSEGV, &act, NULL)<0 || sigaction(SIGFPE, &act, NULL)<0){//perror("sigaction:");printf("set segment catch faile!\n");}printf("set segment catch ok!\n");
}static void OnSIGSEGV(int signum, siginfo_t *info, void *ptr)
{static int i;if (i++ >= 1){//容错处理:如果访问 ucontext_t 结构体时产生错误会进入该分支printf("ReEnter %s is not allowed!\n", __FUNCTION__);abort();}void* pBuff[32];int   nSize = backtrace(pBuff, sizeof(pBuff)/sizeof(pBuff[0]));for (i = 0; i < nSize; i++){printf("backtrace: 0x%x 0x%x\n", pBuff[i], *((int*)pBuff[i]));}char** strSymbols = backtrace_symbols(pBuff, nSize);if (NULL != strSymbols){for (i = 0; i < nSize; i++){printf("%03d: %s\n", i, strSymbols[i]);}free(strSymbols);}if (NULL != ptr){ucontext_t* ptrUC = (ucontext_t*)ptr;printf("signal[%d]  r0 0x%x\n", signum, ptrUC->uc_mcontext.arm_r0);printf("signal[%d]  r1 0x%x\n", signum, ptrUC->uc_mcontext.arm_r1);printf("signal[%d]  r2 0x%x\n", signum, ptrUC->uc_mcontext.arm_r2);printf("signal[%d]  r3 0x%x\n", signum, ptrUC->uc_mcontext.arm_r3);printf("signal[%d]  r4 0x%x\n", signum, ptrUC->uc_mcontext.arm_r4);printf("signal[%d]  r5 0x%x\n", signum, ptrUC->uc_mcontext.arm_r5);printf("signal[%d]  r6 0x%x\n", signum, ptrUC->uc_mcontext.arm_r6);printf("signal[%d]  r7 0x%x\n", signum, ptrUC->uc_mcontext.arm_r7);printf("signal[%d]  r8 0x%x\n", signum, ptrUC->uc_mcontext.arm_r8);printf("signal[%d]  r9 0x%x\n", signum, ptrUC->uc_mcontext.arm_r9);printf("signal[%d]  r10 0x%x\n",signum, ptrUC->uc_mcontext.arm_r10);printf("signal[%d]  ip 0x%x\n", signum, ptrUC->uc_mcontext.arm_ip);printf("signal[%d]  sp 0x%x\n", signum, ptrUC->uc_mcontext.arm_sp);printf("signal[%d]  fp 0x%x\n", signum, ptrUC->uc_mcontext.arm_fp);printf("signal[%d]  pc 0x%x\n", signum, ptrUC->uc_mcontext.arm_pc);printf("signal[%d]  lr 0x%x\n", signum, ptrUC->uc_mcontext.arm_lr);printf("signal[%d]  cpsr 0x%x\n", signum, ptrUC->uc_mcontext.arm_cpsr);printf("signal[%d]  trap_no 0x%x\n", signum, ptrUC->uc_mcontext.trap_no);printf("signal[%d]  error_code 0x%x\n", signum, ptrUC->uc_mcontext.error_code);printf("signal[%d]  fault_address 0x%x\n", signum, ptrUC->uc_mcontext.fault_address);}else{printf("signal[%d]  when running code at unknown address\n", signum);}abort();
}#endif // __SEGV_CATCH_H

uc_mcontext 结构体如下

#ifndef _ASMARM_SIGCONTEXT_H
#define _ASMARM_SIGCONTEXT_H/** Signal context structure - contains all info to do with the state* before the signal handler was invoked.  Note: only add new entries* to the end of the structure.*/
struct sigcontext {unsigned long trap_no;unsigned long error_code;unsigned long oldmask;unsigned long arm_r0;unsigned long arm_r1;unsigned long arm_r2;unsigned long arm_r3;unsigned long arm_r4;unsigned long arm_r5;unsigned long arm_r6;unsigned long arm_r7;unsigned long arm_r8;unsigned long arm_r9;unsigned long arm_r10;unsigned long arm_fp;unsigned long arm_ip;unsigned long arm_sp;unsigned long arm_lr;unsigned long arm_pc;unsigned long arm_cpsr;unsigned long fault_address;
};#endif

参考: 通过coredump - 用backtrace和addr2line 查找异常函数栈_悟OO道的博客

backtrace: 0x2423c 0xe50b0008
backtrace: 0xb6c59e80 0xe3a070ad
backtrace: 0x174d4 0xe5823004
backtrace: 0x137ec 0xe50b0008
backtrace: 0x13d5c 0xe50b0008
backtrace: 0x140c4 0xe1a03000
backtrace: 0x144d0 0xe1a03000
backtrace: 0xb01c 0xea000066
backtrace: 0xace0 0xea00002d
backtrace: 0x1df68 0xea000031
backtrace: 0x33f4c 0xe3a00d35
backtrace: 0xb6eff038 0xe51b61c0
backtrace: 0xb6d04488 0xeaff2764
013: ./main() [0x2423c]
012: /lib/libc.so.6(__default_rt_sa_restorer_v2+0) [0xb6c59e80]
011: ./main() [0x174d4]
010: ./main() [0x137ec]
009: ./main() [0x13d5c]
008: ./main() [0x140c4]
007: ./main() [0x144d0]
006: ./main() [0xb01c]
005: ./main() [0xace0]
004: ./main() [0x1df68]
003: ./main() [0x33f4c]
002: /lib/libpthread.so.0(+0x7038) [0xb6eff038]
001: /lib/libc.so.6(clone+0x88) [0xb6d04488]
signal[11] catched r0 0xa0f8c00c
signal[11] catched r1 0xb4e40000
signal[11] catched r2 0x280000
signal[11] catched r3 0xa0f8c008
signal[11] catched r4 0x0
signal[11] catched r5 0x0
signal[11] catched r6 0x0
signal[11] catched r7 0x152
signal[11] catched r8 0x0
signal[11] catched r9 0xb6f0ab60
signal[11] catched r10 0xb6f0ab60
signal[11] catched ip 0x0
signal[11] catched sp 0xa5898f60
signal[11] catched fp 0xa5898f7c
signal[11] catched lr 0x17434
signal[11] catched cpsr 0xa0000010
signal[11] catched trap_no 0xe
signal[11] catched error_code 0x805
signal[11] catched fault_address 0x280004

使用addr2line  -- Linux debug : addr2line追踪出错地址_悟OO道的博客

--  通过coredump - 用backtrace和addr2line 查找异常函数栈_悟OO道的博客

gdb + core --  Linux下调试段错误的方法[Segmentation Fault]--GDB_悟OO道的博客

--   关于Segmentation fault (core dumped)几个简单问题_悟OO道的博客

都不能解析出错误函数。ZYNQ板卡上使用报错!

下一步反汇编查找试试!!!

arm栈帧结构

通常情况下,arm的调用栈大致结构与x86相同,都是从高地址向低地址扩张。

pc, lr, sp, fp是处理器的寄存器,其含义如下:

  • pc, program counter,程序计数器。程序当前运行的指令会放入到pc寄存器中
  • fp, 即frame pointer,帧指针。通常指向一个函数的栈帧底部,表示一个函数栈的开始位置。
  • sp, stack pointer,栈顶指针。指向当前栈空间的顶部位置,当进行push和pop时会一起移动。
  • lr, link register。在进行函数调用时,会将函数返回后要执行的下一条指令放入lr中,对应x86架构下的返回地址。

调用栈从高地址向低地址增长,当函数调用时,分别将分别将pc, lr, ip和 fp寄存器压入栈中,然后移动sp指针,为当前程序开辟栈空间。

arm官方手册描述如下:

一个arm程序,在任一时刻都存在十五个通用寄存器,这取决于当前的处理器模式。 它们分别是 r0-r12、sp、lr。
sp(或 r13)是堆栈指针。 C 和 C++ 编译器始终将 sp 用作堆栈指针。 在 Thumb-2 中,sp 被严格定义为堆栈指针,因此许多对堆栈操作无用而又使用了 sp 的指令会产生不可预测的结果。 建议您不要将 sp 用作通用寄存器。
在用户模式下,lr(或 r14)用作链接寄存器 (lr),用于存储调用子例程时的返回地址。 如果返回地址存储在堆栈上,则也可将 r14 用作通用寄存器。
在异常处理模式下,lr 存放异常的返回地址;如果在一个异常内执行了子例程调用,则 lr 存放子例程的返回地址。如果返回地址存储在堆栈上,则可将 lr 用作通用寄存器。

除了官方手册中描述的sp,lr寄存器,通常r12还会作为fp寄存器。fp寄存器对于程序的运行没有帮助,主要用于对栈帧的回溯。因为sp时刻指向的栈顶,通过fp得知上一个栈帧的起始位置。

LINUX C/C++捕获段错误,打印出错的具体位置(精确到哪一行) ​ --Xilinx ARM版本相关推荐

  1. C/C++捕获段错误,打印出错的具体位置(精确到哪一行

    C/C++捕获段错误,打印出错的具体位置(精确到哪一行)  其实还可以使用 glibc 的 backtrace_symbols 函数,把栈帧各返回地址里面的数字地址翻译成符号描述的 背景知识: · 在 ...

  2. Linux平台Segmentation fault(段错误)调试方法

    1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只读的内存地址等等情况. 2. 段错误的原因 段错 ...

  3. 用封装的栈回溯类捕获段错误

    本文介绍使用自封装的 backtrace 类对段错误进行捕获,以方便分析运行错误的方法.并给出实现和测试代码. 背景 我们写程序难免会运行出错,常在河边,哪能不湿鞋.出错不可怕,怕的是无法定位问题,像 ...

  4. linux c++ 运行时报 段错误 的一个原因

    很长时间没有写 c/c++了 这次依据一些代码写了一个linux上的小东西,结果在运行时用new 创建对象的时候,报: 段错误 有可能还出现如下报错信息: *** glibc detected *** ...

  5. linux c代码出现段错误,Linux下段错误(C语言)

    问题描述:在Linux下编程有时会出现段错误的提醒,出现这种错误有可能是因为以下几种原因 1.数组越界:如果在初始化或者接收输入时内容超过了定义好的数组元素个数时会出现段错误,Linux的数组越界检查 ...

  6. linux c代码出现段错误,在linux下代码运行出现段错误,求大神

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include #include #include #include #define PATH1 "/proc/meminf ...

  7. linux/unix 段错误捕获【续】

    本文为"在C/C++中捕获段错误,打印出错的具体位置"的续篇,进一步解决涉及动态链接库的情况. 背景知识: ·linux/unix下动态链接库的基本原理 ·/proc/pid/ma ...

  8. linux 捕获sigsegv信息如何生成core文件,[转]Linux下的段错误产生的原因及调试方法Core Dump...

    简而言之,产生段错误就是访问了错误的内存段,一般是你没有权限,或者根本就不存在对应的物理内存,尤其常见的是访问0地址. 一般来说,段错误就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由 ...

  9. Linux环境下段错误的产生原因及调试方法小结

    From:http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基 ...

最新文章

  1. Spark 2.4重磅发布:优化深度学习框架集成,提供更灵活的流式接收器
  2. linux搭建--DISPLAY环境变量问题(一)
  3. ubuntu中安装kDevelop
  4. 中国计算机学会CCF推荐国际学术会议和期刊目录-计算机科学理论
  5. Monkey Server自动化脚本
  6. 五十八、Vue中的计算属性,方法和侦听器
  7. 2020年最快的dns_2020年哪里换旅行证最快取证?需要几天?
  8. Python《wallpaper abyss壁纸》
  9. 热敏电阻如何查表计算温度_额温枪温补算法:热电堆温度补偿算法 MTP10B7F55
  10. InputFilter实现EditText文本输入过滤器
  11. android hal层编译,Android Hal层接入Opencv(踩坑篇)
  12. tableau的下载安装及简单使用
  13. 以太坊(ethereum)开发DApp应用的入门区块链技术教程
  14. Thinkphp微信幸运大转盘抽奖实例
  15. mysql binlog是什么_什么是 binlog?
  16. 闲聊: 女神异闻录4
  17. Collision Filtering(selective collisions) 碰撞过滤(选择性碰撞)
  18. mysql 双冒号,SQL中的双冒号(::)符号
  19. 手把手教你学python第十三讲(MRO详解和神奇的魔法方法)
  20. 计算机网络:数据链路层功能

热门文章

  1. P3287 [SCOI2014]方伯伯的玉米田
  2. 第三章 微分中值定理与导数的应用
  3. 如何查看自己电脑使用第几代内存条?
  4. surface pro4 win10下安装elementray os双系统教程
  5. 谷粒商城简介(1~5集)
  6. 1.TCL/TK脚本学习——入门基础
  7. mmdetection安装
  8. wps删除分节符导致前面格式变乱的解决方案
  9. PNG图像文件格式解析
  10. windwos服务器网站504,打开网站出现504 gateway time-out的原因及解决方法