gdb查看崩溃时的调用堆栈

使用gdb启动程序

1
gdb <可执行文件名>

启动后执行运行命令run可以简写为r

程序就会从入口开始运行,也可以带上命令行参数运行run [参数1] [参数2] ...

参看当前函数调用堆栈

1
backtrace

可以简写为bt,在程序崩溃后查看当前崩溃的位置和调用堆栈,这估计是gdb最常用的命令。

GDB常用的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
i b  // info breakpoint
b 10 // set breakpoint at line 10
b main.cpp:10 // set breakpoint at line 10 in file main.cpp
b func // set breakpoint at function "func"
b A::A // 设置成员函数的断点
b func(int) // 设置函数断点时指定函数类型,以便在有重载时区分
c // continue
s // 单步执行并在函数调用时进入函数 step in
n // 但不是执行并在函数调用时不进入函数而当成一步完成 step over
finish // 执行完当前函数跳到上层调用处 step out
p x // print the value of x
i ar // info args 查看函数参数的值
i lo // info locals 查看所有局部变量的值
bt // backtrace 查看调用栈
f 1 // 设置栈针到level 1,断点停的地方是level 0,level 1就是上一层,根据bt返回的结果设置,切换栈针后再用i ar和i lo查看当前栈针的变量信息
i thr // info thread 查看线程信息
thr 2 // thread 2 切换当前线程到id:2,根据i thr的返回结果设置
q // quit GDB

配置core dump

如果程序不是通过gdb启动运行的我们也想查看它崩溃时的调用堆栈,则可以通过core dump文件,它会保留崩溃时的现场。首先我们确保运行的可执行文件无论是Debug版还是Release版应该携带了调试符号,即编译选项中加入了-g或-ggdb。然后通过下面的方式启用core dump文件生成:

确保apportsystemd-coredump两个服务存在

1
2
dpkg -l | grep apport
dpkg -l | grep systemd-coredump

如果不存在则安装

1
2
apt install apport 
apt install systemd-coredump

如果存在则确保在运行

1
2
systemctl status apport
systemctl status systemd-coredump.socket

如果没有运行则启动

1
2
systemctl start apport
systemctl start systemd-coredump.socket

默认的core dump文件会生成在/var/lib/systemd/coredump/目录下,为了方便调试我们修改到可执行文件同目录

运行程序前在shell窗口或者shell脚本内先执行

1
2
ulimit -c unlimited
echo "core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern

之后运行的程序崩溃时就会在程序启动的“当前目录”生成core dump文件。文件名是core.<可执行文件名>.<进程ID>

使用core dump

所谓使用core dump,就是通过gdb和core dump文件恢复崩溃时的现场,以便查看崩溃时的函数调用堆栈或者变量值。

用法:

1
gdb <可执行文件名> <core dump文件名>

然后就可以使用

1
bt

查看崩溃现场的调用堆栈了。

主动生成运行中进程的core dump

这种需求主要发生在进程卡死,想知道卡在何处时。

1
gcore -o <core dump文件名> <pid>

可以主动生成core dump文件,这个操作不会杀死进程,如果有需要可手动杀死。

然后参照[使用core dump](#使用core dump)的步骤去查看调用堆栈就可以了