Linux:生成core的几种方式


1.总结

在某些情况下,进程会生成core文件(核心转储),记录进程状态,帮助我们快速定位异常。

例如:

  • 当进程异常时如段错误退出,可以分析结果core,查看调用栈定位空指针处;
  • 当进程执行某处代码阻塞时,可以强制生成core,查看调用栈定位阻塞原因;
  • ……

以下几种方式可生成core:

  • 代码不严谨异常退出,如最常见的段错误(Segmentation fault);
  • 进程收到SIGABRT信号,进程退出并生成core;
  • 通过gcore(或gdb)对进程生成core,进程正常运行不终止;

2.环境版本

操作系统:

[test1280@test1280 20210113]$ uname -a
Linux test1280 2.6.32-642.el6.x86_64 #1 SMP Tue May 10 17:27:01 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
[test1280@test1280 20210113]$ cat /etc/redhat-release
CentOS release 6.8 (Final)

环境变量:

[test1280@test1280 20210113]$ ulimit -c
unlimited

注意:

ulimit -c一定不能是0,最好是ulimited。

ulimit -c如果设置为0,将无法生成core文件。

更多参考:https://blog.csdn.net/test1280/article/details/73655994


3.示例

3.1.运行时异常

最常见的如段错误:

  • 空指针引用
  • 内存越界
  • ……

以操作空指针引起段错误为例:

demo1.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>struct Student
{char *mName;char *mAddr;int   mAge;
};int fun3()
{struct Student* pStudent = NULL;/* 对空指针NULL操作段错误 */pStudent->mName = "test1280";
}int fun2()
{fun3();
}int fun1()
{fun2();
}int main()
{fun1();
}

编译、执行:

[test1280@test1280 20210113]$ gcc -o demo1 demo1.c -g
[test1280@test1280 20210113]$ ./demo1
Segmentation fault (core dumped)

查看core文件:

[test1280@test1280 20210113]$ gdb -c core.3348 demo1
......
Core was generated by `./demo1'.
Program terminated with signal 11, Segmentation fault.
#0  0x0000000000400484 in fun3 () at demo1.c:16
16      pStudent->mName = "test1280";
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.192.el6.x86_64
(gdb) bt
#0  0x0000000000400484 in fun3 () at demo1.c:16
#1  0x000000000040049b in fun2 () at demo1.c:21
#2  0x00000000004004ab in fun1 () at demo1.c:26
#3  0x00000000004004bb in main () at demo1.c:31
(gdb) quit

异常时的调用栈为:main->fun1->fun2->fun3

#0  0x0000000000400484 in fun3 () at demo1.c:16
#1  0x000000000040049b in fun2 () at demo1.c:21
#2  0x00000000004004ab in fun1 () at demo1.c:26
#3  0x00000000004004bb in main () at demo1.c:31

指明异常原因:

Program terminated with signal 11, Segmentation fault.

注:signal 11 = SIGSEGV

指明异常代码(源文件、源代码):

#0  0x0000000000400484 in fun3 () at demo1.c:16
16      pStudent->mName = "test1280";

其他错误也可能引起core生成,如除0操作:

int fun3()
{int i = 0/0;
}
Floating point exception (core dumped)
Program terminated with signal 8, Arithmetic exception.

3.2.信号

信号可以是进程自己触发,又或者是手动触发。

3.2.1.abort

进程在执行到异常流程时,可以主动调用abort函数(C库stdlib)退出进程,并生成core文件。

demo2.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int fun3()
{/* 异常流程,退出进程 */abort();
}int fun2()
{fun3();
}int fun1()
{fun2();
}int main()
{fun1();
}

编译、执行:

[test1280@test1280 20210113]$ gcc -o demo2 demo2.c -g
[test1280@test1280 20210113]$ ./demo2
Aborted (core dumped)

查看core文件:

[test1280@test1280 20210113]$ gdb -c core.3415 demo2
......
Core was generated by `./demo2'.
Program terminated with signal 6, Aborted.
#0  0x0000003da0e325e5 in raise () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.192.el6.x86_64
(gdb) bt
#0  0x0000003da0e325e5 in raise () from /lib64/libc.so.6
#1  0x0000003da0e33dc5 in abort () from /lib64/libc.so.6
#2  0x00000000004004cd in fun3 () at demo2.c:8
#3  0x00000000004004db in fun2 () at demo2.c:13
#4  0x00000000004004eb in fun1 () at demo2.c:18
#5  0x00000000004004fb in main () at demo2.c:23
(gdb) quit

异常时的调用栈为:main->fun1->fun2->fun3->abort->raise

#0  0x0000003da0e325e5 in raise () from /lib64/libc.so.6
#1  0x0000003da0e33dc5 in abort () from /lib64/libc.so.6
#2  0x00000000004004cd in fun3 () at demo2.c:8
#3  0x00000000004004db in fun2 () at demo2.c:13
#4  0x00000000004004eb in fun1 () at demo2.c:18
#5  0x00000000004004fb in main () at demo2.c:23

