背景
测试环境 Fedora 25&24 CentOS 7
目测 Deepin 并没有坑 而Ubuntu可能也存在这个问题(也有类似abrt的二进制文件)
前言
从Windows平台下转到到Linux下的C/C++开发可能第一个接触到的新名词就是段错误
也就是这样
首先是一段神秘代码
#include <stdio.h>
int main(void)
{
char a[1];
char *b = a[20];
printf("%c",*b);
}
然后编译运行
出现段错误一般都是内存出现了问题,比如最常见的数组越界。
但是问题是,出现这种错误往往很难第一时间定位到错误代码,无论是手动printf还是step by step都很麻烦。
利器—coredump
我的理解coredump文件就是一种保存进程终止前信息的文件,或者这样说
保留下第一手的现场数据,OS仿佛是一架被按下快门的相机,而照片就是产出的Core文件。里面含有当进程被终止时内存、CPU寄存器等信息,可以供后续开发人员进行调试。
当进程产生段错误,自然会被OS终止,但是终止前所有的数据信息,都可在coredump文件中找到,方便我们去寻找到底是哪里出bug了。
怎么生成coredump文件呢
一般情况下,并不会产生coredump文件,因为一个coredump文件往往很大,以上面的代码为例
代码很短,a.out大概10K,而coredump就250K,为了节省空间,自然不会产生coredump文件。
出来吧,coredump!
我们可以用ulimit -c
命令查看系统生成coredump文件大小。
一般都是0啦。
然后通过 ulimit -c unlimited
设置为无限大(其实并不是无限,具体涉及到软限制和硬限制,这里我们只是无脑修改,保证一般情况能用)
再次查看,发现已经改好了。
来,让我们再写个段错误
如果你发现在你执行a.out的目录下,并没有新文件产生,或者你是用的包括但不限于(Fedora 25/24,CentOS 7),恭喜你,踩到和我一样的坑了。
无脑解决
问题所在
我当时也查了很多资料,包括中文的英文的。结论基本如下。
在/proc/sys/kernel/core_pattern
中设置了coredump文件默认产生的名字,同时在新版中,都是|/usr/libexec/abrt-hook-ccpp %p xxx
也就是将coredump文件交给了另一个二进制文件去处理。
那么,我们要想让coredump文件在指定位置产生(比如代码所在目录),以及修改默认文件名,只需要修改这个core_pattern文件就可以了。
蛋疼的/proc
/proc并不是简单的和/home一样的目录,它赋予了Linux动态调整内核的能力。关于/proc,我们不详细展开(其实我也不是很懂ToT)。
一个最简单的不同,修改/proc下的文件,不能简单的vim打开然后保存。应该用echo "xxx" >
来输出重定向到目标文件。
同时,这里的文件只有root权限才能修改,连sudo都不可以。。。
最初的想法
一开始我是希望,能通过修改bashrc文件,保证每次打开shell时都修改好core_pattern文件,这样就不用出现段错误再去修改产生coredump文件。但是失败了,因为获取不到root权限,或者说只有在用root开启shell时才能正确修改。
最终的傻瓜解法
首先,修改bashrc还是有用,因为ulimit -c unlimited
这条命令并不需要权限,我们将这句话添加到~/.bashrc中,保证每次打开shell都可以产生coredump文件。
然后,那个怎么修改也改不好的|/usr/libexec/abrt-hook-ccpp %p xxx
,我们直接sudo dnf remove abrt*
一下子全卸载。
最后,修改coredump的配置文件(abrt 存在时修改这个文件好像没用)
root@localhost[ kang ]# vi /lib/sysctl.d/50-coredump.conf
里面会有kernel.core_pattern
这项,在等号后面写上你希望的coredump文件名或者路径就好了。
再来一次段错误
可以看到产生了coredump文件。编译时加上-g参数,方便调试。
我们用 gdb来调试
gdb a.out core.6516.1495100231
就可以一下看到在哪里出错了,并且在这个状态下查看其他的变量值,栈等信息。