¿Cómo generar un volcado de núcleo en Linux cuando un proceso obtiene una falla de segmentación?

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?

Esto depende de qué shell estás usando. Si está utilizando bash, el comando ulimit controla varias configuraciones relacionadas con la ejecución del progtwig, por ejemplo, si debe volcar core. Si escribe

ulimit -c unlimited 

entonces eso le dirá a bash que sus progtwigs 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 

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  

si Gcore no está disponible en su sistema, entonces

 kill -ABRT  

No use kill -SEGV ya que a menudo invocará un manejador de señal que dificultará el diagnóstico del proceso atorado

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.

Tal vez podría hacerlo de esta manera, este progtwig 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 stack hasta el punto de un error de segmentación. Tendrá que cambiar la variable sprintf para usar gdb en el caso de Linux.

 #include  #include  #include  #include  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 aquí .

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 locking ( ¿Cómo activo o desactivo el informe? ).


Mac OS

Para macOS, consulte: ¿Cómo generar volcados centrales en Mac OS X?

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 .

Para activar el volcado del núcleo haga lo siguiente:

  1. En /etc/profile comente la línea:

     # ulimit -S -c 0 > /dev/null 2>&1 
  2. En /etc/security/limits.conf comente la línea:

     * soft core 0 
  3. ejecuta el limit coredumpsize unlimited cmd limit coredumpsize unlimited y compruébalo con el limit 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 # 
  4. para comprobar si se escribe el archivo core, puedes eliminar el proceso relacionado con cmd kill -s SEGV (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  

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 Ubuntu 14.04

  1. Comprobar el volcado del núcleo habilitado:

     ulimit -a 
  2. Una de las líneas debería ser:

     core file size (blocks, -c) unlimited 
  3. Si no :

    gedit ~/.bashrc y añada ulimit -c unlimited al final del archivo y guarde, vuelva a ejecutar el terminal.

  4. Crea tu aplicación con información de depuración:

    En Makefile -O0 -g

  5. 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 
  6. Ejecutar bajo gdb:

     gdb application_name core 

Por defecto, obtendrá un archivo central. Verifique que el directorio actual del proceso sea escribible, o no se creará ningún archivo principal.

Es mejor activar el volcado del núcleo mediante progtwigción utilizando el setrlimit llamadas del sistema.

ejemplo:

 #include  bool enable_core_dump(){ struct rlimit corelim; corelim.rlim_cur = RLIM_INFINITY; corelim.rlim_max = RLIM_INFINITY; return (0 == setrlimit(RLIMIT_CORE, &corelim)); }