当前位置: 首页 > 科技观察

在Linux上创建和调试转储文件

时间:2023-03-13 18:56:51 科技观察

崩溃转储、内存转储、核心转储、系统转储......它们都产生相同的产品:一个文件包含应用程序崩溃时、特定时刻文件的内存状态。这是一篇指导文章,您可以通过克隆示例的应用仓库来学习:gitclonehttps://github.com/hANSIc99/core_dump_example。git信号与dump信号的关系是操作系统和用户应用程序之间的进程间通信。Linux使用POSIX标准中定义的信号。在您的系统上,您可以在/usr/include/bits/signum-generic.h中找到标准信号的定义。如果您想了解有关在应用程序中使用信号的更多信息,请参阅信息丰富的信号手册页。简而言之,Linux会根据预期或意外信号触发进一步的活动。当您退出正在运行的应用程序时,该应用程序通常会收到一个SIGTERM信号。因为这种类型的退出信号是预期的,所以此操作不会创建内存转储。以下信号将导致创建转储文件(来源:GNUC库):SIGFPE:错误的算术运算SIGILL:非法指令SIGSEGV:对存储的无效访问SIGBUS:总线错误SIGABRT:程序检测到错误并被调用中止toabort()报告SIGIOT:此信号在Fedora上已弃用,过去由PDP-11上的abort()触发,现在映射到SIGABRT创建转储文件导航到core_dump_example目录,运行make,然后使用-c1开关以执行示例二进制文件:./coredump-c1应用程序将以状态4退出,并出现以下错误:为“分段错误(核心转储)”写入“Abgebrochen(Speicherabzuggeschrieben)”的转储。是否创建核心转储取决于运行该进程的用户的资源限制。您可以使用ulimit命令修改资源限制。检查用于创建核心转储的当前设置:ulimit-c如果它输出无限制,则它正在使用(推荐的)默认值。否则,使用以下命令更正限制:ulimit-cunlimited要禁用核心转储的创建,请将其大小设置为0:ulimit-c0该数字指定核心转储文件的大小(以块为单位)。什么是核心转储?内核处理核心转储的方式定义在:/proc/sys/kernel/core_pattern我正在运行Fedora31,在我的系统上这个文件包含:/usr/lib/systemd/systemd-coredump%P%u%g%s%t%c%h这表明coredump被转发到systemd-coredump工具。在不同的Linux发行版中,core_pattern的内容会有很大的不同。使用systemd-coredump时,转储文件压缩存储在/var/lib/systemd/coredump下。你不需要直接接触这些文件,你可以使用coredumpctl。例如:coredumpctllist将显示系统中保存的所有可用转储文件。使用coredumpctldump,您可以从上次保存的转储文件中检索信息:[stephan@localhostcore_dump_example]$./coredumpApplicationstarted...(....)Message:Process4598(coredump)ofuser1000dumpedcore.Stacktraceofthread4598:#00x00007f4bbaf22625__GI_raise(libc.)#10x00007f4bbaf0b8d9__GI_abort(libc.so.6)#20x00007f4bbaf664af__libc_message(libc.so.6)#30x00007f4bbaf6da9cmalloc_printerr(libc.so.6)#40x00007f4bbaf6f49c_int_free(libc.so.6)#50x000000000040120en/a(/home/stephan/Dokumente/core_dump_example/coredump)#60x00000000004013b1n/a(/home/stephan/dokumente/core_dump_example/coredump)#70x00007f4bbaf0d1a3__libc_start_main(libc.so.so.6)表示该进程已被SIGABRT停止。此视图中的堆栈跟踪不是很详细,因为它不包括函数名称。但是,使用coredumpctldebug,您可以简单地使用调试器(默认为GDB)打开转储文件。输入bt(backtrace的缩写)以获得更详细的视图:Corewasgeneratedby`./coredump-c1'.ProgramterminatedwithsignalSIGABRT,Aborted.#0__GI_raise(sigsig=sig@entry=6)at../sysdeps/unix/sysv/linux/raise.c:5050returnret;(gdb)bt#0__GI_raise(sigsig=sig@entry=6)at../sysdeps/unix/sysv/linux/raise.c:50#10x00007fc37a9aa8d9in__GI_abort()atabort.c:79#20x00007fc37aa054aagefinc__(actionaction=action@entry=do_abort,fmtfmt=fmt@entry=0x7fc37ab14f4b“%s\n”)在../sysdeps/posix/libc_fatal.c:181#30x00007fc37aa0ca9cinmalloc_printerr(strstr=str@entry=0x7fc37ab130e)0“免费(:invalidpointer")atmalloc.c:5339#40x00007fc37aa0e49cin_int_free(av=,p=,have_lock=0)atmalloc.c:4173#50x000000000040120einfreeSomething(void*)()#60x0000000000in40140内存相比之下,main()和freeSomething()的地址相当低。由于共享对象被映射到虚拟地址空间末尾的区域,因此可以假设SIGABRT是由共享库中的调用引起的。共享对象的内存地址在多次调用之间不是恒定的,所以当你看到多次调用之间地址不同时,可以认为它是一个共享对象。堆栈跟踪显示后续调用源自malloc.c,这表明内存的(取消)分配可能出了问题。在源代码中,(即使没有任何C++知识)您也可以看到它试图释放内存管理函数未返回的指针。这导致未定义的行为并导致SIGABRT。voidfreeSomething(void*ptr){free(ptr);}intnTmp=5;int*ptrNull=&nTmp;freeSomething(ptrNull);这个systemd的coredump工具可以在/etc/systemd/coredump.conf中配置。可以在/etc/systemd/systemd-tmpfiles-clean.timer中配置清洁转储文件的轮换。您可以在其手册页中找到有关coredumpctl的更多信息。要使用调试符号进行编译,请打开Makefile并注释掉第9行的最后一部分。它现在应该如下所示:CFLAGS=-Wall-Werror-std=c++11-g-g开关使编译器能够创建调试信息。启动应用程序,这次使用-c2开关。./coredump-c2你会得到一个浮点异常。在GDB中打开转储文件:coredumpctldebug这一次,您将被引导至源代码中导致错误的行:Readingsymbolsfrom/home/stephan/Dokumente/core_dump_example/coredump...[NewLWP6218]Corewasgeneratedby`./coredump-c2'.ProgramterminatedwithsignalSIGFPE,Arithmeticexception.#00x0000000000401233inzeroDivide()atmain.cpp:2929nRes=5/nDivider;(gdb)键入列表以更好地了解源代码:(gdb)list24intzeroDivide(){25intnDivider=5;26intnRes=0(27whinDivider>0){28nDivider--;29nRes=5/nDivider;30}31returnnRes;32}使用命令infolocals从应用失败的时间点获取局部变量的值:(gdb)infolocalsnDivider=0nRes=5结合源码,可以看到,得到的是除法零错误:nRes=5/0结论了解转储文件的处理方式将帮助您找到并修复应用程序中难以重现的随机错误。如果不是您的应用程序,将核心转储转发给开发人员将帮助她或他找到并解决问题。