bt
# or (exact same command)
where
# OR (for even more details, such as seeing all arguments to the functions--
# thanks to Peter Cordes in the comments below)
bt full
# For gdb help and details, see:
help bt
# or
help where
Core was generated by `sleep 30'.
Program terminated with signal SIGQUIT, Quit.
#0 0x00007f93ed32d334 in ?? ()
(gdb)
运行bt或where查看回溯。你会看到这个:
(gdb) bt
#0 0x00007f93ed32d334 in ?? ()
#1 0x000000000000000a in ?? ()
#2 0x00007f93ed2960a5 in ?? ()
#3 0x0000000000000000 in ?? ()
(gdb)
这些是调用堆栈上调用的函数的地址。如果您打开了调试符号,您会看到更多信息,包括函数名称和行号,如下所示(从我的 C 程序中提取):
#10 0x00007fc1152b8ebf in __printf (format=<optimized out>) at printf.c:33
#11 0x0000562bca17b3eb in fast_malloc (num_bytes=1024) at src/fast_malloc.c:225
#12 0x0000562bca17bb66 in malloc (num_bytes=1024) at src/fast_malloc.c:496
如上所述,您应该已经编译了带有调试符号并使用优化级别 0 的程序,使用-ggdb -O0. 请参阅上面的 C 和 C++ 中的完整示例构建和运行命令。
现在在 gdb 中运行程序:
# Open the executable in gdb
gdb path/to/my/executable
# Run it (if it's still crashing, you'll see it crash)
r
# View the backtrace (call stack)
bt
# Quit when done
q
set logging file gdb_log.txt
set logging on
set trace-commands on
show logging # prove logging is on
flush
set pretty print on
bt # view the backtrace
set logging off
show logging # prove logging is back off
在 Ubuntu 20.04 中测试。
1.启用核心文件
首先,运行
ulimit -c
以查看系统上核心文件的最大允许大小。在我的 Ubuntu 20.04 上,我的返回0
,这意味着无法创建核心文件。ulimit --help
显示 的含义-c
:因此,将允许的核心文件大小设置为
unlimited
,如下所示。请注意,我认为这仅适用于您在其中运行它的一个终端,并且我认为它不会在重新启动后持续存在,因此您必须在每次想要创建核心文件时运行它,并且在每个终端中运行它工作:而已!现在,运行您的程序,如果它崩溃并执行“核心转储”,它会将核心作为
core
文件转储到您调用可执行文件时所在的同一目录中。该文件的名称只是“核心”。2.查看gdb中的回溯
为了在核心文件中看到有用的信息,您应该已经构建了带有调试符号的 C 或 C++ 程序。如果没有调试符号,您只能看到被调用函数的地址,而不是实际名称或行号。
在 gcc 中,用于
-ggdb -O0
打开为NU e uggerg
优化的 debu 符号。您也可以使用,等,但最好。我们真的需要优化级别 0 ( ) 吗?是的,是的,我们这样做。在这里查看我的答案:堆栈溢出:编译器的选项和选项之间有什么区别?gdb
G
d
b
-g -O0
-g3 -O0
-ggdb -O0
-O0
-O0
-Og
C 和 C++ 中的构建和运行命令示例:因此,您在 C 或 C++ 中的完整构建和运行命令可能如下所示:
像这样打开核心文件
gdb
:假设您刚刚运行
path/to/my/executable
,那么该core
文件将位于您转储核心时所在的同一目录中,因此您可以运行以下命令:在
gdb
中,查看回溯(崩溃时的函数调用堆栈):重要提示:发生核心转储时,它不会自动用新文件覆盖
core
当前目录中的任何预先存在的文件,因此您必须在程序崩溃时手动删除旧core
文件并rm core
生成新的核心文件,以便始终拥有最新的核心文件进行分析。3. 试试看
sleep 30
以启动一个休眠 30 秒的进程。core
在您所在的目录中看到一个文件。gdb -c core
以打开刚刚由强制崩溃创建的核心文件。sleep 30
请注意,当核心转储发生时, 它知道您调用了 ( ) 的命令:bt
或where
查看回溯。你会看到这个:4.忘掉core文件,直接在gdb中运行程序到崩溃点!
正如@Peter Cordes 在下面的评论中所说,您也可以直接在 gdb 中运行程序,让它在那里崩溃,因此您无需在事后打开核心文件!他说:
如上所述,您应该已经编译了带有调试符号并使用优化级别 0 的程序,使用
-ggdb -O0
. 请参阅上面的 C 和 C++ 中的完整示例构建和运行命令。现在在 gdb 中运行程序:
如果您需要手动将回溯记录到日志文件以供以后分析,您可以这样做(改编自我的eRCaGuy_dotfiles 存储库中的注释):
完毕!您现在已将 gdb 回溯保存在文件“gdb_log.txt”中。
参考:
-O0
-Og
额外阅读要做
LD_PRELOAD
:gdb
https: //stackoverflow.com/questions/10448254/how-to-use-gdb-with-ld-preload通过搜索找到。我正在运行 Ubuntu Mate 21.10。对于那些运行较晚型号 Ubuntu 的用户,
apport
将在/var/lib/apport/coredump
.如果找不到核心转储文件,
cat /var/log/apport.log
. 当我这样做时,我看到:注意核心限制 0,这意味着不会生成核心转储文件。所以,我运行了这篇文章 (
ulimit -c unlimited
) 中显示的命令,这次apport.log
显示的是:我在当前目录或包含可执行文件的目录中找不到这个,所以我在整个系统上进行了查找,并在
/var/lib/apport/coredump
.