Comment générer un core dump sous Linux sur une faute de segmentation ?
Question
J'ai un processus sous Linux qui rencontre une erreur de segmentation.Comment puis-je lui dire de générer un core dump en cas d'échec ?
La solution
Cela dépend du shell que vous utilisez.Si vous utilisez bash, la commande ulimit contrôle plusieurs paramètres relatifs à l'exécution du programme, par exemple si vous devez vider le noyau.Si vous tapez
ulimit -c unlimited
alors cela indiquera à bash que ses programmes peuvent vider des cœurs de n'importe quelle taille.Vous pouvez spécifier une taille telle que 52 Mo au lieu d'illimitée si vous le souhaitez, mais en pratique, cela ne devrait pas être nécessaire puisque la taille des fichiers principaux ne sera probablement jamais un problème pour vous.
En tcsh, tu taperais
limit coredumpsize unlimited
Autres conseils
Comme expliqué ci-dessus, la vraie question posée ici est de savoir comment activer les core dumps sur un système où ils ne sont pas activés.Cette question trouve une réponse ici.
Si vous êtes venu ici dans l'espoir d'apprendre comment générer un core dump pour un processus bloqué, la réponse est
gcore <pid>
si gcore n'est pas disponible sur votre système alors
kill -ABRT <pid>
N'utilisez pas kill -SEGV car cela invoquera souvent un gestionnaire de signal, ce qui rendra plus difficile le diagnostic du processus bloqué.
Ce que j'ai fait à la fin, c'est d'attacher gdb au processus avant qu'il ne plante, puis quand il a eu l'erreur de segmentation, j'ai exécuté le generate-core-file
commande.Cela a forcé la génération d’un core dump.
Pour vérifier où les core dumps sont générés, exécutez :
sysctl kernel.core_pattern
ou:
cat /proc/sys/kernel/core_pattern
où %e
est le nom du processus et %t
l’heure du système.Vous pouvez le changer /etc/sysctl.conf
et rechargement par sysctl -p
.
Si les fichiers core ne sont pas générés (testez-le en : sleep 10 &
et killall -SIGSEGV sleep
), vérifiez les limites en : ulimit -a
.
Si la taille de votre fichier principal est limitée, exécutez :
ulimit -c unlimited
pour le rendre illimité.
Ensuite, testez à nouveau, si le core dump réussit, vous verrez « (core dumped) » après l'indication d'erreur de segmentation comme ci-dessous :
Défaut de segmentation :11 (core dumpé)
Voir également: core dumped - mais le fichier core n'est pas dans le répertoire courant ?
Ubuntu
Dans Ubuntu, les core dumps sont gérés par Apport et peut être situé dans /var/crash/
.Cependant, il est désactivé par défaut dans les versions stables.
Pour plus de détails, veuillez vérifier : Où puis-je trouver le core dump dans Ubuntu ?.
macOS
Pour macOS, voir : Comment générer des core dumps sous Mac OS X ?
Peut-être pourriez-vous le faire de cette façon, ce programme est une démonstration de la façon de détecter une erreur de segmentation et de l'envoyer à un débogueur (il s'agit du code original utilisé sous AIX
) et imprime la trace de la pile jusqu'au point d'erreur de segmentation.Vous devrez changer le sprintf
variable à 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 devrez peut-être ajouter un paramètre supplémentaire pour que gdb vide le noyau, comme indiqué ici dans ce blog. ici.
D'autres éléments peuvent influencer la génération d'un core dump.J'ai rencontré ceux-ci :
- le répertoire du dump doit être accessible en écriture.Par défaut, il s'agit du répertoire courant du processus, mais cela peut être modifié en définissant
/proc/sys/kernel/core_pattern
. - dans certaines conditions, la valeur du noyau dans
/proc/sys/fs/suid_dumpable
peut empêcher la génération du noyau.
Il existe d'autres situations pouvant empêcher la génération qui sont décrites dans la page de manuel - essayez man core
.
Pour activer le core dump, procédez comme suit :
Dans
/etc/profile
commentez la ligne :# ulimit -S -c 0 > /dev/null 2>&1
Dans
/etc/security/limits.conf
commentez la ligne :* soft core 0
exécuter la cmd
limit coredumpsize unlimited
et vérifie-le avec 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 le corefile est écrit, vous pouvez tuer le processus associé avec cmd
kill -s SEGV <PID>
(ne devrait pas être nécessaire, juste au cas où aucun fichier principal ne serait écrit, cela peut être utilisé comme vérification) :# kill -s SEGV <PID>
Une fois le corefile écrit, assurez-vous de désactiver à nouveau les paramètres de coredump dans les fichiers associés (1./2./3.) !
Pour Ubuntu 14.04
Vérifiez le core dump activé :
ulimit -a
L'une des lignes doit être :
core file size (blocks, -c) unlimited
Sinon :
gedit ~/.bashrc
et ajouterulimit -c unlimited
à la fin du fichier et enregistrez, réexécutez le terminal.Construisez votre application avec les informations de débogage :
Dans le Makefile
-O0 -g
Exécutez l'application qui crée un vidage de mémoire (le fichier de vidage de mémoire portant le nom « core » doit être créé à proximité du fichier nom_application) :
./application_name
Exécuter sous gdb :
gdb application_name core
Par défaut, vous obtiendrez un fichier core.Vérifiez que le répertoire actuel du processus est accessible en écriture, sinon aucun fichier principal ne sera créé.
Mieux vaut activer le core dump par programme à l'aide d'un 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));
}
Attendez.C’est automatiquement le cas.Pas besoin de le faire
Il convient de mentionner que si vous avez un système mis en place, alors les choses sont un peu différentes.Dans la configuration, les fichiers principaux seraient généralement redirigés, au moyen de core_pattern
valeur sysctl, via systemd-coredump(8)
.La limite de taille du fichier principal serait généralement déjà configurée comme "illimitée".
Il est alors possible de récupérer les core dumps en utilisant coredumpctl(1)
.
Le stockage des core dumps, etc.est configuré par coredump.conf(5)
.Il existe des exemples sur la manière d'obtenir les fichiers principaux dans la page de manuel coredumpctl, mais en bref, cela ressemblerait à ceci :
Recherchez le fichier principal :
[vps@phoenix]~$ coredumpctl list test_me | tail -1
Sun 2019-01-20 11:17:33 CET 16163 1224 1224 11 present /home/vps/test_me
Obtenez le fichier principal :
[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163