avatar

目录
core dump文件分析与调试

什么是 core dump

对于程序,由于各种异常或者 bug,导致在运行过程中,并且在满足一定条件下,产生一个叫做 core 的文件。

通常情况下,core 文件会包含程序运行时的:

  • 内存
  • 寄存器状态
  • 堆栈指针
  • 内存管理信息
  • 各种函数调用堆栈信息等

许多程序出错的时候,会产生一个 core 文件。通过工具分析这个文件,我们可以定位到,程序异常退出的时候对应的堆栈调用等信息。

开启 core dump

bash
1
ulimit -c unlimited

生成 core dump 文件

看一段有问题的代码:

c
1
2
3
4
5
6
7
8
#include<stdio.h>

int main(){
int *p=NULL;
*p=0;
puts("error");
return 0;
}

给空指针赋值

linux下编译和执行:

bash
1
2
3
4
5
6
7
8
13:13 taqini@qm /tmp/a
% gcc a.c -o test -no-pie -g
13:14 taqini@qm /tmp/a
% ./test
[1] 23405 segmentation fault (core dumped) ./test
13:14 taqini@qm /tmp/a
% ls
a.c core test

执行编译后的程序会产生 core dump文件。

调试 core dump

dmesg

  • dmesg 用于检测和控制内核缓冲。程序用来帮助用户,了解系统的启动信息,可以获得出错堆栈地址。

  • addr2line 可以将指令的地址和可执行映像转换成文件名,函数名或源代码的工具。

    这种功能将跟踪地址转换成更有意义的内容来说很有用。
    在调用 addr2line 工具时,要使用 -e 选项来指定可执行映像,使用 -f 选项可以告诉工具输出函数名。

bash
1
2
3
4
5
6
13:18 taqini@qm /tmp/a
% sudo dmesg| grep test
[ 5391.121950] test[23973]: segfault at 0 ip 000000000040114e sp 00007ffd215c5ee0 error 6 in test[401000+1000]
13:18 taqini@qm /tmp/a
% addr2line -e test 000000000040114e
/tmp/a/a.c:5

先通过dmesg找到对应出错的地址,再用 addr2line -e 将地址解析到对应的代码行。

addr2line命令只对有调试信息且没开pie的程序管用,现在大部分程序都开了地址随机化,且没有调试信息

gdb

直接gdb a.out core即可,常用命令:

  • bt :查看堆栈信息(调用链)
  • i locals :查看当前程序栈的局部变量
  • i args :查看当前程序栈的参数
  • i r :查看当前寄存器的值

源代码:

c
1
2
3
4
5
6
7
8
9
10
11
12
13
// gcc a.c -fno-stack-protector
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main(){
setvbuf(stdin,0,2,0);
setvbuf(stdout,0,2,0);
char buf[32];
printf("%p\n",printf);
scanf("%s",buf);
printf("%s",buf);
}

存在缓冲区溢出

编译、运行、溢出缓冲区:

bash
1
2
3
4
5
6
7
8
9
10
11
12
13:47 taqini@qm /tmp/b
% gcc a.c -fno-stack-protector
13:47 taqini@qm /tmp/b
% cyclic 128 | ./a.out
0x7fcb1b1efd90
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaab[1] 30098 done cyclic 128 |
30099 segmentation fault (core dumped) ./a.out
13:47 taqini@qm /tmp/b
% ls
a.c a.out core
13:47 taqini@qm /tmp/b
% gdb a.out core

直接用gdb调试,加载core文件,可以对溢出点进行快速定位:

32 - rbp
40 - ret address

strace

strace 是一个集诊断、调试、统计与一体的工具,我们可以使用strace,对应用的系统调用和信号传递的跟踪结果,来对应用进行分析,以达到解决问题,或者是了解应用工作过程的目的。

strace 的简单的用法就是,执行一个指定的命令,在指定的命令结束之后,它也就退出了。
在命令执行的过程中,strace 会记录和解析命令进程的所有系统调用,以及这个进程所接收到的,所有的信号值。

-c ,统计每一系统调用的所执行的时间,次数和出错的次数等
-p ,指定进程pid
-i ,输出系统调用的入口指针

-c 还挺好玩儿,(有点插桩的感觉了)

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
20:17 taqini@qm /tmp/b
% strace -c ./a.out
0x7fbe17220d90
2333333
2333333
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0.00 0.000000 0 9 read
0.00 0.000000 0 2 write
0.00 0.000000 0 2 close
0.00 0.000000 0 2 fstat
0.00 0.000000 0 8 mmap
0.00 0.000000 0 4 mprotect
0.00 0.000000 0 1 munmap
0.00 0.000000 0 1 brk
0.00 0.000000 0 4 pread64
0.00 0.000000 0 1 1 access
0.00 0.000000 0 1 execve
0.00 0.000000 0 2 1 arch_prctl
0.00 0.000000 0 2 openat
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 39 2 total

还是上面的例子,生成48个字节数据溢出缓冲区:

bash
1
2
20:12 taqini@qm /tmp/b
% cyclic 48 | strace -i ./a.out

使用strace跟踪程序流:

文章作者: TaQini
文章链接: http://taqini.space/2021/10/02/how-to-debug-core-dump/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 TaQini
打赏
  • Wechat
    Wechat
  • Alipay
    Alipay

评论