ubuntu coredump文件 dump的文件在哪个目录

当程序运行的过程中异常终止或崩溃,操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为就叫做Core Dump(中文有的翻译成&核心转储&)。我们可以认为 core dump 是&内存快照&,但实际上,除了内存信息之外,还有些关键的程序运行状态也会同时 dump 下来,例如寄存器信息(包括程序指针、栈指针等)、内存管理信息、其他处理器和操作系统状态和信息。core dump 对于编程人员诊断和调试程序是非常有帮助的,因为对于有些程序错误是很难重现的,例如指针异常,而 core dump 文件可以再现程序出错时的情景。
Core Dump 名词解释
在半导体作为电脑内存材料之前,电脑内存使用的是&(Magnetic Core Memory),Core Dump 中的 Core 沿用了磁芯内存的&Core&表达。图为磁芯内存的一个单元,来自&.
在&APUE&一书中作者有句话这样写的:
Because the file is named&core, it shows how long this feature has been part of the Unix System.
这里的 core 就是沿用的是早期电脑磁芯内存中的表达,也能看出 Unix 系统 Core Dump 机制的悠久历史。
Dump&指的是拷贝一种存储介质中的部分内容到另一个存储介质,或者将内容打印、显示或者其它输出设备。dump 出来的内容是格式化的,可以使用一些工具来解析它。
现代操作系统中,用&Core Dump&表示当程序异常终止或崩溃时,将进程此时的内存中的内容拷贝到磁盘文件中存储,以方便编程人员调试。
Core Dump 如何产生
上面说当程序运行过程中异常终止或崩溃时会发生 core dump,但还没说到什么具体的情景程序会发生异常终止或崩溃,例如我们使用&kill -9&命令杀死一个进程会发生 core dump 吗?实验证明是不能的,那么什么情况会产生呢?
Linux 中信号是一种异步事件处理的机制,每种信号对应有其默认的操作,你可以在&&查看 Linux 系统提供的信号以及默认处理。默认操作主要包括忽略该信号(Ingore)、暂停进程(Stop)、终止进程(Terminate)、终止并发生core dump(core)等。如果我们信号均是采用默认操作,那么,以下列出几种信号,它们在发生时会产生 core dump:
SignalActionComment
Quit from keyboard
Illegal Instruction
Abort signal from&
Invalid memory reference
Trace/breakpoint trap
当然不仅限于上面的几种信号。这就是为什么我们使用&Ctrl+z&来挂起一个进程或者&Ctrl+C&结束一个进程均不会产生 core dump,因为前者会向进程发出&SIGTSTP&信号,该信号的默认操作为暂停进程(Stop Process);后者会向进程发出SIGINT&信号,该信号默认操作为终止进程(Terminate Process)。同样上面提到的&kill -9&命令会发出&SIGKILL&命令,该命令默认为终止进程。而如果我们使用&Ctrl+\&来终止一个进程,会向进程发出&SIGQUIT&信号,默认是会产生 core dump 的。还有其它情景会产生 core dump, 如:程序调用&abort()&函数、访存错误、非法指令等等。
下面举两个例子来说明:
终端下比较&Ctrl+C&和&Ctrl+\:
guohailin@guohailin:~$ sleep 10
#使用sleep命令休眠 10 s
#使用 Ctrl+C 终止该程序,不会产生 core dump
guohailin@guohailin:~$ sleep 10
^\Quit (core dumped)
#使用 Ctrl+\ 退出程序, 会产生 core dump
guohailin@guohailin:~$ ls
#多出下面一个 core 文件
-rw------- &1 guohailin guohailin 月 22 11:31 sleep.core.21990
小程序产生 core dump
#include &stdio.h&
int main()
int *null_ptr = NULL;
*null_ptr = 10;
//对空指针指向的内存区域写,会发生段错误
guohailin@guohailin:~$ ./a.out
Segmentation fault (core dumped)
guohailin@guohailin:~$ ls
#多出下面一个 core 文件
-rw-------
1 guohailin guohailin 月 22 11:35 a.out.core.22070
Linux 下打开 Core Dump
我使用的 Linux 发行版是 Ubuntu 13.04,设置生成 core dump 文件的方法如下:
打开 core dump 功能
在终端中输入命令&ulimit -c&,输出的结果为 0,说明默认是关闭 core dump 的,即当程序异常终止时,也不会生成 core dump 文件。
我们可以使用命令&ulimit -c unlimited&来开启 core dump 功能,并且不限制 core dump 文件的大小; 如果需要限制文件的大小,将 unlimited 改成你想生成 core 文件最大的大小,注意单位为 blocks(KB)。
用上面命令只会对当前的终端环境有效,如果想需要永久生效,可以修改文件&/etc/security/limits.conf文件,关于此文件的设置参看&&。增加一行:
# /etc/security/limits.conf
#Each line describes a limit for a user in the form:
修改 core 文件保存的路径
默认生成的 core 文件保存在可执行文件所在的目录下,文件名就为&core。
通过修改&/proc/sys/kernel/core_uses_pid&文件可以让生成 core 文件名是否自动加上 pid 号。例如&echo 1 & /proc/sys/kernel/core_uses_pid&,生成的 core 文件名将会变成&core.pid,其中 pid 表示该进程的 PID。
还可以通过修改&/proc/sys/kernel/core_pattern&来控制生成 core 文件保存的位置以及文件名格式。例如可以用&echo "/tmp/corefile-%e-%p-%t" & /proc/sys/kernel/core_pattern&设置生成的 core 文件保存在 &/tmp/corefile& 目录下,文件名格式为 &core-命令名-pid-时间戳&。&有更多详细的说明!
使用 gdb 调试 Core 文件
产生了 core 文件,我们该如何使用该 Core 文件进行调试呢?Linux 中可以使用 GDB 来调试 core 文件,步骤如下:
首先,使用 gcc 编译源文件,加上&-g&以增加调试信息;
按照上面打开 core dump 以使程序异常终止时能生成 core 文件;
运行程序,当core dump 之后,使用命令&gdb program core&来查看 core 文件,其中 program 为可执行程序名,core 为生成的 core 文件名。
下面用一个简单的例子来说明:
#include &stdio.h&
int func(int *p)
int y = *p;
int main()
int *p = NULL;
return func(p);
编译加上调试信息, 运行之后core dump, 使用 gdb 查看 core 文件.
guohailin@guohailin:~$ gcc core_demo.c -o core_demo -g
guohailin@guohailin:~$ ./core_demo
Segmentation fault (core dumped)
guohailin@guohailin:~$ gdb core_demo core_demo.core.24816
Core was generated by './core_demo'.
Program terminated with signal 11, Segmentation fault.
0x080483cd in func (p=0x0) at core_demo.c:5
int y = *p;
0x080483cd in func (p=0x0) at core_demo.c:5
0x080483ef in main () at core_demo.c:12
(gdb) info frame
Stack level 0, frame at 0xffd590a4:
eip = 0x80483cd in func (core_demo.c:5); saved eip 0x80483ef
called by frame at 0xffd590c0
source language c.
Arglist at 0xffd5909c, args: p=0x0
Locals at 0xffd5909c, Previous frame's sp is 0xffd590a4
Saved registers:
ebp at 0xffd5909c, eip at 0xffd590a0
从上面可以看出,我们可以还原 core_demo 执行时的场景,并使用&where&可以查看当前程序调用函数栈帧, 还可以使用 gdb 中的命令查看寄存器,变量等信息.
阅读(...) 评论()
一个代码可以创造一个世界,也可以毁灭一个世界!linux core dump详解_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
linux core dump详解
上传于|0|0|文档简介
&&linux系统下的进程core dump相关内容介绍
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩2页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢96423人阅读
linux研究(43)
一,什么是coredump
&&&&&&& 我们经常听到大家说到程序core掉了,需要定位解决,这里说的大部分是指对应程序由于各种异常或者bug导致在运行过程中异常退出或者中止,并且在满足一定条件下(这里为什么说需要满足一定的条件呢?下面会分析)会产生一个叫做core的文件。
&&&&&&& 通常情况下,core文件会包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成第一个文件,许多的程序出错的时候都会产生一个core文件,通过工具分析这个文件,我们可以定位到程序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决。
二,coredump文件的存储位置
&& core文件默认的存储位置与对应的可执行程序在同一目录下,文件名是core,大家可以通过下面的命令看到core文件的存在位置:
&& cat& /proc/sys/kernel/core_pattern
&& 缺省值是core
注意:这里是指在进程当前工作目录的下创建。通常与程序在相同的路径下。但如果程序中调用了chdir函数,则有可能改变了当前工作目录。这时core文件创建在chdir指定的路径下。有好多程序崩溃了,我们却找不到core文件放在什么位置。和chdir函数就有关系。当然程序崩溃了不一定都产生 core文件。
如下程序代码:则会把生成的core文件存储在/data/coredump/wd,而不是大家认为的跟可执行文件在同一目录。
通过下面的命令可以更改coredump文件的存储位置,若你希望把core文件生成到/data/coredump/core目录下:
&& echo “/data/coredump/core”& /proc/sys/kernel/core_pattern
注意,这里当前用户必须具有对/proc/sys/kernel/core_pattern的写权限。
缺省情况下,内核在coredump时所产生的core文件放在与该程序相同的目录中,并且文件名固定为core。很显然,如果有多个程序产生core文件,或者同一个程序多次崩溃,就会重复覆盖同一个core文件,因此我们有必要对不同程序生成的core文件进行分别命名。
我们通过修改kernel的参数,可以指定内核所生成的coredump文件的文件名。例如,使用下面的命令使kernel生成名字为core.filename.pid格式的core dump文件:
echo “/data/coredump/core.%e.%p” &/proc/sys/kernel/core_pattern
这样配置后,产生的core文件中将带有崩溃的程序名、以及它的进程ID。上面的%e和%p会被替换成程序文件名以及进程ID。
如果在上述文件名中包含目录分隔符“/”,那么所生成的core文件将会被放到指定的目录中。 需要说明的是,在内核中还有一个与coredump相关的设置,就是/proc/sys/kernel/core_uses_pid。如果这个文件的内容被配置成1,那么即使core_pattern中没有设置%p,最后生成的core dump文件名仍会加上进程ID。
三,如何判断一个文件是coredump文件?
在类unix系统下,coredump文件本身主要的格式也是ELF格式,因此,我们可以通过readelf命令进行判断。
&&&&&可以看到ELF文件头的Type字段的类型是:CORE (Core file)
&&&& 可以通过简单的file命令进行快速判断:&&&&
四,产生coredum的一些条件总结
1,& 产生coredump的条件,首先需要确认当前会话的ulimit –c,若为0,则不会产生对应的coredump,需要进行修改和设置。
ulimit& -c&unlimited& (可以产生coredump且不受大小限制)
若想甚至对应的字符大小,则可以指定:
ulimit –c [size]
&&&&&&&&&&&&&&&
&&&&&& 可以看出,这里的size的单位是blocks,一般1block=512bytes
&&&&&&& 如:
&&&&&&& ulimit –c 4& (注意,这里的size如果太小,则可能不会产生对应的core文件,笔者设置过ulimit –c 1的时候,系统并不生成core文件,并尝试了1,2,3均无法产生core,至少需要4才生成core文件)
但当前设置的ulimit只对当前会话有效,若想系统均有效,则需要进行如下设置:
?& 在/etc/profile中加入以下一行,这将允许生成coredump文件
ulimit-c unlimited
?& 在rc.local中加入以下一行,这将使程序崩溃时生成的coredump文件位于/data/coredump/目录下:
echo /data/coredump/core.%e.%p& /proc/sys/kernel/core_pattern&
注意rc.local在不同的环境,存储的目录可能不同,susu下可能在/etc/rc.d/rc.local
&&&&&&更多ulimit的命令使用,可以参考:
&&&&&&这些需要有root权限, 在ubuntu下每次重新打开中断都需要重新输入上面的ulimit命令, 来设置core大小为无限.
2, 当前用户,即执行对应程序的用户具有对写入core目录的写权限以及有足够的空间。
3, 几种不会产生core文件的情况说明:
The&core&file&will&not&be&generated&if
(a)&&&&the&process&was&set-user-ID&and&the&current&user&is&not&the&owner&of&the&program&file,&or
(b)&&&&&the&process&was&set-group-ID&and&the&current&user&is&not&the&group&owner&of&the&file,
(c)&&&&&the&user&does&not&have&permission&to&write&in&the&current&working&directory,&
(d)&&&&&the&file&already&exists&and&the&user&does&not&have&permission&to&write&to&it,&or&
(e)&&&&&the&file&is&too&big&(recall&the&RLIMIT_CORE&limit&in&Section&7.11).&The&permissions&of&the&core&file&(assuming&that&the&file&doesn't&already&exist)&are&usually&user-read&and&user-write,&although&Mac&OS&X&sets&only&user-read.
五,coredump产生的几种可能情况
造成程序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,多线程读写的数据未加锁保护。
对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成coredump
&4,非法指针
& a) 使用空指针
& b) 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为bus error而core dump。
&5,堆栈溢出
不要使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。&&
六,利用gdb进行coredump的定位
& 其实分析coredump的工具有很多,现在大部分类unix系统都提供了分析coredump文件的工具,不过,我们经常用到的工具是gdb。
& 这里我们以程序为例子来说明如何进行定位。
1,& 段错误 – segmentfault
?& 我们写一段代码往受到系统保护的地址写内容。
?& 按如下方式进行编译和执行,注意这里需要-g选项编译。
可以看到,当输入12的时候,系统提示段错误并且core dumped
?& 我们进入对应的core文件生成目录,优先确认是否core文件格式并启用gdb进行调试。
从红色方框截图可以看到,程序中止是因为信号11,且从bt(backtrace)命令(或者where)可以看到函数的调用栈,即程序执行到coremain.cpp的第5行,且里面调用scanf 函数,而该函数其实内部会调用_IO_vfscanf_internal()函数。
接下来我们继续用gdb,进行调试对应的程序。
记住几个常用的gdb命令:
l(list) ,显示源代码,并且可以看到对应的行号;
b(break)x, x是行号,表示在对应的行号位置设置断点;
p(print)x, x是变量名,表示打印变量x的值
r(run), 表示继续执行到断点的位置
n(next),表示执行下一步
c(continue),表示继续执行
q(quit),表示退出gdb
启动gdb,注意该程序编译需要-g选项进行。
注:& SIGSEGV&&&&&11&&&&&& Core&&& Invalid memoryreference
七,附注:
1,& gdb的查看源码
显示源代码
GDB 可以打印出所调试程序的源代码,当然,在程序编译时一定要加上-g的参数,把源程序信息编译到执行文件中。不然就看不到源程序了。当程序停下来以后,GDB会报告程序停在了那个文件的第几行上。你可以用list命令来打印程序的源代码。还是来看一看查看源代码的GDB命令吧。
list&linenum&
显示程序第linenum行的周围的源程序。
list&function&
显示函数名为function的函数的源程序。
显示当前行后面的源程序。
显示当前行前面的源程序。
一般是打印当前行的上5行和下5行,如果显示函数是是上2行下8行,默认是10行,当然,你也可以定制显示的范围,使用下面命令可以设置一次显示源程序的行数。
setlistsize &count&
设置一次显示源代码的行数。
showlistsize
查看当前listsize的设置。
list命令还有下面的用法:
list&first&, &last&
显示从first行到last行之间的源代码。
list ,&last&
显示从当前行到last行之间的源代码。
list +
往后显示源代码。
一般来说在list后面可以跟以下这些参数:
&linenum&&& 行号。
&+offset&&& 当前行号的正偏移量。
&-offset&&& 当前行号的负偏移量。
&filename:linenum&& 哪个文件的哪一行。
&function&& 函数名。
&filename:function&哪个文件中的哪个函数。
&*address&& 程序运行时的语句在内存中的地址。
2,& 一些常用signal的含义
SIGABRT:调用abort函数时产生此信号。进程异常终止。
SIGBUS:指示一个实现定义的硬件故障。
SIGEMT:指示一个实现定义的硬件故障。EMT这一名字来自PDP-11的emulator trap 指令。
SIGFPE:此信号表示一个算术运算异常,例如除以0,浮点溢出等。
SIGILL:此信号指示进程已执行一条非法硬件指令。4.3BSD由abort函数产生此信号。SIGABRT现在被用于此。
SIGIOT:这指示一个实现定义的硬件故障。IOT这个名字来自于PDP-11对于输入/输出TRAP(input/outputTRAP)指令的缩写。系统V的早期版本,由abort函数产生此信号。SIGABRT现在被用于此。
SIGQUIT:当用户在终端上按退出键(一般采用Ctrl-/)时,产生此信号,并送至前台进
程组中的所有进程。此信号不仅终止前台进程组(如SIGINT所做的那样),同时产生一个core文件。
SIGSEGV:指示进程进行了一次无效的存储访问。名字SEGV表示“段违例(segmentationviolation)”。
SIGSYS:指示一个无效的系统调用。由于某种未知原因,进程执行了一条系统调用指令,但其指示系统调用类型的参数却是无效的。
SIGTRAP:指示一个实现定义的硬件故障。此信号名来自于PDP-11的TRAP指令。
SIGXCPUSVR4和4.3+BSD支持资源限制的概念。如果进程超过了其软C P U时间限制,则产生此信号。
SIGXFSZ:如果进程超过了其软文件长度限制,则SVR4和4.3+BSD产生此信号。
3,& Core_pattern的格式
可以在core_pattern模板中使用变量还很多,见下面的列表:
%% 单个%字符
%p 所dump进程的进程ID
%u 所dump进程的实际用户ID
%g 所dump进程的实际组ID
%s 导致本次core dump的信号
%t core dump的时间 (由日计起的秒数)
%e 程序文件名
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1469823次
积分:14818
积分:14818
排名:第690名
原创:245篇
转载:206篇
评论:183条
(1)(1)(1)(1)(2)(1)(4)(2)(1)(2)(1)(1)(1)(1)(1)(4)(3)(1)(2)(7)(8)(2)(3)(2)(2)(2)(3)(6)(2)(7)(10)(5)(12)(7)(9)(10)(7)(9)(14)(3)(5)(6)(9)(12)(17)(6)(5)(8)(7)(11)(3)(1)(2)(5)(6)(2)(10)(2)(1)(8)(4)(23)(35)(31)(2)(5)(6)(16)(9)(10)(3)(7)(2)(3)(14)Redhat Linux下如何生成core dump文件
下如何生成core dump文件
在 系统中默认是不生成core dump文件的,这是因为在/etc/profile文件中有这样一行
ulimit -S -c 0 & /dev/null 2&&1
如何打开core dump呢?最简单的方法是用户在自己的~/.bash_profile中加入ulimit -S -c unlimited & /dev/null 2&&1,这样设置后允许当前用户生成没有大小限制的core dump文件。此外还有两种系统级修改生成core dump的方法。
第一种方法是修改/etc/profile,把ulimit那一行改为
ulimit -S -c unlimited & /dev/null 2&&1
这样设置后系统允许所有用户生成没有大小限制的core dump文件。这样做的优点是不需要重起系统,缺点是无法控制只让某些用户生成core dump文件。
第二种方法是修改/etc/security/limits.conf文件。很多系统上限都可以通过修改这个文件改变,如最大子进程个数,最大打开文件数等等。这个文件有详细的注释,对如何修改这个文件做了说明。如果想对所有用户打开core dump,可以加入一行
* soft core 0
如果只想对某些用户或用户组打开core dump,可以加入
user soft core 0或@group soft core 0
注意如果通过修改/etc/security/limits.conf文件打开core dump,还需要注释掉/etc/profile中的ulmit那一行
#ulimit -S -c 0 & /dev/null 2&&1
这样修改的优点是可以针对特定用户或特定组打开core dump文件,缺点是需要重起系统。
最后说一下生成core dump文件的位置,默认位置与可执行程序在同一目录下,文件名是core.***,其中***是一个数字。core dump文件名的模式保存在/proc/sys/kernel/core_pattern中,缺省值是core。通过以下命令可以更改core dump文件的位置(如希望生成到/tmp/cores目录下)
echo &/tmp/cores/core& & /proc/sys/kernel/core_pattern
core dump(内核转储) 的使用
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/chaoi/archive//1693149.aspx在Unix系统下,应用程序崩溃,一般会产生core文件,如何根据core文件查找问题的所在,并做相应的分析和调试,是非常重要的,本文对此做简单介绍。
例如,一个程序cmm_test_tool在运行的时候发生了错误,并生成了一个core文件,如下:
-rw-r&r& 1 root cmm_test_tool.c
-rw-r&r& 1 root cmm_test_tool.o
-rwxr-xr-x 1 root cmm_test_tool
-rw&&- 1 root core.19344
-rw&&- 1 root core.19351
-rw-r&r& 1 root cmm_test_tool.cfg
-rw-r&r& 1 root cmm_test_tool.res
-rw-r&r& 1 root cmm_test_tool.log
[root@AUTOTEST_SIM2 mam2cm]#
就可以利用命令gdb进行查找,参数一是应用程序的名称,参数二是core文件,运行
gdb cmm_test_tool core.19344结果如下:
[root@AUTOTEST_SIM2 mam2cm]# gdb cmm_test_tool core.19344
GNU gdb Red Hat
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type &show copying& to see the conditions.
There is absolutely no warranty for GDB. Type &show warranty& for details.
This GDB was configured as &i386-redhat-linux&&
Core was generated by `./cmm_test_tool&.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/i686/libpthread.so.0&done.
Loaded symbols for /lib/i686/libpthread.so.0
Reading symbols from /lib/i686/libm.so.6&done.
Loaded symbols for /lib/i686/libm.so.6
Reading symbols from /usr/lib/libz.so.1&done.
Loaded symbols for /usr/lib/libz.so.1
Reading symbols from /usr/lib/libstdc++.so.5&done.
Loaded symbols for /usr/lib/libstdc++.so.5
Reading symbols from /lib/i686/libc.so.6&done.
Loaded symbols for /lib/i686/libc.so.6
Reading symbols from /lib/libgcc_s.so.1&done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /lib/ld-linux.so.2&done.
Loaded symbols for /lib/ld-linux.so.2
Reading symbols from /lib/libnss_files.so.2&done.
Loaded symbols for /lib/libnss_files.so.2
#0 0&4202cec1 in __strtoul_internal () from /lib/i686/libc.so.6
进入gdb提示符,输入where,找到错误发生的位置和堆栈,如下:
(gdb) where
#0 0&4202cec1 in __strtoul_internal () from /lib/i686/libc.so.6
#1 0& in strtoul () from /lib/i686/libc.so.6
#2 0&0804b4da in GetMaxIDFromDB (get_type=2, max_id=0&806fd20) at cmm_test_tool.c:788
#3 0& in ConstrctVODProgram (vod_program=0&40345bdc) at cmm_test_tool.c:946
#4 0& in TVRequestThread (arg=0&0) at cmm_test_tool.c:372
#5 0& in pthread_start_thread () from /lib/i686/libpthread.so.0
至此,可以看出文件出错的位置是函数 GetMaxIDFromDB ,两个参数分别是2和0&806fd20,这个函数位于源代码的788行,基于此,我们就可以有针对性的找到问题的根源,并加以解决。
linux c Segmentation fault
To debug segmentation fault, please following steps:&
& ulimit &c unlimited&
# run test image&
& ./a.out&
# Segmenation fault happened. You will see the file &core.xxxx& (xxxx is pid) in the directory&
& gdb a.out core.xxxx&
& (gdb) bt&
# Then you will see the segmentation fault point at the File xxxx.cpp : Line xxxx.&
举个例子,我在fedora 下面运行这个代码的, 文件名叫做test.c&
int main()&
char *p = NULL;&
1.编译一下 gcc -ggdb test.c&
2.输入命令 ulimit -c unlimited&
3.运行文件 ./a.out&
发生segmentation falut,同时会生成一个文件core.xxxx(xxxx means pid)&
4.gdb a.out core.xxxx&
5.gdb & bt&
马上就会输出错误代码所在的文件和行数,同时还打印出这句错误的语句。
Cited from:/blogger/post_show.asp?BlogID=420361&PostID=7613747
backtrace函数与堆栈
[b]linux[/b][b]下追踪函数调用堆栈[/b]
一般察看函数运行时堆栈的方法是使用GDB之类的外部调试器,但是,有些时候为了分析程序的BUG,(主要针对长时间运行程序的分析),在程序出错时打印出函数的调用堆栈是非常有用的。
在头文件&execinfo.h&中声明了三个函数用于获取当前线程的函数调用堆栈
Function: int backtrace(void **buffer,int size)
该函数用与获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针列表。参数 size 用来指定buffer中可以保存多少个void* 元素。函数返回值是实际获取的指针个数,最大不超过size大小
在buffer中的指针实际是从堆栈中获取的返回地址,每一个堆栈框架有一个返回地址
注意某些编译器的优化选项对获取正确的调用堆栈有干扰,另外内联函数没有堆栈框架;删除框架指针也会使无法正确解析堆栈内容
Function: char ** backtrace_symbols (void *const *buffer, int size)
backtrace_symbols将从backtrace函数获取的信息转化为一个字符串数组. 参数buffer应该是从backtrace函数获取的数组指针,size是该数组中的元素个数(backtrace的返回值) &&
函数返回值是一个指向字符串数组的指针,它的大小同buffer相同.每个字符串包含了一个相对于buffer中对应元素的可打印信息.它包括函数名,函数的偏移地址,和实际的返回地址
现在,只有使用ELF二进制格式的程序和苦衷才能获取函数名称和偏移地址.在其他系统,只有16进制的返回地址能被获取.另外,你可能需要传递相应的标志给链接器,以能支持函数名功能(比如,在使用GNU ld的系统中,你需要传递(-rdynamic))
该函数的返回值是通过malloc函数申请的空间,因此调用这必须使用free函数来释放指针.
注意:如果不能为字符串获取足够的空间函数的返回值将会为NULL
Function:void backtrace_symbols_fd (void *const *buffer, int size, int fd)
backtrace_symbols_fd 与backtrace_symbols 函数具有相同的功能,不同的是它不会给调用者返回字符串数组,而是将结果写入文件描述符为fd的文件中,每个函数对应一行.它不需要调用malloc函 数,因此适用于有可能调用该函数会失败的情况
下面的例子显示了这三个函数的用法&
/* Obtain a backtrace and print it to stdout. */
print_trace (void)
void *array[10];
size = backtrace (array, 10);
strings = backtrace_symbols (array, size);
printf (&Obtained %zd stack frames.\n&, size);
for (i = 0; i [i]);
free (strings);
/* A dummy function to make the backtrace more interesting. */
dummy_function (void)
print_trace ();
main (void)
dummy_function ();
[i]备注:void *const *buffer -- buffer指向char类型的常量指针的指针(很是拗口)[/i]
[b]善用[/b][b]backtrace[/b][b]解决大问题[/b][b]([/b][b]转[/b][b])[/b]
程序在得到一个Segmentation fault这样的错误信息毫无保留地就跳出来了,遇到这样的问题让人很痛苦,查找问题不亚于你N多天辛苦劳累编写代码的难度。那么有没有更好的方法可以在产生SIGSEGV信号的时候得到调试可用的信息呢?看看下面的例程吧!
#ifndef __sigsegv_h__
#define __sigsegv_h__
#ifdef __cplusplus
extern &C& {
& int setup_sigsegv();
#ifdef __cplusplus
#endif /* __sigsegv_h__ */
#define _GNU_SOURCE
#ifndef NO_CPP_DEMANGLE
#if defined(REG_RIP)
# define SIGSEGV_STACK_IA64
# define REGFORMAT &%016lx&
#elif defined(REG_EIP)
# define SIGSEGV_STACK_X86
# define REGFORMAT &%08x&
# define SIGSEGV_STACK_GENERIC
# define REGFORMAT &%x&
static void signal_segv(int signum, siginfo_t* info, void*ptr) {
& static const char *si_codes[3] = {&&, &SEGV_MAPERR&, &SEGV_ACCERR&};
& ucontext_t *ucontext = (ucontext_t*)
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
& int f = 0;
& void **bp = 0;
& void *ip = 0;
& void *bt[20];
& fprintf(stderr, &Segmentation Fault!\n&);
& fprintf(stderr, &info.si_signo = %d\n&, signum);
& fprintf(stderr, &info.si_errno = %d\n&, info-&si_errno);
& fprintf(stderr, &info.si_code &= %d (%s)\n&, info-&si_code, si_codes[info-&si_code]);
& fprintf(stderr, &info.si_addr &= %p\n&, info-&si_addr);
& for(i = 0; i & & fprintf(stderr, &reg[%02d] & & & = 0x& REGFORMAT &\n&, i, ucontext-&uc_mcontext.gregs[i]);
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
# if defined(SIGSEGV_STACK_IA64)
& ip = (void*)ucontext-&uc_mcontext.gregs[REG_RIP];
& bp = (void**)ucontext-&uc_mcontext.gregs[REG_RBP];
# elif defined(SIGSEGV_STACK_X86)
& ip = (void*)ucontext-&uc_mcontext.gregs[REG_EIP];
& bp = (void**)ucontext-&uc_mcontext.gregs[REG_EBP];
& fprintf(stderr, &Stack trace:\n&);
& while(bp && ip) {
& & if(!dladdr(ip, &dlinfo))
& & const char *symname = dlinfo.dli_
#ifndef NO_CPP_DEMANGLE
& & char *tmp = __cxa_demangle(symname, NULL, 0, &status);
& & if(status == 0 && tmp)
& & & symname =
& & fprintf(stderr, &% 2d: %p &(%s)\n&,
& & & & & & ++f,
& & & & & & ip,
& & & & & & symname,
& & & & & & (unsigned)(ip - dlinfo.dli_saddr),
& & & & & & dlinfo.dli_fname);
#ifndef NO_CPP_DEMANGLE
& & if(tmp)
& & & free(tmp);
& & if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, &main&))
& & ip = bp[1];
& & bp = (void**)bp[0];
& fprintf(stderr, &Stack trace (non-dedicated):\n&);
& sz = backtrace(bt, 20);
& strings = backtrace_symbols(bt, sz);
& for(i = 0; i & & fprintf(stderr, &%s\n&, strings[i]);
& fprintf(stderr, &End of stack trace\n&);
& exit (-1);
int setup_sigsegv() {
& memset(&action, 0, sizeof(action));
& action.sa_sigaction = signal_
& action.sa_flags = SA_SIGINFO;
& if(sigaction(SIGSEGV, &action, NULL) & & perror(&sigaction&);
& & return 0;
& return 1;
#ifndef SIGSEGV_NO_AUTO_INIT
static void __attribute((constructor)) init(void) {
& setup_sigsegv();
#include &sigsegv.h&
int die() {
& char *err = NULL;
& strcpy(err, &gonner&);
& return 0;
int main() {
& return die();
下面来编译上面的main.c程序看看将会产生什么样的信息呢,不过要注意的就是如果要在你的程序里引用sigsegv.h、sigsegv.c得到堆栈信息的话记得加上-rdynamic -ldl参数。
/data/codes/c/test/backtraces $ gcc -o test -rdynamic -ldl -ggdb -g sigsegv.c main.c
/data/codes/c/test/backtraces $ ./test
Segmentation Fault!
info.si_signo = 11
info.si_errno = 0
info.si_code &= 1 (SEGV_MAPERR)
info.si_addr &= (nil)
reg[00] & & & = 0x
reg[01] & & & = 0x
reg[02] & & & = 0xc010007b
reg[03] & & & = 0x0000007b
reg[04] & & & = 0x
reg[05] & & & = 0xb7fc8ca0
reg[06] & & & = 0xbff04c2c
reg[07] & & & = 0xbff04c1c
reg[08] & & & = 0xb7f8cff4
reg[09] & & & = 0x
reg[10] & & & = 0xbff04c50
reg[11] & & & = 0x
reg[12] & & & = 0x0000000e
reg[13] & & & = 0x
reg[14] & & & = 0x080489ec
reg[15] & & & = 0x
reg[16] & & & = 0x
reg[17] & & & = 0xbff04c1c
reg[18] & & & = 0x0000007b
Stack trace:
1: 0x80489ec &(/data/codes/c/test/backtraces/test)
2: 0x8048a16 &(/data/codes/c/test/backtraces/test)
End of stack trace
/data/codes/c/test/backtraces $
下面用gdb来看看出错的地方左右的代码:
/data/codes/c/test/backtraces $ gdb ./test
gdb& disassemble die+16
Dump of assembler code for function die:
0x080489dc : & & push & %ebp
0x080489dd : & & mov & &%esp,%ebp
0x080489df : & & sub & &$0x10,%esp
0x : & & movl & $0x0,0xfffffffc(%ebp)
0x : & &mov & &0xfffffffc(%ebp),%eax
0x080489ec : & &movl & $0x6e6e6f67,(%eax)
0x : & &movw & $0x(%eax)
0x : & &movb & $0x0,0x6(%eax)
0x080489fc : & &mov & &$0x0,%eax
0x08048a01 : & &leave &
0x08048a02 : & &ret & &
End of assembler dump.
也可以直接break *die+16进行调试,看看在出错之前的堆栈情况,那么下面我们再来看看代码问题到底出在什么地方了。
/data/codes/c/test/backtraces $ gdb ./test
gdb& break *die+16
Breakpoint 1 at 0x80489f2: file main.c, line 6.
gdb& list *die+16
0x80489f2 is in die (main.c:6).
1 & & & #include &sigsegv.h&
2 & & & #include&
4 & & & int die() {
5 & & & & char *err = NULL;
6 & & & & strcpy(err, &gonner&);
7 & & & & return 0;
10 & & &int main() {
现 在看看定位错误将会多么方便,上面的调试指令中list之前break不是必须的,只是让你可以看到break其实就已经指出了哪一行代码导致 Segmentation fault了。如果你要发布你的程序你一般会为了减少体积不会附带调试信息的(也就是不加-ggdb -g参数),不过没关系,你一样可以得到上面stack-trace信息,然后你调试之前只要加上调试信息即可。
顶一下(0) 踩一下(0)
热门标签:}

我要回帖

更多关于 ubuntu 打开coredump 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信