【Linux】学会 core dump 事后调试 快速定位段错误

时间:2022-11-07 00:57:11

环境: centos 6.5

core dump是什么

其实就是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。最常见的就是段错误,然后程序直接挂掉。当程序出现段错误时,不要一脸蒙蔽,有一种简单而有效的方式快速定位错误。

常见 core dump 错误

总结自前辈的经验:

一、无效指针

  1. 对空指针进行了操作
  2. 对未初始化的指针进行了操作
  3. 使用一个已经释放内存过的指针再次delete 重复释放,(所以说释放后要置空,置空就不会报错)
  4. 多线程访问全局变量,导致内存值异常而程序核心转存。

二、指针越界

  1. 检查赋值语句,检查定位到错误上下变量的值,可以结合注释来定位
  2. 内存变量值异常,检查定位行,代码走读排查函数调用是使用否有问题,重点关注函数:sprintf, strcpy,memmove, memcpy,stcmp,strcasecmp等容易出现错误的函数。

三、操作系统特殊性

  1. 字节对齐方式引起的程序核心转储
  2. 引用模块与自身模块所定义的结构体的字节对齐方式不同
  3. 在代码中, 把引用到的别的模块的头文件包含到自身文件中的字节对齐方式语法声明的中间了, 结果导致字节对齐方式出现了变化

如何生成 core dump

以下几步:

  1. 在gcc 加上-g选项,生成调试信息
  2. 使用ulimit -a 查看你系统对生成core文件大小的限制,一般都限制为0,为了避免产生过过多冗余信息,也为了保证数据的安全,因为内存中可能有很多隐私信息,此时需要修改core 文件的信息(下面有具体的案例)。
  3. 生成 core 文件后(各个平台生成的文件定定义格式可能不同,我使用的系统默认生成在当前目录下,文件名是core.**,*号是进程ID)然后使用 gdb execute core.* 调试你的程序。 execute 是你 挂掉的程序名字, 后面跟着的是生成的 core文件。

记录一下调试过程

在写一个小型http 服务器的时候,浏览器访问静态页面没有问题,一旦访问可执行脚本(用 c 写的cgi 接口程序 )就GG,由于可执行脚本是 父进程 fork 出子进程然后exec 程序替换,将可执行脚本替换进来,然后就直接挂掉。

初步怀疑是错误发生在执行脚本的函数里,然后一开始写的时候没有写宏测试代码,直接开干。也不想用printf 输出调试,发现这是一个段错误,然后就想到了之前看到过的 事后调试。

下面是调试过程:

【Linux】学会 core dump 事后调试 快速定位段错误

1、 查看系统是否有对 core 文件的限制

【Linux】学会 core dump 事后调试 快速定位段错误

果然。。有。。(废话啊)。

然后我们可以有两种方式可以修改:

[bob @ host httpd]$ulimit -c 1024

-c 后面跟你要限制的大小,然后这有时候没什么用。因为你也不知道它会 dump 多大的数据,如果一直无法产生core文件,可以用下面这个命令

[bob @ host httpd]$ulimit -c unlimited # 表示大小无限制

由于当时没有保存截图。。我想情景再现,发现我已经想不起来是哪里的错误,记得是一个很比较低级但是不容易发现的错误,就是越界问题。下面我写个小例子来演示一下:

#include <stdio.h>
#include <stdlib.h>

int main()
{

int *p;

*p = 10;

return 0;
}

你说这会不会挂?当然。。会啊,解引用未知地址。

【Linux】学会 core dump 事后调试 快速定位段错误

然后查看修改系统对core 的限制并在gcc 上加-g 选项,再次执行程序:

【Linux】学会 core dump 事后调试 快速定位段错误

注意如果出现报错的问题,请切换成root 用户,我的机子上普通用户 无法修改为 ulimited。

然后再次执行程序:
【Linux】学会 core dump 事后调试 快速定位段错误

又挂了,但是当前目录下多了一个core.* 的文件。
现在使用gdb 调试该程序。
【Linux】学会 core dump 事后调试 快速定位段错误

看关键部分!!,直接就到定位到了 12 行,然后在推断定位行上下,就发现指针未初始化的问题。当然如果程序较大,还需要仔细分析,结合core 文件的辅助,快速定位错误。