Core dump
m |
m (→Analyzing the dump later) |
||
(11 intermediate revisions by one user not shown) | |||
Line 1: | Line 1: | ||
− | To enable | + | To enable core dumps, do this in a shell: |
<source lang="bash"> | <source lang="bash"> | ||
ulimit -c unlimited | ulimit -c unlimited | ||
Line 27: | Line 27: | ||
It will often be stored to <code>./code</code> but the naming schema can be changed. | It will often be stored to <code>./code</code> but the naming schema can be changed. | ||
'''BEWARE''': once a dump has been taken, if the naming schema does not result in a unique name, then an existing dump (or file) will NOT be overwritten. | '''BEWARE''': once a dump has been taken, if the naming schema does not result in a unique name, then an existing dump (or file) will NOT be overwritten. | ||
+ | |||
+ | ==Creating a core dump== | ||
+ | <code>SIGQUIT</code> is usually bound to <code>^\</code>. If it's not being masked and core dumps are enabled, then you should get a dump in your current directory. | ||
+ | |||
+ | Alternatively, use <code>kill -QUIT ${PID}</code> or <code>kill -ABRT ${PID}</code> | ||
+ | |||
+ | ===From within GDB=== | ||
+ | <source lang="text"> | ||
+ | generate-core-file [file] | ||
+ | </source> | ||
==Naming the core dumps== | ==Naming the core dumps== | ||
Line 32: | Line 42: | ||
<source lang="bash"> | <source lang="bash"> | ||
cat /proc/sys/kernel/core_pattern | cat /proc/sys/kernel/core_pattern | ||
− | <source> | + | </source> |
And run the following (as root) to update it: | And run the following (as root) to update it: | ||
Line 39: | Line 49: | ||
</source> | </source> | ||
Putting a '<code>|</code>' (pipe) before an executable path and parameters from below in here allows you to run a script on a crash! That is executed before the application is killed! | Putting a '<code>|</code>' (pipe) before an executable path and parameters from below in here allows you to run a script on a crash! That is executed before the application is killed! | ||
+ | Be careful, that application is run as root, as a child of 'keventd'. | ||
+ | [http://timetobleed.com/an-obscure-kernel-feature-to-get-more-info-about-dying-processes/ Info] | ||
===Pattern replacement=== | ===Pattern replacement=== | ||
Line 62: | Line 74: | ||
| %<NUL> || '%' is dropped | | %<NUL> || '%' is dropped | ||
|} | |} | ||
+ | |||
+ | ===Permanent Configuration=== | ||
+ | You can add a line like this to <code>/etc/sysctl.conf</code>: | ||
+ | <source lang="text"> | ||
+ | kernel.core_pattern = "%e.core.%s.%p" | ||
+ | </source> | ||
+ | |||
+ | ==Core Dump a Running Process== | ||
+ | # Check <code>/proc/${PID}/limits</code> | ||
+ | # SIGQUIT - <code>kill -QUIT ${PID}</code> | ||
==Analyzing the dump later== | ==Analyzing the dump later== | ||
Line 67: | Line 89: | ||
<source lang="bash"> | <source lang="bash"> | ||
gdb ${EXECUTABLE} ${COREDUMP} | gdb ${EXECUTABLE} ${COREDUMP} | ||
+ | </source> | ||
+ | |||
+ | ==Initiate a dump from C== | ||
+ | <source lang="c"> | ||
+ | #include <stdio.h> | ||
+ | #include <unistd.h> | ||
+ | #include <sys/types.h> | ||
+ | #include <sys/wait.h> | ||
+ | #include <sys/time.h> | ||
+ | #include <sys/resource.h> | ||
+ | |||
+ | void dump_core(void) { | ||
+ | pid_t cpid, rpid; | ||
+ | int status; | ||
+ | |||
+ | cpid = fork(); | ||
+ | |||
+ | if (cpid == -1) { | ||
+ | /* fork failed... */ | ||
+ | fprintf(stderr, "dump_core(): failed to fork...\n"); | ||
+ | } | ||
+ | |||
+ | if (cpid == 0 || cpid == -1) { | ||
+ | /* in the child or fork()-failed process... */ | ||
+ | struct rlimit rlim; | ||
+ | rlim_t t; | ||
+ | |||
+ | /* ensure that a dump will be created by setting RLIMIT_CORE... */ | ||
+ | if (getrlimit(RLIMIT_CORE, &rlim) == -1) { | ||
+ | fprintf(stderr, "dump_core(): failed to query RLIMIT_CORE... continuing to attempt a core dump...\n"); | ||
+ | } else { | ||
+ | if (rlim.rlim_max == 0) { | ||
+ | fprintf(stderr, "dump_core(): rlim_max is set to 0... we can't create a core dump...\n"); | ||
+ | if (cpid == -1) return; | ||
+ | exit(42); | ||
+ | } else if (rlim.rlim_max != RLIM_INFINITY) { | ||
+ | fprintf(stderr, "dump_core(): rlim_max is not RLIM_INFINITY... limited to a dump of %ldx 512-byte blocks...\n", rlim.rlim_max); | ||
+ | } | ||
+ | t = rlim.rlim_cur; | ||
+ | rlim.rlim_cur = rlim.rlim_max; | ||
+ | if (setrlimit(RLIMIT_CORE, &rlim) == -1) { | ||
+ | fprintf(stderr, "dump_core(): failed to set RLIMIT_CORE...\n"); | ||
+ | if (t == 0) { | ||
+ | fprintf(stderr, "dump_core(): rlim_cur was set to 0... we can't create a core dump...\n"); | ||
+ | if (cpid == -1) return; | ||
+ | exit(42); | ||
+ | } else if (t != RLIM_INFINITY) { | ||
+ | fprintf(stderr, "dump_core(): rlim_cur is not RLIM_INFINITY... limited to a dump of %ldx 512-byte blocks...\n", t); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* and crash in your favorite way! */ | ||
+ | abort(); | ||
+ | (*((int*)0)) = 42; | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | /* wait for the child to go away (die) */ | ||
+ | if ((rpid = waitpid(cpid, &status, 0)) == -1) { | ||
+ | fprintf(stderr, "dump_core(): failed to wait for the child...\n"); | ||
+ | } else if (rpid == 0) { | ||
+ | fprintf(stderr, "dump_core(): somehow waitpid() returned with no notification...\n"); | ||
+ | } else if (rpid != cpid) { | ||
+ | fprintf(stderr, "dump_core(): somehow waitpid() returned a notification for the wrong child...\n"); | ||
+ | } else { | ||
+ | if (WIFEXITED(status)) { | ||
+ | if (WEXITSTATUS(status) == 42) { | ||
+ | fprintf(stderr, "dump_core(): failed to create a core dump...\n"); | ||
+ | } else { | ||
+ | fprintf(stderr, "dump_core(): child returned with %d (unexpected...)\n", WEXITSTATUS(status)); | ||
+ | } | ||
+ | } else if (WIFSIGNALED(status)) { | ||
+ | if (WCOREDUMP(status)) { | ||
+ | /* if everything goes to plan, this should be all you'll see: */ | ||
+ | fprintf(stderr, "dump_core(): successfully created a core dump!\n"); | ||
+ | } else { | ||
+ | fprintf(stderr, "dump_core(): apparently no core dump was created... :-(\n"); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
</source> | </source> |
Latest revision as of 11:20, 2 March 2017
To enable core dumps, do this in a shell:
ulimit -c unlimited
Or this from C:
#include <sys/time.h> #include <sys/resource.h> void coredump_enable(void) { struct rlimit rlim; getrlimit(RLIMIT_CORE,&rlim); rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE,&rlim); } void coredump_disable(void) { struct rlimit rlim; getrlimit(RLIMIT_CORE,&rlim); rlim.rlim_cur = 0; setrlimit(RLIMIT_CORE,&rlim); }
After you call coredump_enable()
, if your program dies for any reason (Segfault, etc) then a core dump will be taken.
It will often be stored to ./code
but the naming schema can be changed.
BEWARE: once a dump has been taken, if the naming schema does not result in a unique name, then an existing dump (or file) will NOT be overwritten.
Contents |
[edit] Creating a core dump
SIGQUIT
is usually bound to ^\
. If it's not being masked and core dumps are enabled, then you should get a dump in your current directory.
Alternatively, use kill -QUIT ${PID}
or kill -ABRT ${PID}
[edit] From within GDB
generate-core-file [file]
[edit] Naming the core dumps
Run the following to see your current setting:
cat /proc/sys/kernel/core_pattern
And run the following (as root) to update it:
echo "%e.core.%s.%p" > /proc/sys/kernel/core_pattern
Putting a '|
' (pipe) before an executable path and parameters from below in here allows you to run a script on a crash! That is executed before the application is killed!
Be careful, that application is run as root, as a child of 'keventd'.
Info
[edit] Pattern replacement
%p | pid |
%% | output one '%' |
%u | uid |
%g | gid |
%s | signal number |
%t | UNIX time of dump |
%h | hostname |
%e | executable filename |
%<OTHER> | both are dropped |
%<NUL> | '%' is dropped |
[edit] Permanent Configuration
You can add a line like this to /etc/sysctl.conf
:
kernel.core_pattern = "%e.core.%s.%p"
[edit] Core Dump a Running Process
- Check
/proc/${PID}/limits
- SIGQUIT -
kill -QUIT ${PID}
[edit] Analyzing the dump later
Take your executable in the left hand, and the core in the right, and shove them at gdb:
gdb ${EXECUTABLE} ${COREDUMP}
[edit] Initiate a dump from C
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/resource.h> void dump_core(void) { pid_t cpid, rpid; int status; cpid = fork(); if (cpid == -1) { /* fork failed... */ fprintf(stderr, "dump_core(): failed to fork...\n"); } if (cpid == 0 || cpid == -1) { /* in the child or fork()-failed process... */ struct rlimit rlim; rlim_t t; /* ensure that a dump will be created by setting RLIMIT_CORE... */ if (getrlimit(RLIMIT_CORE, &rlim) == -1) { fprintf(stderr, "dump_core(): failed to query RLIMIT_CORE... continuing to attempt a core dump...\n"); } else { if (rlim.rlim_max == 0) { fprintf(stderr, "dump_core(): rlim_max is set to 0... we can't create a core dump...\n"); if (cpid == -1) return; exit(42); } else if (rlim.rlim_max != RLIM_INFINITY) { fprintf(stderr, "dump_core(): rlim_max is not RLIM_INFINITY... limited to a dump of %ldx 512-byte blocks...\n", rlim.rlim_max); } t = rlim.rlim_cur; rlim.rlim_cur = rlim.rlim_max; if (setrlimit(RLIMIT_CORE, &rlim) == -1) { fprintf(stderr, "dump_core(): failed to set RLIMIT_CORE...\n"); if (t == 0) { fprintf(stderr, "dump_core(): rlim_cur was set to 0... we can't create a core dump...\n"); if (cpid == -1) return; exit(42); } else if (t != RLIM_INFINITY) { fprintf(stderr, "dump_core(): rlim_cur is not RLIM_INFINITY... limited to a dump of %ldx 512-byte blocks...\n", t); } } } /* and crash in your favorite way! */ abort(); (*((int*)0)) = 42; exit(-1); } /* wait for the child to go away (die) */ if ((rpid = waitpid(cpid, &status, 0)) == -1) { fprintf(stderr, "dump_core(): failed to wait for the child...\n"); } else if (rpid == 0) { fprintf(stderr, "dump_core(): somehow waitpid() returned with no notification...\n"); } else if (rpid != cpid) { fprintf(stderr, "dump_core(): somehow waitpid() returned a notification for the wrong child...\n"); } else { if (WIFEXITED(status)) { if (WEXITSTATUS(status) == 42) { fprintf(stderr, "dump_core(): failed to create a core dump...\n"); } else { fprintf(stderr, "dump_core(): child returned with %d (unexpected...)\n", WEXITSTATUS(status)); } } else if (WIFSIGNALED(status)) { if (WCOREDUMP(status)) { /* if everything goes to plan, this should be all you'll see: */ fprintf(stderr, "dump_core(): successfully created a core dump!\n"); } else { fprintf(stderr, "dump_core(): apparently no core dump was created... :-(\n"); } } } }