GDB调试之core dump

linux下的c程序常常会因为内存访问错误等原因造成segment fault,此时如果系统core dump功能是打开的,那么将会有内存映像转储到硬盘上,之后可以用gdb对core文件进行分析,查看系统发生segment fault时刻的情况。

 

Linux中生成 Core Dump 文件的方法


1 什么是 Core Dump


Core Dump 又叫核心转储。在程序运行过程中发生异常时,将其内存数据保存到文件中,这个过程叫做 Core Dump。


2 Core Dump 的作用


在开发过程中,难免会遇到程序运行过程中异常退出的情况,这时候想要定位哪里出了问题,仅仅依靠程序自身的信息打印(日志记录)往往是不够的,这个时候就需要 Core Dump 文件来帮忙了。
一个完整的 Core Dump 文件实际上相当于恢复了异常现场,利用 Core Dump 文件,可以查看到程序异常时的所有信息,变量值、栈信息、内存数据,程序异常时的运行位置(甚至记录代码行号)等等,定位所需要的一切信息都可以从 Core Dump文件获取到,能够非常有效的提高定位效率。


3 如何生成 Core Dump


3.1 Core Dump 文件生成开关


Core Dump 文件的生成是由Core文件大小限制,Linux中默认的Core文件大小设置为零,也就是不生成 Core Dump 文件,可以使用ulimit -c命令来查看当前的Core文件大小限制。
要生成 Core Dump 文件,只需要执行下面的命令设置Core文件的大小即可(其中filesize参数的单位为KByte):
ulimit -c filesize
如果要设置Core文件大小无限制(即把程序完整的运行内存都保存下来),则执行如下命令:
ulimit -c unlimited


3.2 Core Dump 文件名设置


Core Dump 文件默认的名字为core,而且新的Core文件会把老的覆盖,这样我们只能看到最后一次的 Core Dump 信息,可以通过设置Core文件名称模板,使每次生成的 Core Dump 文件区分开来。
Core Dump 文件的命名规则定义在/proc/sys/kernel/core_pattern文件中,规则中还可以加入预设的变量来更好的区分Core文件,支持的变量列表如下:
变量 说明
%% %字符
%p 进程ID(PID)
%u 用户ID(UID)
%g 用户组ID
%s 触发 Core Dump 的信号
%t 触发 Core Dump 的时间(单位为秒,从 1970-01-01 00:00:00 开始计算)
%h 主机名称(主机名可以通过uname命令来查看)
%e 程序名称(无路径信息)
%E 程序的路径名称(路径中的/会被!替代)
%c Core文件的限制大小值(Linux 2.6.24版本后开始支持)
注:Core Dump 文件名的最大长度为128字节(在 Linux 2.6.19 版本前,最大长度为64字节)。
例如:可以通过下面的命令,生成文件名为core-程序名称-进程ID-时间的 Core Dump 文件:
echo "core-%e-%p-%t" > /proc/sys/kernel/core_pattern
从 Linux 2.4 版本开始,提供了一种比较原始的Core文件名设置方式,直接设置/proc/sys/kernel/core_uses_pid文件中的值为1,生成的Core文件名中便会自动加上.PID后缀,即生成的文件名为core.PID这种形式。执行下面的命令可以设置该值:
echo "1" > /proc/sys/kernel/core_uses_pid


4 如何使用 Core Dump


有了 Core Dump 文件后,可以使用GDB来加载分析,执行如下命令(假设可执行程序名称及路径为/home/hutaow/test_dump,生成的Core文件名为core):

gdb /home/hutaow/test_dump -c core
gdb ./test_dump -c core


加载完成后,即可以在GDB中查看程序异常时的各种运行信息了(查看变量值、线程信息、调用栈、反汇编等等)。

 

5 gdb调试堆栈信息一堆问号如 #0 0x0000000000000000 in ?? () 看这里跟踪

一、首次运行coredump文件

利用gdb运行coredump文件,在gdb环境下运行run命令,可以看到如下的信息:
Thread 4 “go” received signal SIGSEGV, Segmentation fault.
说明线程id为4挂掉了。那么如何找到线程Id为4的线程呢,接下来还有如下打印
[Switching to Thread 0x7ffff3a32700 (LWP 393021)]
0x7ffff3a32700为线程的堆栈地址,记住此地址0x7ffff3a32700

该步骤gdb命令调用过程如下:

gdb ./go core.629415 (go是我的可执行程序,core是coredump文件)
(gdb) run(运行程序)
二、再次运行coredump文件
退出步骤一中的gdb,重新运行coredump文件,在我们之前printf定位到的函数处加入断点,然后启动单步调试,再打印出所有的线程信息来,找到步骤一中挂掉的线程堆栈地址,然后进入该线程,打印线程堆栈即可看到是哪个线程挂掉了。

该步骤gdb命令调用过程如下:
gdb ./go core.629415 (go是我的可执行程序,core是coredump文件)
(gdb) b My_test (在My_test函数加断点)
(gdb) run(运行程序)
(gdb) info threads(打印线程信息)

Id Target Id Frame
1 Thread 0x7ffff7fd6780 (LWP 777965) “go” 0x00007ffff6cc933d in read () at …/sysdeps/unix/syscall-template.S:84
2 Thread 0x7ffff471a700 (LWP 778007) “go” 0x00007ffff6cd9ad3 in epoll_wait () at …/sysdeps/unix/syscall-template.S:84
3 Thread 0x7ffff7f10700 (LWP 778008) “go” 0x00007ffff6ccf693 in select () at …/sysdeps/unix/syscall-template.S:84
4 Thread 0x7ffff3a32700 (LWP 778009) “go” 0x00007ffff6cd9ad3 in epoll_wait () at …/sysdeps/unix/syscall-template.S:84

(gdb) thread 4(切换到挂掉的线程0x7ffff3a32700)
(gdb) bt(查看该线程中的堆栈信息)
bt完之后即可查看到出问题的线程了。接下来排查对应的线程就可以了。

加断点的目的是为了让程序不再往下走,以便我们在程序奔溃前找到对应的线程号并切进去查看堆栈,如果程序奔溃后再切到线程后bt的话 就是一堆0和问号什么都看不到,更找不到是哪个线程挂了。

这种一堆0和问号的问题多注意排查线程中memset.memcpy,这种函数,初始化赋值或者拷贝内存的时候拷贝的多了就有可能把线程的堆栈冲掉而导致出现堆栈信息为0?的现象。
————————————————
版权声明:本文为CSDN博主「yebour」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yebour/article/details/111405805

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_yeoman_ym

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值