¿Cómo generar un volcado de núcleo en Linux cuando un proceso obtiene una falla de segmentación?
bash unix (9)
Tengo un proceso en Linux que está recibiendo un error de segmentación. ¿Cómo puedo decirle que genere un volcado del núcleo cuando falla?
Como se explicó anteriormente, la verdadera pregunta que se hace aquí es cómo habilitar los volcados centrales en un sistema donde no están habilitados. Esa pregunta es respondida aquí.
Si ha venido aquí con la esperanza de aprender cómo generar un volcado de núcleo para un proceso bloqueado, la respuesta es
gcore <pid>
si Gcore no está disponible en su sistema, entonces
kill -ABRT <pid>
No use kill -SEGV ya que a menudo invocará un manejador de señal que dificultará el diagnóstico del proceso atorado
Esto depende de qué shell estás usando. Si está utilizando bash, el comando ulimit controla varias configuraciones relacionadas con la ejecución del programa, por ejemplo, si debe volcar core. Si escribe
ulimit -c unlimited
entonces eso le dirá a bash que sus programas pueden volcar núcleos de cualquier tamaño. Puede especificar un tamaño como 52M en lugar de ilimitado si lo desea, pero en la práctica esto no debería ser necesario ya que el tamaño de los archivos centrales probablemente nunca sea un problema para usted.
En tcsh, escribirías
limit coredumpsize unlimited
Hay más cosas que pueden influir en la generación de un volcado de memoria. Me encontré con estos:
- el directorio para el volcado debe ser de escritura. Por defecto, este es el directorio actual del proceso, pero puede modificarse configurando
/proc/sys/kernel/core_pattern
. - en algunas condiciones, el valor del kernel en
/proc/sys/fs/suid_dumpable
puede evitar que se genere el núcleo.
Hay más situaciones que pueden evitar la generación que se describen en la página de manual: try man core
.
Lo que hice al final fue adjuntar gdb al proceso antes de que se bloqueara, y luego, cuando obtuvo el segfault, ejecuté el comando generate-core-file
. Eso forzó la generación de un volcado de núcleo.
Para Ubuntu 14.04
Comprobar el volcado del núcleo habilitado:
ulimit -a
Una de las líneas debería ser:
core file size (blocks, -c) unlimited
Si no :
gedit ~/.bashrc
y añadaulimit -c unlimited
al final del archivo y guarde, vuelva a ejecutar el terminal.Crea tu aplicación con información de depuración:
En Makefile
-O0 -g
Ejecutar la aplicación que crea el volcado del núcleo (el archivo de volcado del núcleo con el nombre ''núcleo'' debe crearse cerca del archivo nombre_aplicación):
./application_name
Ejecutar bajo gdb:
gdb application_name core
Para activar el volcado del núcleo haga lo siguiente:
En
/etc/profile
comente la línea:# ulimit -S -c 0 > /dev/null 2>&1
En
/etc/security/limits.conf
comente la línea:* soft core 0
ejecuta el
limit coredumpsize unlimited
cmdlimit coredumpsize unlimited
y compruébalo con ellimit
cmd:# limit coredumpsize unlimited # limit cputime unlimited filesize unlimited datasize unlimited stacksize 10240 kbytes coredumpsize unlimited memoryuse unlimited vmemoryuse unlimited descriptors 1024 memorylocked 32 kbytes maxproc 528383 #
para comprobar si se escribe el archivo core, puedes eliminar el proceso relacionado con cmd
kill -s SEGV <PID>
(no debería ser necesario, solo en caso de que no se haya escrito ningún archivo core, se puede utilizar como verificación):# kill -s SEGV <PID>
Una vez que se ha escrito el archivo core, asegúrese de desactivar nuevamente la configuración del busreducto en los archivos relacionados (1./2/3).
Para verificar dónde se generan los volcados del núcleo, ejecute:
sysctl kernel.core_pattern
donde %e
es el nombre del proceso y %t
la hora del sistema. Puede cambiarlo en /etc/sysctl.conf
y volver a cargar mediante sysctl -p
.
Si los archivos centrales no se generan ( killall -SIGSEGV sleep
por: sleep 10 &
y killall -SIGSEGV sleep
), verifique los límites por: ulimit -a
.
Si el tamaño de su archivo central es limitado, ejecute:
ulimit -c unlimited
para hacerlo ilimitado
Luego, vuelva a probar, si el volcado de núcleo es exitoso, verá "(núcleo volcado)" después de la indicación de falla de segmentación como se muestra a continuación:
Falla de segmentación: 11 (núcleo objeto de dumping)
Ubuntu
En Ubuntu, por lo general, los volcados son manejados por un apport
en /var/crash/
, pero en un formato diferente, sin embargo, no está habilitado por defecto en las versiones estables. Lea más en Ubuntu wiki .
Utiliza core_pattern
para canalizar directamente el volcado de núcleo en la aplicación:
$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c
De modo que incluso los archivos centrales están deshabilitados por ulimit
, el apport
aún capturará el bloqueo ( ¿Cómo activo o desactivo el informe? ).
Mac OS
Para macOS, consulte: ¿Cómo generar volcados centrales en Mac OS X?
Por defecto, obtendrá un archivo central. Verifique que el directorio actual del proceso sea escribible, o no se creará ningún archivo principal.
Tal vez podría hacerlo de esta manera, este programa es una demostración de cómo atrapar un error de segmentación y elimina un depurador (este es el código original utilizado en AIX
) e imprime el seguimiento de la pila hasta el punto de un error de segmentación. Tendrá que cambiar la variable sprintf
para usar gdb
en el caso de Linux.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
static void signal_handler(int);
static void dumpstack(void);
static void cleanup(void);
void init_signals(void);
void panic(const char *, ...);
struct sigaction sigact;
char *progname;
int main(int argc, char **argv) {
char *s;
progname = *(argv);
atexit(cleanup);
init_signals();
printf("About to seg fault by assigning zero to *s/n");
*s = 0;
sigemptyset(&sigact.sa_mask);
return 0;
}
void init_signals(void) {
sigact.sa_handler = signal_handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGSEGV);
sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGBUS);
sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGQUIT);
sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGHUP);
sigaction(SIGHUP, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGKILL);
sigaction(SIGKILL, &sigact, (struct sigaction *)NULL);
}
static void signal_handler(int sig) {
if (sig == SIGHUP) panic("FATAL: Program hanged up/n");
if (sig == SIGSEGV || sig == SIGBUS){
dumpstack();
panic("FATAL: %s Fault. Logged StackTrace/n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
}
if (sig == SIGQUIT) panic("QUIT signal ended program/n");
if (sig == SIGKILL) panic("KILL signal ended program/n");
if (sig == SIGINT) ;
}
void panic(const char *fmt, ...) {
char buf[50];
va_list argptr;
va_start(argptr, fmt);
vsprintf(buf, fmt, argptr);
va_end(argptr);
fprintf(stderr, buf);
exit(-1);
}
static void dumpstack(void) {
/* Got this routine from http://www.whitefang.com/unix/faq_toc.html
** Section 6.5. Modified to redirect to file to prevent clutter
*/
/* This needs to be changed... */
char dbx[160];
sprintf(dbx, "echo ''where/ndetach'' | dbx -a %d > %s.dump", getpid(), progname);
/* Change the dbx to gdb */
system(dbx);
return;
}
void cleanup(void) {
sigemptyset(&sigact.sa_mask);
/* Do any cleaning up chores here */
}
Es posible que deba agregar un parámetro adicional para que gdb descargue el núcleo como se muestra aquí en este blog here .