段错误以及调试方法

一.段错误产生的原因

  1. 段错误就是访问了不可访问的内存,出现了运行时出现了segmentation fault的报错
  2. 产生的原因:访问不存在的内存地址、访问系统保护的内存地址 、访问只读的内存地址、空指针废弃(eg:malloc与free释放后,继续使用)、堆栈溢出、内存越界(数组越界,变量类型不一致等)

二. 使用GDB逐步查找段错误

  1. 首先加上命令行得先加上-g -rdynamic的参数进行编译,eg:gcc -g rdynamic xxx.c 随着gdb ./a.out
  2. eg:在这里插入图片描述
  3. 运行结果在这里插入图片描述
    很明显,都不用一步步的调试,后面几行就显示了出错位置。
    并且进程还收到了SIGSEGV信号而结束,而SIGSEGV默认的handler的动作是打印“段错误”的出错信息,并产生core文件。

三. 分析core文件

  1. 什么是core文件
    Core文件其实就是内存的映像,当程序崩溃时,存储内存的相应信息,主用用于对程序进行调试。 当程序崩溃时便会产生core文件,其实准确的应该说是core dump 文件,默认生成位置与可执行程序位于同一目录下,文件名为core.
    Core的意思是内存, Dump的意思是扔出来;core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump.

  2. 如何使用

gdb -c core文件路径 [应用程序的路径]

进去后输入where回车, 就可以显示程序在哪一行当掉的, 在哪个函数中。
但是core文件的生成跟你当前系统的环境设置有关系, 可以用下面的语句设置一下, 然后再运行程序便成生成core文件ulimit -c ulimited; 输入命令

ulimit -c   //查是否为0,是0就不生成core文件
ulimit -c 1000  //ulimit -c ulimited,改变数值,限制系统的core文件大小
  1. eg 在这里插入图片描述

四.段错误时启动调试

(gdb)bt
在这里插入图片描述
二,三,四都是在基于系统上的gdb的前提进行的。如果没有,glibc为我们提供了此类能够dump栈内容的函数簇,详见/usr/include/execinfo.h

五. 利用backtrace和objdump进行分析

eg
在这里插入图片描述在这里插入图片描述

  1. 运行结果
    在这里插入图片描述
  2. 这里得提一下,需要用到库<execinfo.h>和<signal.h>
  3. 运行结果似乎没上面几种方式的信息多,清晰;但是还没完,我们再用objdump反汇编程序,找到上面地址对应的代码位置。
  4. objdump -d a.out
    找到对应main 0x5601a75e0b0f对应的代码位置
    在这里插入图片描述
  5. backtrace函数
    backtrace函数的作用:当程序出现异常,段错误,崩溃的情况下,会收到内核发送给进程的异常信号,会把程序的堆栈信息打印出来。
 int backtrace(void **buffer, int size)
 //该函数获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针数组,参数size用来指定buffer中可以保存多少个void*元素。函数的返回值是实际返回的void*元素个数。buffer中的void*元素实际是从堆栈中获取的返回地址。
 char **backtrace_symbols(void *const *buffer, int size)
 //该函数将backtrace函数获取的信息转化为一个字符串数组,参数buffer是backtrace获取的堆栈指针,size是backtrace返回值。函数返回值是一个指向字符串数组的指针,它包含char*元素个数为size。每个字符串包含了一个相对于buffer中对应元素的可打印信息,包括函数名、函数偏移地址和实际返回地址。
 //backtrace_symbols生成的字符串占用的内存是malloc出来的,但是是一次性malloc出来的,释放是只需要一次性释放返回的二级指针即可。
 void backtrace_symbols_fd(void *const *buffer, int size, int fd)
 //该函数与backtrace_symbols函数功能相同,只是它不会malloc内存,而是将结果写入文件描述符为fd的文件中,每个函数对应一行;该函数可重入。

注意事项:backtrace_symbols的实现需要符号名称的支持,在gcc编译过程中需要加入-rdynamic参数;

  1. objdump反汇编码
objdump -f test   //显示test的文件头信息

objdump -d test   //反汇编test中的需要执行指令的那些section

objdump -D test   //与-d类似,但反汇编test中的所有section

objdump -h test   //显示test的Section Header信息

objdump -x test   //显示test的全部Header信息

objdump -s test   //除了显示test的全部Header信息,还显示他们对应的十六进制文件代码

六.段错误信息的获取

当我们运行的时候,发先有段错误segmentation fault时,我们可以通过一些命令进行段错误信息获取。

  1. -g gcc -g 主要适用于gdb调试
  2. dmesg 直接输入命令dmesg
    dmesg 可以在应用程序崩溃时,显示内存中保存的相关信息。 dmesg 可以查看发生段错误的程序名称、引起段错误发生的内存地址、指令指针地址、堆栈指针地址、错误代码、错误原因等等。
  3. ldd 命令
    查看二进制程序的共享链接库依赖,包括库的名称、起始地址,这样可以确定段错误到底是发生在了自己的程序中还是依赖的共享库中。
    在这里插入图片描述
  • 9
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值