歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> Redhat Linux下如何生成core dump文件

Redhat Linux下如何生成core dump文件

日期:2017/3/1 14:43:17   编辑:關於Linux
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信息,然後你調試之前只要加上調試信息即可。
Copyright © Linux教程網 All Rights Reserved