学会用core dump调试程序错误 |
您所在的位置:网站首页 › coredump调试流程 › 学会用core dump调试程序错误 |
什么是coredump? 通常情况下coredmp包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息等。可以理解为把程序工作的当前状态存储成一个文件。许多程序和操作系统出错时会自动生成一个core文件。 如何使用coredump? coredump可以用在很多场合,使用Linux,或者solaris的人可能都有过这种经历,系统在跑一些压力测试或者系统负载一大的话,系统就hang住了或者干脆system panic.这时唯一能帮助你分析和解决问题的就是coredump了。 现在很多应该程序出错时也会出现coredump. 分析coredump的工具 现在大部分类unix操作系统都提供了分析core文件的工具,比如 GNU Binutils Binary File Descriptor library (BFD), GNU Debugger (gdb),mdb等 coredump的文件格式 类unix操作系统中使用efi格式保存coredump文件。 在solairs下 bash-3.2# file *unix.3 ELF 32-bit LSB executable 80386 Version 1, statically linked, not stripped, no debugging information availableunix.4 ELF 32-bit LSB executable 80386 Version 1, statically linked, not stripped, no debugging information available 造成程序coredump的原因很多,这里根据以往的经验总结一下: 1 内存访问越界 a) 由于使用错误的下标,导致数组访问越界 b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符 c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。 2 多线程程序使用了线程不安全的函数。 应该使用下面这些可重入的函数,尤其注意红色标示出来的函数,它们很容易被用错:asctime_r(3c) gethostbyname_r(3n) getservbyname_r(3n) ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n) ctime_r(3c) getlogin_r(3c) getservent_r(3n) fgetgrent_r(3c) getnetbyaddr_r(3n) getspent_r(3c) fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c) fgetspent_r(3c) getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n) lgamma_r(3m) getauclassent_r(3) getprotobyname_r(3n) localtime_r(3c) getauclassnam_r(3) etprotobynumber_r(3n) nis_sperror_r(3n) getauevent_r(3) getprotoent_r(3n) rand_r(3c) getauevnam_r(3) getpwent_r(3c) readdir_r(3c) getauevnum_r(3) getpwnam_r(3c) strtok_r(3c) getgrent_r(3c) getpwuid_r(3c) tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c) getgrnam_r(3c) getrpcbynumber_r(3n) gethostbyaddr_r(3n) getrpcent_r(3n) 3 多线程读写的数据未加锁保护。 对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成core dump 4 非法指针 a) 使用空指针 b) 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型 的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它 时就很容易因为bus error而core dump. 5 堆栈溢出 不要使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。
coredump文件的生成方法以及使用方法: (假设下例是在x86上交叉编译,而在arm上运行异常的现象) 1. 在arm内核里加入coredump的支持(一般内核都支持coredump, 不用重编) 2. 运行命令,此时允许coredump文件产生:(在arm上) ulimit –c unlimited 3. 执行程序:(在arm上)./test 在异常退出时,会显示如下信息,注意括号里的内容Segmentation fault (core dumped)程序执行目录下将产生*core文件 4. 用gdb分析:(在x86上)arm-linux-gdb ./test test.core 再用gdb的bt或where看就可以了(arm-linux-gdb的编译见) 系统支持生成core并设置存储位置的方法: 1> 在/etc/profile中加入以下一行,这将允许生成coredump文件 ulimit -c unlimited2> 在rc.local中加入以下一行,这将使程序崩溃时生成的coredump文件位于/tmp目录下: echo /tmp/core.%e.%p > /proc/sys/kernel/core_pattern /tmp/也可以是其它的目录位置。最佳位置应当满足以下需求: * 对所有用户可写 * 空间容量足够大 * 掉电后文件不丢失
------ 最来在项目中遇到大型程序出现SIGSEGV ,一直不知道用core dump工具来调试程序,花了近一周的时间,才定位问题,老大很生气,后果很严重,呵呵,事后仔细学习了这块的知识,了解一点core dump的知识。 在使用半导体作为内存的材料前,人类是利用线圈当作内存的材料(发明者为王安),线圈就叫作core ,用线圈做的内存就叫作“core memory”。(线圈的单词应该是coil,呵呵)如今,半导体工业澎勃发展,已经没有人用线圈当内存了,不过,在许多情况下,人们还是把内存叫作“core”。 所以注意了:这里的core不是核心,而是内存。不过结合实际来看,好像也有点“内核所占内存”的意思。 core dump又是什么东东? 我 们在开发(或使用)一个程序时,最怕的就是程序莫明其妙地挂掉。虽然系统没事,但我们下次仍可能遇到相同的问题。于是,这时操作系统就会把程序挂掉时的 内存内容写入一个叫做core的文件里(这个写入的动作就叫dump,dump的英语意思是垃圾、倾倒。从这里来看,这些内存的内容是程序错误运行的结 果,所以算是垃圾,把他弄出来就好比从大的内存池里“倾倒”。),以便于我们调试。这个过程,因此叫做core dump。 1. 在嵌入式系统中,有时core dump直接从串口打印出来,结合objdump查找ra和epa地址,运用栈回溯,可以找到程序出错的地方。 2. 在一般Linux系统中,默认是不会产生core dump文件的,通过ulimit -c来查看core dump文件的大小,一般开始是0,可以设置core文件大小,ulimit -c 1024(kbytes单位)或者ulimit -c unlimited。 3. core dump文件输出设置,一般默认是当前目录,可以在/proc/sys/kernel中找到core-user-pid,通过 echo "1" > /proc/sys/kernel/core-user-pid使core文件名加上pid号,还可以用 mkdir -p /root/corefile echo "/root/corefile/core-%e-%p-%t" > /proc/sys/kernel/core-pattern控制core文件保存位置和文件名格式。 以下是参数列表: %p - insert pid into filename 添加pid %u - insert current uid into filename 添加当前uid %g - insert current gid into filename 添加当前gid %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 添加文件名 %c 转储文件的大小上限 %e 所dump的文件名 %g 所dump的进程的实际组ID %h 主机名 %p 所dump的进程PID %s 导致本次coredump的信号 %t 转储时刻(由1970年1月1日起计的秒数) %u 所dump进程的实际用户ID
4. 用gdb查看core文件:下面我们可以在发生运行时信号引起的错误时发生core dump了.编译时加上-g发生core dump之后, 用gdb进行查看core文件的内容, 以定位文件中引发core dump的行.gdb [exec file] [core file]如:gdb ./test test.core在进入gdb后, 用bt命令查看backtrace以检查发生程序运行到哪里, 来定位core dump的文件行. 5. 给个例子 test.c
void a() { char *p = NULL; printf("%d/n", *p); }
int main() { a(); return 0; }
编译 gcc -g -o test test.c 运行 ./test 报segmentation fault(core dump) gdb ./test test.core如果生成的是test.core. http://blog.csdn.net/wen0006/article/details/3945845 --------
一,什么是core文件?什么是core dump?为什么要提出这?
Gdb手册上是这么描述core文件的定义的,A core file or core dump is a file that records the memory image of a running process and its process status(register values etc...)。
Core文件理解:当一个进程崩溃时,在该进程会在指定目录生成一个core文件 用来记录该进程崩溃时的内存映像,并附带了一些调试信息。该文件主要供 调试使用。
(1)在软件开发中,很多bug只能在特定的环境和条件下才能出现,重现的时机 和条件都很难把握。有可能出现很多次测试后该问题才重现一次。这就给调试带 来了很多不便。 (2)还有一种情形,就是软件的代码量比较大,如果靠设断点和单步跟踪也很 麻烦,起码很费时间。 为了解决上面的两个问题,就提出了core dump技术,在程序崩溃的时候,将 程序的内存映像保存到一个core文件中去,然后通过分析这个core文件来找到程序 崩溃的原因。 ----------------------------------------------------------------
二,怎么查看系统是否打开生成core文件的功能?没有开启又该如何开启?
可以使用ulimit命令查看。 #ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited file size (blocks, -f) unlimited max locked memory (kbytes, -l) 4 max memory size (kbytes, -m) unlimited open files (-n) 2048 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) 7168 virtual memory (kbytes, -v) unlimited
core file size (blocks, -c) 0说明core文件的最大大小为0,说明core dump 没有开启。可以使用ulimit -c unlimited来开启core dump。 ---------------------------------------------------------------
三,如何设置core dump文件名及其文件位置?
/proc/sys/kernel/core_uses_pid 这个文件内容为0的话,所有core dump文件 名都是core,没有扩展名;内容为1的话,文件名编程core.pid,即加上进程号作 为扩展名。
sudo echo "1" > /proc/sys/kernel/core_uses_pid 修改该参数。
还可以通过修改/proc/sys/kernel/core_pattern来指定core dump文件位置和文件名, 此文件内容改为/tmp/coredumpfile/core-%e-%p-%t,表示所有的core dump都放在/tmp/coredumpfile目录下,文件名为core-命令名-pid-系统时间详细参数列表
%p - insert pid into filename 添加pid %u - insert current uid into filename 添加当前uid %g - insert current gid into filename 添加当前gid %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 添加命令名 ----------------------------------------------------------------------------四,如何使用gdb来调试core文件?
gdb [选项] 被调试的可执行文件 core文件
执行该命令,gdb会产生生成该core文件的进程名,中断该进程的信号等。
当进程接收到一下UNIX信号时会产生core文件。
SIGABRT :调用abort函数产生该信号,进程异常终止。 SIGFPE:该信号表示一个算术运算异常,例如除以0,浮点数溢出等。 ... -----------------------------------------------------------------------------
五,实例:(通过除数为0制造出core dump) #include int wib(int no1, int no2) { int result, diff; diff = no1 - no2; result = no1 / diff; return result; } int main(int argc, char *argv[]) { int value, div, result, i, total; value = 10; div = 6; total = 0; for(i = 0; i |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |