【Linux】gdb调试coredump

一、coredump是什么

Coredump叫做核心转储,它是进程运行时在突然崩溃的那一刻的一个内存快照。操作系统在程序发生异常而异常在进程内部又没有被捕获的情况下,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在一个文件里。

该文件也是二进制文件,可以使用gdb、elfdump、objdump或者windows下的windebug、solaris下的mdb进行打开分析里面的具体内容。

注:core是在半导体作为内存材料前的线圈,当时用线圈当做内存材料,线圈叫做core。用线圈做的内存叫做core memory。

二、ulimit设置

虽然我们知道进程在coredump的时候会产生core文件,但是有时候却发现进程虽然core了,但是我们却找不到core文件。

在linux和Solaris下是需要进行设置的。可以使用ulimit -a来看这些设置

ulimit -c 可以设置core文件的大小,如果这个值为0.则不会产生core文件,这个值太小,则core文件也不会产生,因为core文件一般都比较大。

使用ulimit -c unlimited来设置无限大,则任意情况下都会产生core文件。

此时生成的core文件名称都是统一的”core”命名。

自定义core文件的文件名

上面的设置只是使能了core dump功能,缺省情况下,内核在coredump时所产生的core文件放在与该程序相同的目录中,并且文件名固定为core。很显然,如果有多个程序产生core文件,或者同一个程序多次崩溃,就会重复覆盖同一个core文件。

我们通过修改kernel的参数,可以指定内核所生成的coredump文件的文件名。例如,Easwy使用下面的命令使kernel生成名字为core_filename_time_pid格式的core dump文件:

echo /corefile/core_%e_%t_%p > /proc/sys/kernel/core_pattern

echo后面内容最好不要带上引号,有的系统会把引号也带入,这样,系统是不识别该内容的,也就会导致程序coredump而不会生成core文件。

可以在core_pattern模板中使用变量见下面的列表:

%%单个%字符

%p所dump进程的进程ID

%u所dump进程的实际用户ID

%g所dump进程的实际组ID

%s导致本次core dump的信号

%t core dump的时间 (由1970年1月1日计起的秒数)

%h主机名

%e程序文件名

设置永久保存:

打开/etc/security/limits.conf 文件,在该文件的最后加上两行

@root soft core unlimited
@root hard core unlimited

配置好后,放回原目录,重启reboot

命名规则的修改在/proc/sys/kernel/core_pattern中也只是临时的,这个也是动态加载和生成的。永久修改在/etc/sysctl.conf文件中,在该文件的最后加上两行:

kernel.core_pattern = /corefile/core_%e_%t_%p
kernel.core_uses_pid = 0

可以使用以下命令,使修改结果马上生效。

#sysctl –p

三、产生 core dump 的可能原因

1、内存访问越界

a) 由于使用错误的下标,导致数组访问越界
b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用 结束符
c) 使用 strcpy, strcat, sprintf, strcmp, strcasecmp 等字符串操作函数,将目标字符串读/写爆。应该使用 strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp 等函数防止 读写越界。

2、多线程程序使用了线程不安全的函数

3、多线程读写的数据未加锁保护

对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成 core dump

4、非法指针

a)使用空指针
b)访问野指针,野指针造成的错误叫做内存泄漏,但存在野指针并不一定每次运行程序都会出现段错误,因为可能某次给野指针随机分配的内存地址是其它变量已经申请过的内存地址,这种情况不会出现段错误
c)随意使用指针转换,一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中, 再访问这个结构或类型。 这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为 bus error 而 core dump。

拓展:bus error(总线错误)

在编译和运行一个程序的时候,人们可能会遇到下面的信息:“Bus error(core dumped)”;当出现这种信息的时候,则表示在SPARC等RISC类型的CPU中发生了“违反定位访问”的情况。例如,读者可以阅读下面的程序:

#include <string.h>
#include <stdio.h>
void main(){
    char buf[256];
    int *x;
    x = (int *) & buf[1];
    //强制类型转换的是指针而非char型变量,指针指向的内存数据可以认为是任意类型,char、int 、float、double甚至结构    
    *x = 68000;
    //假设buf的开始地址为0x1000,则这句将0x1001~0x1004的内容拷贝给x(x为int型),如前所述,int型数据地址必须为4的整数倍,此处0x1001不满足该条件,故会引起CPU内部总线错误    
    printf("*x = %d\n",*x);
}

在这段程序中,能够确保256byte的存储器区域,其中能够存储68000的整数值。但是,这样也会发生前面所讲的地址问题,在上述的情况下,数组buf的存储区域从4的整数倍开始。在该数组的第二个位置(即奇数地址单元)中赋予了数据类型为int的值。在RISC类型的CPU中,数据类型int值只能存储在4的整数倍地址中。因此,在将要对变量x赋值68000的时候,CPU不能够继续执行这个程序,则出现Bus error这个信息,然后终止该程序的运行

但是,在Pentinm(奔腾)系列的CPU中,则不会产生Bus error这个信息。这是因为采用了Pentinm系列的80386的流程的RISC类型的CPU,提高了CPU的处理效率,或电路进行了简单化处理,从8位开始就使用了重视移植性的体系结构

5、堆栈溢出

使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误

四、gdb调试coredump

1、生成符号表

objcopy --only-keep-debug projectD projectsymbol.dbg

2、加载符号表

gdb -q --symbol=projectsymbol.dbg -exec=projectR

3、同时调试多个程序

4、x指令介绍

gdb查看指定地址的内存地址的值:examine 简写 x
x/(n,f,u为可选参数)

n: 需要显示的内存单元个数,也就是从当前地址向后显示几个内存单元的内容,一个内存单元的大小由后面的u定义

f:显示格式

x(hex) 按十六进制格式显示变量。
d(decimal) 按十进制格式显示变量。
u(unsigned decimal) 按十进制格式显示无符号整型。
o(octal) 按八进制格式显示变量。
t(binary) 按二进制格式显示变量。
a(address) 按十六进制格式显示变量。
c(char) 按字符格式显示变量。
f(float) 按浮点数格式显示变量

u:每个单元的大小,按字节数来计算。默认是4 bytes。GDB会从指定内存地址开始读取指定字节,并把其当作一个值取出来,并使用格式f来显示

b:1 byte     h:2 bytes     w:4 bytes      g:8 bytes

比如x/3uh 0x54320表示从内存地址0x54320读取内容,h表示以双字节为单位,3表示输出3个单位,u表示按照十六进制显示。

gdb打印表达式的值:print/f 表达式
f是输出的格式,x/d/u/o/t/a/c/f

表达式可以是当前程序的const常量,变量,函数等内容,但是GDB不能使用程序中所定义的宏

查看当前程序栈的内容: x/10x $sp–>打印stack的前10个元素
查看当前程序栈的信息: info frame----list general info about the frame
查看当前程序栈的参数: info args—lists arguments to the function
查看当前程序栈的局部变量: info locals—list variables stored in the frame
查看当前寄存器的值:info registers(不包括浮点寄存器) info all-registers(包括浮点寄存器)
查看当前栈帧中的异常处理器:info catch(exception handlers)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值