Comment générer un dump de noyau sous Linux quand un processus a un défaut de segmentation?
J'ai un processus sous Linux qui a un problème de segmentation. Comment puis-je lui dire de générer un dump core quand il échoue?
10 réponses
Cela dépend du shell que vous utilisez. Si vous utilisez bash, alors la commande ulimit contrôle plusieurs paramètres relatifs à l'exécution du programme, par exemple si vous devez vider core. Si vous tapez
ulimit -c unlimited
alors cela indiquera à bash que ses programmes peuvent décharger des noyaux de n'importe quelle taille. Vous pouvez spécifier une taille telle que 52M au lieu de illimité si vous voulez, mais en pratique cela ne devrait pas être nécessaire puisque la taille des fichiers core ne sera probablement jamais un question pour vous.
dans tcsh, tapez
limit coredumpsize unlimited
comme expliqué ci-dessus, la vraie question qui se pose ici est de savoir comment activer les dumps core sur un système où ils ne sont pas activés. La réponse à cette question est donnée ici.
si vous êtes venu ici dans l'espoir d'apprendre à générer un dump core pour un processus hung, la réponse est
gcore <pid>
si gcoré n'est pas disponible sur votre système alors
kill -ABRT <pid>
N'utilisez pas kill-SEGV car cela fera souvent appel à un gestionnaire de signal faisant il est plus difficile à diagnostiquer l'coincé processus de
ce que j'ai fait à la fin était d'attacher gdb au processus avant qu'il ne s'écrase, et puis quand il a obtenu le segfault j'ai exécuté la commande generate-core-file
. Cette génération forcée d'une décharge de noyau.
peut-être que vous pourriez le faire de cette façon, ce programme est une démonstration de la façon de piéger un défaut de segmentation et de shells out à un débogueur (c'est le code original utilisé sous AIX
) et imprime la trace de pile jusqu'au point d'un défaut de segmentation. Vous devrez changer la variable sprintf
pour utiliser gdb
dans le cas 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 */
}
vous pourriez avoir à ajouter un paramètre pour obtenir gdb pour Dumper le noyau comme montré ici blog ici .
pour vérifier où les dumps du cœur sont générés, exécutez:
sysctl kernel.core_pattern
où %e
est le nom du procédé et %t
le temps du système. Vous pouvez le modifier dans /etc/sysctl.conf
et recharger par sysctl -p
.
si les fichiers de base ne sont pas générés (tester par: sleep 10 &
et killall -SIGSEGV sleep
), vérifier les limites par: ulimit -a
.
si la taille de votre fichier de base est limitée, Lancez:
ulimit -c unlimited
pour le rendre illimité.
puis tester à nouveau, si le dumping du cœur est réussi, vous verrez "(core dumped) "après l'indication de défaut de segmentation comme ci-dessous:
segmentation fault: 11 (core dumped)
Ubuntu
dans Ubuntu généralement les dumps sont traitées par apport
dans /var/crash/
, mais dans un format différent, cependant il n'est pas activé par défaut dans les versions stables. Lire plus à Ubuntu wiki .
il utilise core_pattern
pour Piper directement le noyau dump dans l'apport:
$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c
donc même les fichiers de base sont désactivés par ulimit
, apport
captureront toujours le crash ( comment activer ou désactiver L'Apport? ).
macOS
pour macOS, voir: Comment générer des core dumps dans Mac OS X?
il y a plus de choses qui peuvent influencer la génération d'un noyau dump. J'ai rencontré ceci:
- le répertoire du dump doit être accessible en écriture. Par défaut c'est le répertoire courant du processus, mais qui peut être modifiée par le paramètre
/proc/sys/kernel/core_pattern
. - dans certaines conditions, la valeur du noyau dans
/proc/sys/fs/suid_dumpable
peut empêcher le noyau d'être généré.
il y a plus de situations qui peuvent empêchez la génération qui sont décrites dans la page de manuel - essayez man core
.
pour activer le vidage du cœur, faire ce qui suit:
-
Dans
/etc/profile
commentaire de la ligne:# ulimit -S -c 0 > /dev/null 2>&1
-
Dans
/etc/security/limits.conf
en commentaire la ligne:* soft core 0
-
exécuter le cmd
limit coredumpsize unlimited
et le vérifier avec le cmdlimit
:# 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 #
-
pour vérifier si la corefile obtient écrit Vous pouvez tuer le processus relatif avec cmd
kill -s SEGV <PID>
(ne devrait pas être nécessaire, juste au cas où aucun fichier de base obtient écrit cela peut être utilisé comme un chèque):# kill -s SEGV <PID>
une fois le corefile écrit, assurez-vous de désactiver à nouveau les paramètres de coredump dans les fichiers correspondants (1./2./ 3.) !
Pour Ubuntu 14.04
-
Vérifier core dump activé:
ulimit -a
-
L'une des lignes devrait être:
core file size (blocks, -c) unlimited
-
Si ce n' :
gedit ~/.bashrc
et ajouterulimit -c unlimited
à la fin du fichier et enregistrer, relancer le terminal. -
Construisez votre application avec les informations de débogage :
Dans Le Makefile
-O0 -g
-
exécuter l'application qui crée le dump de base (le fichier de dump de base avec le nom' core’ doit être créé près du fichier application_name):
./application_name
-
Exécuter sous gdb:
gdb application_name core
Par défaut, vous obtiendrez un fichier core. Vérifiez que le répertoire courant du processus est accessible en écriture, ou pas de fichier de base sera créée.
il est préférable d'activer le dump core par programmation en utilisant l'appel système setrlimit
.
exemple:
#include <sys/resource.h>
bool enable_core_dump(){
struct rlimit corelim;
corelim.rlim_cur = RLIM_INFINITY;
corelim.rlim_max = RLIM_INFINITY;
return (0 == setrlimit(RLIMIT_CORE, &corelim));
}