Linux

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > Linux > Linux下coredump定位方法

Linux下关于coredump的定位方法说明

作者:凌肖战

这篇文章主要介绍了Linux下关于coredump的定位方法说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一. Linux 下 cordump 机制

Linux 系统下存在一种 coredump 机制。

当程序运行过程中异常终止或崩溃,Linux 操作系统会将程序当时的堆栈等内存状态信息记录下来,会在指定文件下生成一个 coredump 相关的 Log 文件。

软件开发人员可以通过对 coredump文件进行分析,即可定位到导致程序运行崩溃的 bug

当程序访问的内存超过了系统给定的内存空间,就会产生 Segmentation fault(core dumped),所以:

一般产生段错误的原因有如下:

二. coredump 文件定位方法

根据上一篇配置 coredump 机制的方法,成功配置好之后。

就可以运行代码,当程序运行中崩溃时即可产生相应的 coredump 文件。

操作如下:

这里为了方便起见,不更改 coredump 文件的生成路径,即生成的 coredump 文件会与可执行程序在同一目录下,文件默认叫 core 的文件。

下面以一段测试代码说明一下,Linux 环境下 使用 gdb 调试器对 coredump 文件进行分析调试。

代码如下:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
int fun()
{
    printf("---fun()\n");
    char buffer[3] = {0}; 
    memcpy(buffer, "Hello", 6);  
    printf("---buffer: %s\n", buffer);  
    return 0;
}
int main()
{
    printf("---main()---\n");   
    int pid = 0;
    pid = getpid();
    printf("pid %d\n", pid);
    fun(); 
    printf("---End main\n");
    return 0;
}

1. 编译运行

操作如下:

编译代码。输入 gcc -g main.c -o main.out 命令

运行程序。输入 ./main.out 命令。

如下所示:

wangtian@wangtian-virtual-machine:~/Code_Learns/C_Learns/debug/debug2$ ./main.out 
---main()---
pid 3814
---fun()
---buffer: Hello
*** stack smashing detected ***: terminated
已放弃 (核心已转储)

当程序出现段错误时崩溃时,可查看程序当前目录下是否生成 coredump 相关文件。

如下所示:

wangtian@wangtian-virtual-machine:~/Code_Learns/C_Learns/debug/debug2$ ls -l
总用量 180
-rw------- 1 wangtian wangtian 393216 12月 13 16:55 core
drwxrwxr-x 2 wangtian wangtian   4096 11月 25 22:24 debug
-rw-rw-r-- 1 wangtian wangtian     90 10月 28 13:32 debug.c
-rw-rw-r-- 1 wangtian wangtian     81 10月 20 18:12 debug.h
-rw-rw-r-- 1 wangtian wangtian   5688 12月 13 16:55 debug.o
-rw-rw-r-- 1 wangtian wangtian    356 12月 13 16:55 main.c
-rw-rw-r-- 1 wangtian wangtian   7144 12月 13 16:55 main.o
-rwxrwxr-x 1 wangtian wangtian  21144 12月 13 16:55 main.out

2. gdb 调试 coredump 文件

查看 coredump 文件。

输入 objdump -t core 命令:

wangtian@wangtian-virtual-machine:~/Code_Learns/C_Learns/debug/debug2$  objdump -t core
core:     文件格式 elf64-x86-64
SYMBOL TABLE:
无符号

可以看到,coredump 文件是不带符号表的。

所以调试时,需要同时加上 可执行程序文件。

输入命令 gdb main.out core 进行调试,如下所示:

wangtian@wangtian-virtual-machine:~/Code_Learns/C_Learns/debug/debug2$ gdb main.out core
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main.out...
[New LWP 4272]
Core was generated by `./main.out'.
Program terminated with signal SIGABRT, Aborted.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50	../sysdeps/unix/sysv/linux/raise.c: 没有那个文件或目录.

可以看到,程序收到 signal SIGABRT 后崩溃了。

输入 bt (backtrace 缩写) 命令,可以查看下程序崩溃时的堆栈信息,

如下所示:

(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ff8d6f5c859 in __GI_abort () at abort.c:79
#2  0x00007ff8d6fc729e in __libc_message (action=action@entry=do_abort, 
    fmt=fmt@entry=0x7ff8d70f108f "*** %s ***: terminated\n")
    at ../sysdeps/posix/libc_fatal.c:155
#3  0x00007ff8d7069aea in __GI___fortify_fail (
    msg=msg@entry=0x7ff8d70f1077 "stack smashing detected") at fortify_fail.c:26
#4  0x00007ff8d7069ab6 in __stack_chk_fail () at stack_chk_fail.c:24
#5  0x000056183642c243 in fun () at main.c:12
#6  0x000056183642c28c in main () at main.c:20

以上的堆栈信息,显示 __stack_chk_fail () 错误。可以看到调用 fun() 函数过程中发生了栈问题。

__stack_chk_fail () 打印信息说明发生了缓冲区溢出,即数组越界问题。

从这段栈信息中并不能直观的定位到出现问题的地方,因为出现问题的地方是之前的数组越界,但是这里的栈信息已经执行到主函数 main中, 特别是在大项目中更是无法准确的定位出错的地方。

越界写坏内存,什么时候会 crash 取决于我们写坏的内存什么时候被用到,有时候会离犯罪现场特别远。所以,导致定位这样情况的崩溃问题比较麻烦。

在发生__stack_chk_fail () 错误的附近函数 fun() 中第11 行打断点,如下所示:

(gdb) b main.c:11
Breakpoint 1 at 0x56183642c22a: file main.c, line 11.
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000056183642c22a in fun at main.c:11
(gdb) r
Starting program: /home/wangtian/Code_Learns/C_Learns/debug/debug2/main.out 
---main()---
pid 3868
---fun()
---buffer: Hello
Breakpoint 1, fun () at main.c:11
11	    return 0;
(gdb) n
12	}
(gdb) 
*** stack smashing detected ***: terminated
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50	../sysdeps/unix/sysv/linux/raise.c: 没有那个文件或目录.
(gdb) 

初步可以定位到,是在函数 fun() 内部发生了数组越界问题。目前还不能定位到具体某一行。

canary 栈溢出保护机制的具体原理:

总结

以上一系列的操作,说明通过 gdb 对 数据越界问题的调试定位,这种方法不是太好用。

原因:越界写坏内存,什么时候会 crash 取决于我们写坏的内存什么时候被用到,有时候会离犯罪现场特别远。所以,导致定位这样情况的崩溃问题比较麻烦。后续文章再针对数组越界问题定位方法进行新的总结。

好了,以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文