来自:http://blog.ddup.us/?p=176html
写C/C++程序常常要直接和内存打交道,一不当心就会形成程序执行时产生Segment Fault而挂掉。通常这种状况都是由于数组越界访问,空指针或是野指针读写形成的。程序小的话还比较好办,对着源代码仔细检查就能解决。可是对于代码量 较大的程序,里边包含N多函数调用,N多数组指针访问,这时想定位问题就不是很容易了(此时牛人依然能够经过在适当位置打printf加二分查找的方式迅 速定位:P)。懒人的话仍是直接GDB搞起吧。linux
偶尔就能听见某程序员同窗抱怨“擦,又出Core了!”。简单来讲,core dump说的是操做系统执行的一个动做,当某个进程由于一些缘由意外终止(crash)的时候,操做系统会将这个进程当时的内存信息转储(dump)到磁盘上1。产生的文件就是core文件了,通常会以core.xxx形式命名。程序员
发生doredump通常都是在进程收到某个信号的时候,Linux上如今大概有60多个信号,可使用 kill -l 命令所有列出来。shell
sagi@sagi-laptop:~$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
针对特定的信号,应用程序能够写对应的信号处理函数。若是不指定,则采起默认的处理方式, 默认处理是coredump的信号以下:数组
3)SIGQUIT 4)SIGILL 6)SIGABRT 8)SIGFPE 11)SIGSEGV 7)SIGBUS 31)SIGSYS 5)SIGTRAP 24)SIGXCPU 25)SIGXFSZ 29)SIGIOT
咱们看到SIGSEGV在其中,通常数组越界或是访问空指针都会产生这个信号。另外虽然默认是这样的,可是你也能够写本身的信号处理函数改变默认行为,更多信号相关能够看参考连接33。bash
上述内容只是产生coredump的必要条件,而非充分条件。要产生core文件还依赖于程序运行的shell,能够经过ulimit -a命令查看,输出内容大体以下:函数
sagi@sagi-laptop:~$ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 20 file size (blocks, -f) unlimited pending signals (-i) 16382 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) unlimited virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
看到第一行了吧,core file size,这个值用来限制产生的core文件大小,超过这个值就不会保存了。我这里输出是0,也就是不会保存core文件,即便产生了,也保存不下来==! 要改变这个设置,可使用ulimit -c unlimited。fetch
OK, 如今万事具有,只缺一个能产生Core的程序了,介个对C程序员来讲太容易了。spa
#include <stdio.h>; #include <stdlib.h>; int crash() { char *xxx = "crash!!"; xxx[1] = 'D'; // 写只读存储区! return 2; } int foo() { return crash(); } int main() { return foo(); }
上手调试操作系统
上边的程序编译的时候有一点须要注意,须要带上参数-g, 这样生成的可执行程序中会带上足够的调试信息。编译运行以后你就应该能看见期待已久的“Segment Fault(core dumped)”或是“段错误 (核心已转储)”之类的字眼了。看看当前目录下是否是有个core或是core.xxx的文件。祭出linux下经典的调试器GDB,首先带着core文 件载入程序:gdb exefile core,这里须要注意的这个core文件必须是exefile产生的,不然符号表会对不上。载入以后大概是这个样子的:
sagi@sagi-laptop:~$ gdb coredump core Core was generated by ./coredump'. Program terminated with signal 11, Segmentation fault. #0 0x080483a7 in crash () at coredump.c:8 8 xxx[1] = 'D'; (gdb)
咱们看到已经能直接定位到出core的地方了,在第8行写了一个只读的内存区域致使触发Segment Fault信号。使用where命令,可知道出问题的代码是如何被调用的。
好比:在查看larbin运行过程当中出现segmentation fault的时候,查看其core文件,发现是site.cc中的调用的newId()函数中的strcpy()这一行出了问题。使用where命令后,可知,通过main() -> fetchDns() -> NamedSite::newQuery() -> newId的过程,larbin程序出错啦~~
上边的程序比较简单,不须要另外的操做就能直接找到问题所在。现实却不是这样的,经常须要进行单步跟踪,设置断点之类的操做才能顺利定位问题。下边列出了GDB一些经常使用的操做。
bt这个命令重点推荐,尤为是当函数嵌套很深,调用关系复杂的时候,他可以显示出整个函数的调用堆栈,调用关系一目了然。另外上边有两个单步执行的命令,一个是n,一个是s。主要区别是n会将函数调用当成一步执行,而s会跟进调用函数内部。