首页 > 代码库 > Segmentation Fault的一种定位方法

Segmentation Fault的一种定位方法

1. 介绍

网上有很多Segmentation Fault的调试方法,下面这篇文件就很好
<Linux环境下段错误的产生原因及调试方法小结>
然而笔者在实际的使用中由于各种原因总觉得不够用
于是在网上找到了一种个人觉得更直接的方法

2. 原理

Segmentation Fault发生的时候,程序收到了信号11(SIGSEGV)
我们捕获该信号,然后利用事故发生时保存的寄存器现场加上栈信息定位到具体行
这里参考了< C/C++捕获段错误,打印出错的具体位置(精确到哪一行) >
使用其提供的头文件segvCatch.h

3. 实例程序

下面是测试用的实例程序 SegFault.c

   1:  #include "segvCatch.h"
   2:   
   3:  void SegFaultFunc()
   4:  {
   5:      int *p = NULL;
   6:      *p = 123;
   7:  }
   8:  void Func3()
   9:  {
  10:      SegFaultFunc();
  11:  }
  12:  void Func2()
  13:  {
  14:      Func3();
  15:  }
  16:  void Func1()
  17:  {
  18:      Func2();
  19:  }
  20:  int main()
  21:  {
  22:      initSegvCatch();
  23:      Func1();
  24:      return 0;
  25:  }
<style type="text/css">.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }</style><style type="text/css">.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }</style>

4. 分析

下面是编译和定位过程

[Jerry@ work]$ gcc SegFault.c -g -o SegFault -rdynamic[Jerry@ work]$./SegFault signal[11] catched when running code at 80488d6signal[11] catched when running code at 80488b9signal[11] catched when running code at 80488afsignal[11] catched when running code at 80488a5signal[11] catched when running code at 8048896Aborted[Jerry@ work]$ addr2line 80488d6 80488b9 80488af 80488a5 8048896 -e ./SegFault -f         main/home/Jerry/work/SegFault.c:23Func1/home/Jerry/work/SegFault.c:18Func2/home/Jerry/work/SegFault.c:14Func3/home/Jerry/work/SegFault.c:10SegFaultFunc/home/Jerry/work/SegFault.c:6
<style type="text/css">.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }</style>

可以看到最后依次显示了调用顺序
main() –> Func1() –> Func2() –> Func3() –> SegFaultFunc()

同时定位到具体出错的行(第六行)

值得注意是在编译时需要加上-g以获得调试信息()

5. 扩展

由于笔者开发使用的系统架构是ARM,而上面的segvCatch.h只支持x86
故笔者在一番研究之后得到了基于ARM和MIPS的方法

关键点在于获取当前执行的指令的地址
对于X86,为EIP寄存器
对于ARM/MIPS,则为PC寄存器

其实际值可以查看工具链头文件ucontext.h来了解实际定义的保存方式

对于X86  为ucontext_t.uc_mcontext.gregs[REG_EIP]对于ARM  为ucontext_t.uc_mcontext.arm_pc对于MIPS 为ucontext_t.uc_mcontext.pc (未测试)

6. 下载

修改后的版本已上传至GitHub
https://github.com/sharmer/SomeDownload/tree/master/SegFault

Segmentation Fault的一种定位方法