Redhat Linux下如何生成core dump文件
在Redhat Linux系统中默认是不生成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/2007/07/16/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 Linux (5.2.1-4)
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)
进入gdb提示符,输入where,找到错误发生的位置和堆栈,如下:
(gdb) where
#0 0×4202cec1 in __strtoul_internal () from /lib/i686/libc.so.6
#1 0×4202d4e7 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×0804b9d7 in ConstrctVODProgram (vod_program=0×40345bdc) at cmm_test_tool.c:946
#4 0×0804a2f4 in TVRequestThread (arg=0×0) at cmm_test_tool.c:372
#5 0×40021941 in pthread_start_thread () from /lib/i686/libpthread.so.0
(gdb)
至此,可以看出文件出错的位置是函数 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
#include
int main()
{
char *p = NULL;
*p = 10;
}
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:http://blog.tianya.cn/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函 数,因此适用于有可能调用该函数会失败的情况
下面的例子显示了这三个函数的用法
#include
#include
#include
/* Obtain a backtrace and print it to stdout. */
void
print_trace (void)
{
void *array[10];
size_t size;
char **strings;
size_t i;
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. */
void
dummy_function (void)
{
print_trace ();
}
int
main (void)
{
dummy_function ();
return 0;
}[/i]
[i]备注:void *const *buffer -- buffer指向char类型的常量指针的指针(很是拗口)[/i]
[b]善用[/b][b]backtrace[/b][b]解决大问题[/b][b]([/b][b]转[/b][b])[/b]
程序在得到一个Segmentation fault这样的错误信息毫无保留地就跳出来了,遇到这样的问题让人很痛苦,查找问题不亚于你N多天辛苦劳累编写代码的难度。那么有没有更好的方法可以在产生SIGSEGV信号的时候得到调试可用的信息呢?看看下面的例程吧!
sigsegv.h
#ifndef __sigsegv_h__
#define __sigsegv_h__
#ifdef __cplusplus
extern "C" {
#endif
int setup_sigsegv();
#ifdef __cplusplus
}
#endif
#endif /* __sigsegv_h__ */
sigsegv.c
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#ifndef NO_CPP_DEMANGLE
#include
#endif
#if defined(REG_RIP)
# define SIGSEGV_STACK_IA64
# define REGFORMAT "%016lx"
#elif defined(REG_EIP)
# define SIGSEGV_STACK_X86
# define REGFORMAT "%08x"
#else
# define SIGSEGV_STACK_GENERIC
# define REGFORMAT "%x"
#endif
static void signal_segv(int signum, siginfo_t* info, void*ptr) {
static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
size_t i;
ucontext_t *ucontext = (ucontext_t*)ptr;
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
int f = 0;
Dl_info dlinfo;
void **bp = 0;
void *ip = 0;
#else
void *bt[20];
char **strings;
size_t sz;
#endif
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];
# endif
fprintf(stderr, "Stack trace:/n");
while(bp && ip) {
if(!dladdr(ip, &dlinfo))
break;
const char *symname = dlinfo.dli_sname;
#ifndef NO_CPP_DEMANGLE
int status;
char *tmp = __cxa_demangle(symname, NULL, 0, &status);
if(status == 0 && tmp)
symname = tmp;
#endif
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);
#endif
if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
break;
ip = bp[1];
bp = (void**)bp[0];
}
#else
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]);
#endif
fprintf(stderr, "End of stack trace/n");
exit (-1);
}
int setup_sigsegv() {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = signal_segv;
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();
}
#endif
main.c
#include "sigsegv.h"
#include
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] = 0x00000033
reg[01] = 0x00000000
reg[02] = 0xc010007b
reg[03] = 0x0000007b
reg[04] = 0x00000000
reg[05] = 0xb7fc8ca0
reg[06] = 0xbff04c2c
reg[07] = 0xbff04c1c
reg[08] = 0xb7f8cff4
reg[09] = 0x00000001
reg[10] = 0xbff04c50
reg[11] = 0x00000000
reg[12] = 0x0000000e
reg[13] = 0x00000006
reg[14] = 0x080489ec
reg[15] = 0x00000073
reg[16] = 0x00010282
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
0x080489e2 : movl $0x0,0xfffffffc(%ebp)
0x080489e9 : mov 0xfffffffc(%ebp),%eax
0x080489ec : movl $0x6e6e6f67,(%eax)
0x080489f2 : movw $0x7265,0x4(%eax)
0x080489f8 : movb $0x0,0x6(%eax)
0x080489fc : mov $0x0,%eax
0x08048a01 : leave
0x08048a02 : ret
End of assembler dump.
gdb>
也可以直接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
3
4 int die() {
5 char *err = NULL;
6 strcpy(err, "gonner");
7 return 0;
8 }
9
10 int main() {
gdb>
现 在看看定位错误将会多么方便,上面的调试指令中list之前break不是必须的,只是让你可以看到break其实就已经指出了哪一行代码导致 Segmentation fault了。如果你要发布你的程序你一般会为了减少体积不会附带调试信息的(也就是不加-ggdb -g参数),不过没关系,你一样可以得到上面stack-trace信息,然后你调试之前只要加上调试信息即可。