本文简单介绍core文件与gdb调试core文件的方法
概要:
1. core 文件
2. 配置core程序崩溃时产生文件
3. 可修改core文件名
4. 产生core文件的情形
5. gdb调试core文件
a) gdb -c <xxx.core> [可执行程序]
b) gdb命令:backtrace / bt
c) gdb命令:up/down/frame
d) gdb命令:info locals
e) gdb命令:info args
f) gdb命令:print <变量名> / print *<变量名>
1. core 文件
linux/unix下,可执行程序崩溃时会产生core文件。core文件是内存映象,可用于调试程序找出程序崩溃的原因。
2. 配置core程序崩溃时产生文件
linux/unix下,通过limit -a,可以查看系统是否对可程序的崩溃生成core文件。其中core file size 便是指产生core文件的大小。下面是freebsd系统中输出limit -a 输出的一行,unlimited表示不限制,如果 unlimited 为 1024,则表示产生core文件最大为 1024块,每块大小为512字节。如果为0,则表示不产生core文件。
core file size (512-blocks, -c) unlimited
core file size (512-blocks, -c) 1024
core file size (512-blocks, -c) 0
通过limit命令,可以改变设置。如 ulimit -c unlimited 或 limit -c 1024等。
3. 可修改core文件名
core文件产生于程序的工作目录,不通系统命名不一样 freebsd 下,默认命名为 程序名.core ,这个名称是可以修改的。freebsd下,通过 man core 可以知道,通过sysctl可以查看core文件名的规则和对其进行修改。下面是指core文件名组成是 程序名.core。
root@freebsd:/ # sysctl -a | grep corefile
kern.corefile: %N.core
freebsd下查看 man core,可以知道core文件命名时可用的规则:
The name of the file is controlled via the sysctl(8) variable
kern.corefile. The contents of this variable describes a filename to
store the core image to. This filename can be absolute, or relative
(which will resolve to the current working directory of the program gen-
erating it).
The following format specifiers may be used in the kern.corefile sysctl
to insert additional information into the resulting core file name:
%H Machine hostname.
%I An index starting at zero until the sysctl debug.ncores
is reached. This can be useful for limiting the number
of corefiles generated by a particular process.
%N process name.
%P processes PID.
%U process UID.
4. 产生core文件的情形
程序在运行时,发生致命错误导致程序崩溃,会产生core文件。当系统捕获到一些信号如 SIGSEGV 等信号,就会生产core文件。
通过man signal,可以查看到什么信息会产生core:
Num Name Default Action Description
1 SIGHUP terminate process terminal line hangup
2 SIGINT terminate process interrupt program
3 SIGQUIT create core image quit program
4 SIGILL create core image illegal instruction
5 SIGTRAP create core image trace trap
6 SIGABRT create core image abort program (formerly SIGIOT)
7 SIGEMT create core image emulate instruction executed
8 SIGFPE create core image floating-point exception
9 SIGKILL terminate process kill program
10 SIGBUS create core image bus error
11 SIGSEGV create core image segmentation violation
12 SIGSYS create core image non-existent system call invoked
最常见的程序崩溃的原因便是 SIGSEGV(非法访问内存)。
5. gdb调试core文件
1) 程序在编码时,加上 -g 选项来增加调试信息。
2) 用gdb对core文件进行调试,查看程序运行状态。
下面列举一些常用的命令:
a) gdb -c <xxx.core> [可执行程序]
运行gdb,调度core文件。如下面是我的可执行程序所在的目录:
root@freebsd:~/test/core_statck # ls
core_stack core_stack.core core_stack.cpp
core_stack.cpp 源文件
core_stack 由源文件编译出来的可执行程序
core_stack.core core_stack产生的core文件
输入命令后,gdb就会运行并输出很多信息,这些信息基本上是加载库的信息。最后还会输出最后一个stack中的信息。此时gdb是处于第0栈状态。
root@freebsd:~/test/core_statck # gdb -c core_stack.core core_stack
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 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-marcel-freebsd"...
Core was generated by `core_stack'.
Program terminated with signal 6, Aborted.
Reading symbols from /usr/lib/libc++.so.1...done.
Loaded symbols for /usr/lib/libc++.so.1
Reading symbols from /lib/libcxxrt.so.1...done.
Loaded symbols for /lib/libcxxrt.so.1
Reading symbols from /lib/libm.so.5...done.
Loaded symbols for /lib/libm.so.5
Reading symbols from /lib/libgcc_s.so.1...done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /lib/libc.so.7...done.
Loaded symbols for /lib/libc.so.7
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
#0 0x2829a467 in kill () from /lib/libc.so.7
(gdb)
b) gdb命令:backtrace / bt
gdb命令 bt 可以输出程序崩溃前栈上的信息,主要是程序的调用栈。
(gdb) bt
#0 0x2829a467 in kill () from /lib/libc.so.7
#1 0x2829a3f7 in raise () from /lib/libc.so.7
#2 0x28298b06 in abort () from /lib/libc.so.7
#3 0x282797f8 in __assert () from /lib/libc.so.7
#4 0x08049de0 in MyDump::print (this=0xbfbfecd8, x=4, core=false) at core_stack.cpp:13
#5 0x080491bd in MyDump::detaildump (this=0xbfbfecd8, a=111, b=222) at core_stack.cpp:35
#6 0x08049166 in MyDump::dump (this=0xbfbfecd8, level=0, a=111, b=222) at core_stack.cpp:30
#7 0x08049140 in MyDump::dump (this=0xbfbfecd8, level=1, a=111, b=222) at core_stack.cpp:28
#8 0x08049140 in MyDump::dump (this=0xbfbfecd8, level=2, a=111, b=222) at core_stack.cpp:28
#9 0x08049140 in MyDump::dump (this=0xbfbfecd8, level=3, a=111, b=222) at core_stack.cpp:28
#10 0x0804928f in main () at core_stack.cpp:46
由上面输出可以看出,程序的调用情况,同时还会输出源文件中对应的行号。
c) gdb命令:up/down/frame
up: 进行上一栈
down: 进入下一栈
frame N: 进行第N栈
这三个命令主要是用户切换gdb当前所处于的栈。gdb处理某一栈的状态时,便可以通过info,print等命令来查看栈中的信息。
d) gdb命令:info locals
查看局部变量,一个很有用的命令。下面可以看到,函数内有一个局部变量lev,值为2
(gdb) info locals
lev = 2
e) gdb命令:info args
查看函数参数,一个很有用的命令。下面可以看到函数的入参有 this, level, a, b 以及它们的值。
(gdb) info args
this = (MyDump *) 0xbfbfecd8
level = 2
a = 111
b = 222
f) gdb命令:print <变量名> / print *<变量名>
查看变量值和指针所指变量的值,一个很有用的命令。print 可以打印当前栈可见的变量,包括局部变量、函数入参、全局变量等。下面是输出this指针的对象,this所指对象有一个成员变量m_n,值为4
(gdb) print *this
$6 = {m_n = 4}
info locals, info args, print 三个命令配合起来,基本上很容易了解到程序core时的当前状态,定位core的原因。
上面的命令,大部分情况都可以定位出程序core的问题了。但是对于复杂的栈情况或是栈中有数据被破坏,这是比较能发查出的。更多的命令和用法,需要查看man gdb 和 gdb 命令 help 来了解。