在调用abort时,调用raise,发送SIGABRT信号到进程自身。

指明异常原因:

Program terminated with signal 6, Aborted.

注:signal 6 = SIGABRT

指明异常代码(源文件、源代码):

#0  0x0000003da0e325e5 in raise () from /lib64/libc.so.6
3.2.2.kill
  • Ctrl+\

如果进程运行在前台,例如:

demo3.c

[test1280@test1280 20210113]$ cat demo3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int fun3()
{while (1){sleep(1);}
}int fun2()
{fun3();
}int fun1()
{fun2();
}int main()
{fun1();
}

编译、执行:

[test1280@test1280 20210113]$ gcc -o demo3 demo3.c -g
[test1280@test1280 20210113]$ ./demo3
【前台阻塞,在demo3执行完毕前,当前shell阻塞】

在当前shell键入Ctrl+\,发送SIGQUIT信号到前台进程:

[test1280@test1280 20210113]$ gcc -o demo3 demo3.c -g
[test1280@test1280 20210113]$ ./demo3
^\Quit (core dumped)

此时,前台进程终止运行,生成core文件。

查看core文件:

[test1280@test1280 20210113]$ gdb -c core.3575 demo3
......
Core was generated by `./demo3'.
Program terminated with signal 3, Quit.
#0  0x0000003da0eacbc0 in __nanosleep_nocancel () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.192.el6.x86_64
(gdb) bt
#0  0x0000003da0eacbc0 in __nanosleep_nocancel () from /lib64/libc.so.6
#1  0x0000003da0eaca50 in sleep () from /lib64/libc.so.6
#2  0x00000000004004d2 in fun3 () at demo3.c:9
#3  0x00000000004004e2 in fun2 () at demo3.c:15
#4  0x00000000004004f2 in fun1 () at demo3.c:20
#5  0x0000000000400502 in main () at demo3.c:25

注意:signal 3 = SIGQUIT

Program terminated with signal 3, Quit.
  • kill

kill命令(或类似kill的命令),可以手动发送指定信号到指定进程。

例如,仍以demo3为例,可以保持前台挂起,新启动shell终端执行kill:

【终端1】
[test1280@test1280 20210113]$ ./demo3
【终端1阻塞...】【终端2】
【先查demo3进程的PID=3587】
[test1280@test1280 ~]$ ps aux | grep demo3 | grep -v grep
test1280   3587  0.0  0.0   3920   328 pts/0    S+   06:41   0:00 ./demo3
【执行kill命令发送SIGQUIT到3587进程】
[test1280@test1280 ~]$ kill -SIGQUIT 3587【终端1】
[test1280@test1280 20210113]$ ./demo3
Quit (core dumped)
【demo3进程收到在终端2通过kill发送的SIGQUIT信号,进程退出,终端1不再阻塞】

3.3.gcore

若生产环境中进程出现异常阻塞,在不宕停进程的情况下想生成core,可以使用gcore。

gcore是一个调用gdb的脚本:

[test1280@test1280 20210113]$ which gcore
/usr/bin/gcore
[test1280@test1280 20210113]$ file `which gcore`
/usr/bin/gcore: POSIX shell script text executable
[test1280@test1280 20210113]$ vi `which gcore`
......

gcore的man描述:

Generate a core dump of a running program with process ID pid.
Produced file is equivalent to a kernel produced core file as if the process crashed (and if “ulimit -c” were used to set up an appropriate core dump limit).
Unlike after a crash, after gcore the program remains running without any change.

例如,仍以demo3为例,可以保持前台挂起,新启动shell终端执行gcore:

【终端1】
[test1280@test1280 20210113]$ ./demo3
【终端1等待demo3进程宕停,终端1阻塞挂起】【终端2】
【先查demo3进程的PID=3644】
[test1280@test1280 20210113]$ ps aux | grep demo3 | grep -v grep
test1280   3644  0.0  0.0   3920   332 pts/0    S+   06:52   0:00 ./demo3
【gcore <pid>生成core】
[test1280@test1280 20210113]$ gcore 3644
0x0000003da0eacbc0 in __nanosleep_nocancel () from /lib64/libc.so.6
Saved corefile core.3644【终端1】
[test1280@test1280 20210113]$ ./demo3
【终端1进程仍然阻塞等待demo3进程宕停,在执行gcore后,demo3进程仍运行】

gcore脚本,是调用gdb的gcore指令实现其功能:

[test1280@test1280 20210113]$ gdb
(gdb) help gcore
Save a core file with the current state of the debugged process.
Argument is optional filename.  Default filename is 'core.<process_id>'.
(gdb) quit

4.总结

进程会由于各种各样的原因主动地或被动地生成core。

但归咎起来,大体上都是通过内核信号生成:

* SIGSEGV:段错误
* SIGABRT:abort
* SIGQUIT:Ctrl+Q

除上之外,还有其他信号也会导致进程出core,例如SIGILL、SIGTRAP等。

关键在于,何种情况会导致信号触发送到进程。

除了信号,gcore调用gdb的gcore指令,使得某个进程生成core文件但并不终止进程执行。

遗留问题:gcore实现原理,是否也是发送某一种特定信号,此信号会使得进程生成core但并不终止?

Linux:生成core的几种方式相关推荐

  1. 在 C# 中生成代码的四种方式——包括.NET 5中的Source Generators

    Microsoft在最新的C#版本中引入了Source Generator.这是一项新功能,可以让我们在代码编译时生成源代码.在本文中,我将介绍四种C#中的代码生成方式,以简化我们的日常工作.然后,您 ...

  2. Linux进程通信的四种方式——共享内存、信号量、无名管道、消息队列|实验、代码、分析、总结

    Linux进程通信的四种方式--共享内存.信号量.无名管道.消息队列|实验.代码.分析.总结 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须 ...

  3. linux生成core文件路径,core文件生成和路径设置

    在程序崩溃时,内核会生成一个core文件,即程序最后崩溃时的内存映像,和程序调试信息. 之后可以通过gdb,打开core文件察看程序崩溃时的堆栈信息,可以找出程序出错的代码所在文件和函数. 1.cor ...

  4. json 生成html转换,根据json字符串生成Html的一种方式

    文章说明: 本文介绍了根据Json串生成Html的一种方式(只是简单实现了文本框,密码框,下拉框).只是觉得好玩才这样做,如果觉得没有任何价值,请忽略.不足指出希望各位大牛指点.后续将根据各位的指点继 ...

  5. 【Pytest篇】pytest生成报告的几种方式

    使用Pytest生成测试报告的几种方式 1.生成Junitxml文件,可供后续jenkins持续集成使用 在cmd 命令行中执行如下命令 pytest test_login_dlz.py --juni ...

  6. 写一个静态HTML页面,直接写HTML代码和用JS动态生成代码,哪种方式要好

    如果写一个静态HTML页面,直接写HTML代码和用JS动态生成代码,哪种方式要好点?为什么? 不考虑人力因素(手写HTML太费时间排除),请从读取和解析或者其他的角度分析.谢谢 添加评论 分享 按投票 ...

  7. php 生成复杂json数据,生成json的几种方式

    这里是修真院后端小课堂,每篇分享文从 [背景介绍][知识剖析][常见问题][解决方案][编码实战][扩展思考][更多讨论][参考文献] 八个方面深度解析后端知识/技能,本篇分享的是: [生成json的 ...

  8. Linux 修改密码的两种方式

    Linux 修改密码的两种方式 1.直接进行修改 2.使用 echo 进行修改 1.直接进行修改 密码需要输入两次进行确认. 对用户"zhangyan"进行密码修改,改为" ...

  9. linux 删除文件的几种方式

    linux 删除文件的几种方式 创建.删除和修改文件是用户在 Linux 系统中执行的非常常见操作.大家都知道,在 Linux 系统里使用 rm 命令删除单个文件时,几乎一瞬间就完成了.但是如果文件数 ...

最新文章

  1. 神经网络的学习方式网络传播和图卷积,两者到底什么关系?
  2. NETCORE openSUSE docker 安装
  3. 游戏中常用的寻路算法的分享(4)处理移动中的障碍物
  4. SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常见问题总结
  5. 同志亦凡人第五季/全集BQueer As Folk 5迅雷下载
  6. 尺度不变性是指什么不变_不变性如何提供帮助
  7. python画同心圆程序_Python Turtle:使用circle()方法绘制同心圆
  8. js设置百分比保留两位小数
  9. DW ——随机抽号(七位)(JavaScript)
  10. Python处理Excel文件
  11. mysql 左表为null_sql left join count 左表为空表的时候出现空行
  12. vue-router如何参数传递
  13. 一个6年java程序员的工作感悟,写给还在迷茫的你
  14. linux上卓懿应用商城王者荣耀键盘映射如何设置?
  15. win10内置计算机和天气闪退,win10系统中天气闪退怎么办?Win10天气应用闪退问题解决方法...
  16. Python之字典遍历元素
  17. Python将PDF转换为图片
  18. 常见Http响应头部 responses header
  19. java输入语句怎么写_java输入语句应该怎样写?示例演示
  20. 新浪微博开放平台站内应用开发流程直播(一)

热门文章

  1. bitset 用法整理
  2. Linux使用Shell定时清理日志文件
  3. hook failed (add --no-verify to bypass)
  4. 水晶头的制作的学习经历
  5. 使用gradle开启multiDex时,如何配置MainDex
  6. 安装spss破解版以及spss安装之后提示我程序无法启动,因为应用程序的并行配置不正确
  7. Keystone的安装及其配置
  8. linux进程管理杂记(1)
  9. vim配置参考备忘-------嵌入式
  10. Go Moudle笔记