1. 内核转储作用 (1) 内核转储的最大好处是能够保存问题发生时的状态。 (2) 只要有可执行文件和内核转储,就可以知道进程当时的状态。 (3) 只要获取内核转储,那么即使没有复现环境,也能调试。 2. 启用内核转储 1.1 查看内核转储是否有效 在终端中输入以下命令,查看内核转储是否有效。 #ulimit -c 0 -c 表示内核转储文件的大小限制,现在显示为零,表示不能用。 可以改为1G #ulimit -c 1073741824 也可以改为无限制 #ulimit -c unlimited 2.2 测试一个例子 例子的源代码: #include <stdio.h> int main(void) { int *a = NULL; *a = 0x1; return 0; } 把以上源代码,写成一个a.c文件后,编译a.c文件产生一个a.out的可执行文件: #gcc -g a.c -o a.out 修改a.out文件的权限后,执行它: #./a.out 就会显示: Segmentation fault(core dump) 这表示在当前目录下, 已经生成了a.out对应的内核转储文件。 注意:后面带有(core dump), 才说明转储文件成功生成了。 #file core* core:ELF 64-bit LSB core file x86-64, version 1(SYSV), SVR4-style, from './a.out' coreDump: UTF-8 Unicode C program text 要用GDB调试内核转储文件,应该使用以下方式启动GDB: #gdb -c ./*.core ./a.out GNU gdb (GDB) 7.1-Ubuntu ... Core was generated by './a.out'. Program terminated with signal 11, Segmentation fault. #0 0x00000000004004dc in main() at a.c:6 6 *a =0x1; a.c的第6行收到了11号信号。用GDB的list命令可以查看附近的源代码。 (gdb) l 5 1
2 3
4
5
6
7
8
这里默认都是当前目录,也可以给core 和a.out 指定路径 到这里测试完成! 2.3 永久生效的办法 上面所述的方法,只是在当前shell中生效,重启之后,就不再有效了。永久生效的办法是: #vi /etc/profile 然后,在profile中添加: ulimit -c 1073741824 或者 ulimit -c unlimited 这样重启机器后生效了。 或者, 使用source命令使之马上生效。 #source /etc/profile 3. 指定内核转储的文件名和目录 缺省情况下,内核在coredump时所产生的core文件放在与该程序相同的目录中,并且文件名固定为core。很显然,如果有多个程序产生core文件,或者同一个程序多次崩溃,就会重复覆盖同一个core文件。 我们可以通过修改kernel的参数,指定内核转储所生成的core文件的路径和文件名。 可以通过在/etc/sysctl.conf文件中,对sysctl变量kernel.core_pattern的设置。 #vi /etc/sysctl.conf 然后,在sysctl.conf文件中添加下面两句话: kernel.core_pattern = /var/core/core_%e_%p kernel.core_uses_pid = 0 保存后退出。 需要说明的是, 这里%e, %p分别表示: %c 转储文件的大小上限 %e 所dump的文件名 %g 所dump的进程的实际组ID %h 主机名 %p 所dump的进程PID %s 导致本次coredump的信号 %t 转储时刻(由1970年1月1日起计的秒数) %u 所dump进程的实际用户ID 可以使用以下命令,使修改结果马上生效。 #sysctl –p /etc/sysctl.conf 请在/var目录下先建立core文件夹,然后执行a.out程序,就会在/var/core/下产生以指定格式命名的内核转储文件。查看转储文件的情况: #ls /var/core core_a.out_2834 4. 手动强制某个进程产生core dump的方法(尝试) 当某些程序发生crash时,对应进程会产生coredump文件。通过这个coredump文件,开发人员可以找到bug的原因。但是coredump的产生,大都是因为程序crash了。 而有些bug是不会导致程序crash的,比如死锁,这时程序已经不正常了,可是却没有coredump产生。如果环境又不允许gdb调试,难道我们就束手无策了吗? 针对以上这种情况,一般情况下,对于这样的进程可以利用watchdog监控它们,当发现这些进程很长时间没有更新其heartbeat时,可以给这些进程发送可以导致其产生coredump的信号。根据linux的信号默认的处理行为,SIGQUIT,SIGABRT, SIGFPE和SIGSEGV都可以让该进程产生coredump文件。这样我们可以通过coredump来得知死锁是否发生。 当然, 如果进程添加了这些信号的处理函数,那么就不会产生coredump了。不过,对于SIGQUIT, SIGABRT, SIGFPE, SIGSEGV,有谁会为它们加上信号处理函数呢。 还有一种情况,进程并没有死锁或者block在某个位置,但是我们需要在某个指定位置进行调试,获取某些变量或者其它信息。但是,有可能是客户环境或者生产环境,不允许我们进行长时间的检测。那么,我们就需要通过coredump来获得进程在运行到该点时的快照。 这个时候,可以利用gdb来手工产生coredump。在attach上这个进程时,在指定位置打上断点,当断点触发时,使用gdb的命令gcore,可以立即产生一个coredump。 这样,我们就拿到了这个位置的进程快照。 1.寻找您要发送信号的进程ID, # ps
-ef root 得出 qemu-system-x86的 PID号是3207 2.使用kill(1)去发送信号。 # /bin/kill -s QUIT 3207 发送其他的信号也很相似, 只要在命令行中替换QUIT 为ABRT,TERM 或 KILL 就行了 重要提示: 5 使用core dump进行调试 在Linux下遇到“段错误”(segmentation fault),如果段错误发生在服务器端,而服务器端要继续工作,不允许调试,这时“内核转储(core dump)”就派上了用场,可以把生成的内核转储复制到本地进行调试。 具体方法如下: 方法一: 输入命令 #gdb <程序可执行文件> <coredump转储文件> 例如: # gdb
/usr/local/bin/qemu-system-x86_64 然后,在(gdb)提示符后输入
l, 方法二: (1) 在终端输入命令# gdb [-c] <coredump文件>, 例如: gdb -c /var/core/core-3207-qemu-system-x86 (2)然后,在(gdb)提示符后输入file <可执行程序> 例如:(gdb)
file (3) 这时就可以用backtrace/thread等命令查看当时的错误了,就像程序在本地执行到崩溃点一样 或者用where回车, 也可以显示程序在哪一行当掉的 5. 启用整个系统的内核转储 (未完待续......) (4.1) 编辑/etc/profile, 开启登录到系统的所有用户的内核转储功能 首先,看看用的是个什么机器: # uname –a Linux ubuntu240 2.6.32-21-server #32-Ubuntu SMP Fri Apr 16 09:17:34 UTC 2010 x86_64 GNU/Linux 其次,再查看一些默认参数,若core file size是0,即使程序出错时,也不会产生core文件。 # ulimit -a core file
size data seg
size scheduling
priority file
size pending
signals max locked
memory max memory
size open
files pipe
size POSIX message
queues real-time
priority stack
size cpu
time max user
processes virtual
memory file
locks |
|