如何用GDB调试核心转储文件
这种情况一般是数组越界访问、空指针或野指针读写造成的。如果程序很小,就比较好处理,仔细检查源代码就能解决。但是对于一个代码量很大的程序来说,其中包含n个多功能调用和n个多数组指针访问,此时定位问题就不是很容易了(此时牛还是可以通过在适当的位置键入printf和二分搜索法来快速定位问题:P)。如果你懒,我们就从GDB开始吧。什么是核心转储文件?偶尔能听到一个程序员抱怨“妈的,又出核心了!”。简单来说,核心转储是指操作系统执行的一个动作。当一个进程由于某种原因意外崩溃时,操作系统会将该进程的内存信息转储到当时的磁盘上。生成的文件是核心文件,通常以core.xxx的形式命名如何生成核心转储doredump通常发生在一个进程收到某个信号的时候。现在Linux上大约有60个信号,可以用kill -l命令列出来。sagi @ sagi-laptop:~ $ kill-l 1)SIGHUP 2)SIGINT 3)SIGQUIT 4)SIGILL 5)SIGTRAP 6)siga BRT 7)SIG bus 8)SIGFPE 9)SIG kill 1 11)SIGSEGV 12)SIG usr 2 13)SIG pipe 14) 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-655 如果未指定,将采用默认的处理方法。默认的信号处理如下:3)SIG quit 4)sigill 6)sigabrt 8)sigfpe 11)SIGSEGV 7)SIG bus 31)sigsys 5)SIG trap 24)sigxcpu 25)sigxfsz 29)sigiot我们在里面看到sigsegv。此外,虽然这是默认的,但您也可以编写自己的信号处理函数来更改默认行为。欲了解更多信号相关性,请参考链接33。以上内容只是产生coredump的必要条件,而不是充分条件。核心文件的生成还取决于程序运行的shell,可以通过ulimit -a命令查看。输出内容大致如下:sagi @ sagi-laptop: ~ $ ulimit-a核心文件大小(块数,-c) 0dataseg大小(千字节,-d)无限制调度优先级(-e) 20文件大小(块数,-f)无限制挂起信号(-i) 16382最大锁定内存(千字节,-l) 64最大内存大小(千字节,-m)无限制打开文件(-n) 1024管道大小(512字节,-p) 8 -t)无限制最大用户进程(-u)无限制虚拟内存(kbytes,-v)无限制文件锁(-x)无限制参见第一行,核心文件大小,该值用于限制生成的核心文件大小,超过该值不会保存。 我这里的输出是0,这意味着核心文件不会被保存。即使生成了也不能保存= =!要更改此设置,可以使用ulimit -c unlimited。好了,现在一切都准备好了,除了一个可以生成Core的程序。C程序员介绍起来太容易了。#包含;#包含;int crash() { char *xxx = "crash!!";XXX[1]= ' D ';//写只读存储区!return 2;} int foo(){ return crash();} int main(){ return foo();}调试上述程序编译时有一点需要注意。你需要带参数-g,这样生成的可执行程序会带足够的调试信息。编译运行后,应该能看到期待已久的类似“段故障(堆芯)”或“段错误(堆芯)”的字样。查看当前目录下是否有core或core.xxx文件。要在linux下呈现经典的调试器GDB,首先加载带有核心文件的程序:gdb exefile core。需要注意的是,这个核心文件必须由EXFILE生成,否则符号表不匹配。加载后是这样的:sagi @ sagi-laptop:~ $ gdb core dump core generated by。/coredump。程序终止,信号11,分段故障。# 0 0x 080483 a7 in crash()at core dump . c:8 8 XXX[1]= ' D ';(gdb)我们可以看到,可以直接定位到核心之外的地方,在第8行写一个只读存储区,导致触发段故障信号。加载核心时有一个技巧。如果你事先不知道这个核心文件是由哪个程序生成的,你可以随便找个替换,比如/usr/bin/w就是个不错的选择。比如我们用这个方法加载上面生成的core,gdb会有类似的输出:sagi @ sagi-laptop:~ $ gdb/usr/bin/w core是由。/coredump。程序终止,信号11,分段故障。# 0 0x008483 A7 in?()(gdb)你可以看到GDB提示你哪个程序生成了这个内核。上面GDB常见操作的程序比较简单,不需要额外的操作就可以直接发现问题。但现实中并非如此,往往需要进行单步跟踪,设置断点才能成功定位问题。下面列出了GDB的一些常见操作。启动程序:运行
设置断点:b行号|函数名
删除断点:删除断点号
禁用断点:禁用断点号
启用断点:启用断点号。
一步跟踪:next也可以缩写为n
单步跟踪:step也可以缩写为s
打印变量:打印变量名称
设置变量:设置变量=值。
视图变量类型:ptype var
顺序执行到结束:续
顺序执行到某一行:util lineno打印堆栈信息:bt