linux下gdb调试coredump文件的方法

1. 写在前面

  最近部分模块使用了c/c++进行开发,由于目前在测试环境出现偶发性的core dump的情况,在问题的跟进过程中用到了部分方法,本文着重介绍core文件生成配置于gdb对其调试的一些方法。

2. core dump 介绍

(1) 概念

  当程序运行的过程中异常终止或崩溃,操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为叫core dump

  我们一般认为core dump就是内存快照,实际上除了内存信息之外,还有些关键的程序运行状态也会同时dump下来,例如寄存器信息(包括程序指针、栈指针等)、内存管理信息、其他处理器和操作系统状态和信息。

  core dump对于编程人员诊断和调试程序是非常有帮助的,因为对于有些程序错误是很难重现的,例如指针异常,而core dump文件可以再现程序出错时的情景。

(2) core dump 文件生成

  对于程序的异常终止,我们发现实际上,如果使用kill -9 xxx的命令,并不会产生core文件,下面列出几种信号会让系统产生core dump的系统信号。

Signal Action Comment
SIGQUIT Core Quit from keyboard
SIGILL Core Illegal Instruction
SIGABRT Core Abort signal from abort
SIGSEGV Core Invalid memory reference
SIGTRAP Core Trace/breakpoint trap

  core文件不都是立即生成的,随着吐core进程的内存空间越大,此过程可能持续很长一段时间,当进程占用60G+以上内存时,完整core文件需要15分钟才能完全写到磁盘上。

  本文主要介绍一些基本的情况,所以对于core dump更详细的产生情况,可以看文末的一些参考资料,里面有详细的介绍。

(3) core dump 配置

配置文件生成

  一般在系统中,可以通过命令ulimit –c查看core dump产生的文件大小,当为0时,则不会产生core dump,需要进行修改和配置。

  ulimit -c unlimited可以产生coredump且不受大小限制,设置仅对当前生效。

  永久生效的配置方法,需要在/etc/profile中加入ulimit -c unlimited命令,允许生成core dump文件。

更改 core dump 生成路径

  core dump默认会生成在程序的工作目录,有时候为了方便,会进行默认路径的调整,大家需要的可以参考。

  创建/coredump文件夹,调用以下命令即可:

  echo /coredump/core.%e.%p> /proc/sys/kernel/core_pattern

  其中%e表示程序名, %p表示进程id。

3. gdb调试

(1) 基本概念

  GDB是一个由GNU开源组织发布的UNIX/LINUX操作系统下的,基于命令行的功能强大的程序调试工具。对于Linux下工作的c/c++程序员,gdb是必不可少的工具。

  对于GDB详细使用方法,文末也引用了一篇更加详细的文章,供大家参考。

(2) 调试实战

  该介绍默认大家对于linux下文件编译已经掌握,我们在编译的时候,会根据是否需要调试,由于我写的模块异常挂掉,为了快速定位问题,添加了-g指令进行编译,当添加了-g以后,在程序core dump后,可以查看到更加详细的堆栈信息。

  虽然我写的模块,是挂载在其他程序上的,但是只要生成了core文件,就不影响对问题的排查,首先进入挂掉的可执行程序目录,找到对应的core文件。

  执行命令gdb xxx.so core.xxx,加载了当时程序挂掉的内存及其他信息:

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `/usr/local/freeswitch/bin/freeswitch -nc -nf -nonat'.
Program terminated with signal 8, Arithmetic exception.
#0  0x00007f0f09e0619b in onSentenceEnd (cbEvent=0x7f0f08dcd810, cbParam=0x7f0f08fd3020) at mod_asr.cpp:331
331	                            int volume_avg = tmpParam->voiceInfo.volume_total/tmpParam->voiceInfo.count;
Missing separate debuginfos, use: debuginfo-install cyrus-sasl-lib-2.1.26-23.el7.x86_64 flac-libs-1.3.0-5.el7_1.x86_64 glibc-2.17-292.el7.x86_64 gsm-1.0.13-11.el7.x86_64 jbigkit-libs-2.0-11.el7.x86_64 keyutils-libs-1.5.8-3.el7.x86_64 krb5
-libs-1.15.1-37.el7_7.2.x86_64 lame-libs-3.100-1.el7.x86_64 libcom_err-1.42.9-16.el7.x86_64 libedit-3.0-12.20121213cvs.el7.x86_64 libgcc-4.8.5-39.el7.x86_64 libjpeg-turbo-1.2.90-8.el7.x86_64 libogg-1.3.0-7.el7.x86_64 libselinux-2.5-14.1.el7.x86_64 libshout-2.2.2-11.el7.x86_64 libsndfile-1.0.25-10.el7.x86_64 libstdc++-4.8.5-39.el7.x86_64 libtheora-1.1.1-8.el7.x86_64 libtiff-4.0.3-32.el7.x86_64 libtool-ltdl-2.4.2-22.el7_3.x86_64 libvorbis-1.3.3-8.el7.1.x86_64 lua-5.1.4-15.el7.x86_64 mpg123-libs-1.25.6-1.el7.x86_64 ncurses-libs-5.9-14.20130511.el7_4.x86_64 nspr-4.21.0-1.el7.x86_64 nss-3.44.0-7.el7_7.x86_64 nss-softokn-freebl-3.44.0-8.el7_7.x86_64 nss-util-3.44.0-4.el7_7.x86_64 openldap-2.4.44-21.el7_6.x86_64 openssl-libs-1.0.2k-19.el7.x86_64 pcre-8.32-17.el7.x86_64 postgresql-libs-9.2.24-2.el7_7.x86_64 speex-1.2-0.19.rc1.el7.x86_64 sqlite-3.7.17-8.el7_7.1.x86_64 

  进入调试模式后,使用bt查看堆栈信息:

unixODBC-2.3.1-14.el7.x86_64 xz-libs-5.2.2-1.el7.x86_64 zlib-1.2.7-18.el7.x86_64(gdb) bt
#0  0x00007f0f09e0619b in onSentenceEnd (cbEvent=0x7f0f08dcd810, cbParam=0x7f0f08fd3020) at mod_asr.cpp:331
#1  0x00007f0f09b1cff9 in AlibabaNls::SpeechTranscriberListener::handlerFrame(AlibabaNls::NlsEvent) () from /usr/local/freeswitch/lib/libnlsCppSdk.so
#2  0x00007f0f09b03b9c in AlibabaNls::NlsSessionBase::handlerFrame(AlibabaNls::util::WebsocketFrame) () from /usr/local/freeswitch/lib/libnlsCppSdk.so
#3  0x00007f0f09b0dba7 in AlibabaNls::transport::engine::webSocketAgent::workloop() () from /usr/local/freeswitch/lib/libnlsCppSdk.so
#4  0x00007f0f09b0cc70 in AlibabaNls::transport::engine::thread_func(void*) () from /usr/local/freeswitch/lib/libnlsCppSdk.so
#5  0x00007f0f9b121e65 in start_thread () from /lib64/libpthread.so.0
#6  0x00007f0f9a77588d in clone () from /lib64/libc.so.6

  由于我在模块编译过程中加入了-g所以能够直接定位到代码行级别的问题,后来查看自己的源码发现,在极端情况下,确实会出现分母为0的情况,导致Segmentation fault,前几天还在提醒同事分母不能为0,自己却遗漏了,实在是疏忽大意。

参考资料

Linux Core Dump

linux下gdb调试方法与技巧整理

你可能感兴趣的:(c++,linux,gdb,core)