Core dump
core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump. (linux中如果内存越界会收到SIGSEGV信号,然后就会core dump)
在程序运行的过程中,有的时候我们会遇到Segment fault(段错误)这样的错误。这种看起来比较困难,因为没有任何的栈、trace信息输出。该种类型的错误往往与指针操作相关。往往可以通过这样的方式进行定位。
配置操作系统产生core文件
ulimit -c 或者 ulimit -a查看core file文件大小的配置情况
比如我在自己的Ubuntu系统随便打开一个终端
pc@mypc:~$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 62923
max locked memory (kbytes, -l) 65536
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) 62923
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
此时“core file size ”大小为0,说明终端没有打开core dump,解决方法:
ulimit -c unlimited(只对当前终端进程有效)
或在~/.bashrc 的最后加入: ulimit -c unlimited (一劳永逸)
使用gdb查看core文件
在发生了core dump之后,如何使用gdb查看core文件内容,以定位文件中引发core dump的行呢? 我们通过以下“test_gdb.cpp”代码说明,该代码中有一个很明显的数组越界错误
#include <iostream>
void fun(){
char v[10];
for(int i = 0; i <= 10; i++){
v[i] = i;
}
}
int main() {
fun();
return 0;
}
编译并运行程序
pc@mypc:~$ g++ -g main.cpp -o a.out
pc@mypc:~$ ./a.out
段错误 (核心已转储)
意料之中,运行该代码的时候发生了段错误,系统捕捉这一错误并在终端所在文件夹里生成了core文件。接下来在同一个终端里输入:
- gdb [exec file] [core file] 命令行格式打开gdb和生成的core文件
pc@mypc:~$ gdb ./a.out core
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test_gdb...done.
[New LWP 31499]
Core was generated by `./test_gdb'.
Program terminated with signal SIGABRT, Aborted.
51 ../sysdeps/unix/sysv/linux/raise.c: 没有那个文件或目录.
gdb的提示信息告诉我们错误发生在"…/sysdeps/unix/sysv/linux/raise.c:51"位置上,错误原因是"…/sysdeps/unix/sysv/linux/raise.c: 没有那个文件或目录.",这是由于数组越界发生的系统内部错误,我们不用管它。直接回溯(backtrace)错误发生的位置:
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007f7ad2fa1921 in __GI_abort () at abort.c:79
#2 0x00007f7ad2fea967 in __libc_message (action=action@entry=do_abort,
fmt=fmt@entry=0x7f7ad31178fb "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:181
#3 0x00007f7ad3095b61 in __GI___fortify_fail_abort (need_backtrace=need_backtrace@entry=false,
msg=msg@entry=0x7f7ad31178d9 "stack smashing detected") at fortify_fail.c:33
#4 0x00007f7ad3095b22 in __stack_chk_fail () at stack_chk_fail.c:29
#5 0x0000559718536977 in fun () at /home/gao/Cpp_Projects/test_gdb/main.cpp:8
#6 0x0000559718536994 in main () at /home/gao/Cpp_Projects/test_gdb/main.cpp:14
gdb提示中每一条消息前边都有一个编号,其中很多都是系统内部函数的调用错误,但是我们只关心自己代码里边的问题。于是我们可以输入以下命令进行更进一步的调试:
- frame [number] 单独查看某函数中的错误。
- list 查看错误位置附近的代码
- info locals 查看错误函数中的局部变量
- print [var_name] 或 p [var_name] 查看单独某一个变量的值
(gdb) frame 5
8 }
(gdb) list
3 void fun(){
4 char v[10];
5 for(int i = 0; i <= 10; i++){
6 v[i] = i;
7 }
8 }
9
10 int main() {
11 int a,b;
12 a = 0;
(gdb) info locals
v = "\000\001\002\003\004\005\006\a\b\t"
(gdb) print v
$1 = "\000\001\002\003\004\005\006\a\b\t"
通过该gdb+core dump file的方法就可以大概定位到错误发生的位置了。
|