Linux开发

it2024-08-12  39

dump core = 核心转储,也就是我们平时在Linux上最容易遇到的段错误

这种错误一般是因为你访问了一些不可越界的内存导致的,在操作系统上有als地址随机化与虚拟地址保护,我们不能访问越过我们自己程序内存边界的地址

如果访问了一般就会出现这种错误:

当然,当你尝试修改一些只读区域的内存也会出现这种情况,这是因为内核发现你在尝试做一些违规行为,那么内核会拦截并杀死你的程序。

当我们在写大工程的时候,出现这种情况的确让人很头疼,在大工程下,文件那么多,较为优秀的工程里模块化的占有率也比较高,很难查出问题出现在那个模块上,也很难定位到某个文件。

这种情况下一般只是一行代码导致的,如果我们能够快速定位到文件且定位到出错代码行,岂不美哉?

这个时候GDB就出现了,一般大多数人称为 GDB dump core调试

就是先让Linux内核生成核心转储文件,该文件里包含了程序出错时产生的堆栈调用,还有一些错误信息。

前提是这个程序在编译时没有经过任何优化,且编译时,gcc/g++必须+"-g"选项,让编译器生成地址符号表还有一些调试信息。

这样我们才能精确定位到函数以及文件名。

生成dump core文件方法:

ulimit -c unlimited

使用ulimit -c选项来生成core文件,到程序可执行目录下使用这个命令,后面的unlimited代表无限制大小

可以把unlimited替换成大小,以字节为单位,限制core文件生成的大小

如果改为0,则不生成。

先到我们出错的debug程序目录下使用此命令:

我们在运行出错程序:

使用ls命令查看是否产生文件:

产生的core就是我们的核心转储文件。

我们是不能打开的,这个文件只有gdb能够识别,所以我们要使用gdb来调试它

gdb 程序 core文件

gdb ./Weye_RadarServer core

成功调试:

下面的缺少raise.c文件无需理会,这个是因为gdb缺失glibc库,可以忽略这个问题。

其中这一行也明确表示出,收到了SIGABRT信号,被操作系统直接杀死,所以可以肯定是访问了不属于我们自己的内存地址。

如果你比较幸运,在gdb刚调试时,就会定位出代码行。

接着,我们要用”bt“命令查看堆栈情况

第一行的raise.c这个错误先忽略

我们往下看,gdb定位出三个报错文件的行号以及文件

分别对应#8,#9,#10

使用frame命令查看堆栈调用情况,先看#10的main

是第十一行代码出了错

我们调用了init这个函数出了错!

是init那么我们看第#9,这里是init的实现

这里我们的init又调用了start_init这个函数,是start_init函数出了错,这个时候我们就可以看第8行,刚好是start_init的段错误

good,找到了,是tree.hpp的第82行代码出了错

std::string _temp_type(attr_xml.lookUp_kid_node(ZMQ_HAND,ZMQ_PROTOCOL).Char);

代码定位到这一行

这行代码就是使用c++的string类,并且传递一个构造参数

参数使用的是函数返回值

这样基本上可以确定是lookUp_kid_node在调用的时候返回了一个不确定的地址或者返回了NULL,同时_temp_type去做构造,字符串复制了,这个地址是不正确的,所以发生了越界!

这个函数使用的是atrr_xml模块,一个用于解析xml文件的

排错:

1.确定xml模块是正确的,并且测试通过的

2.确定xml模块已经打开xml文件

3.确定xml文件是否正确,查找的字段是否存在

这里我依次排查最后发现问题出现在xml文件字段上

在宏定义里定义里字段值:

xml文件字段:

ProtoCol字段在宏定义里定义成了ProtoCOl,最后的这个O写成了大写的...

导致xml模块无法解析到,返回了NULL,然后又被string类去构造,导致构造了个空地址,产生了段错误,NULL也是一个地址,属于地址为0的这块内存,这块内存操作系统是不可能分配给我们的,它归操作系统内核1G空间。

当我把字段修改完后程序正常运行:

在补充一个点,core文件其实你也可以不用生成,用gdb启动,在用r跑起来,到出错段gdb停下来后,就可以用上面的方法排查了。

修改core文件名称以及路径方法:

修改文件命令: echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern或者:sysctl -w kernel.core_pattern=/corefile/core.%e.%p.%s 可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳 以下是参数列表: %p - insert pid into filename 添加pid(进程id) %u - insert current uid into filename 添加当前uid(用户id) %g - insert current gid into filename 添加当前gid(用户组id) %s - insert signal that caused the coredump into the filename 添加导致产生core的信号 %t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间 %h - insert hostname where the coredump happened into filename 添加主机名 %e - insert coredumping executable name into filename 添加导致产生core的命令名

 

ps:记录一次调试经历。

最新回复(0)