utilisation des core dump sous linux

13
Utilisation des core dump Thierry GAYET Lorsque l'on développe, il peut parfois être utile de récupérer le contexte mémoire qui a été à l'origine de la terminaison anormale d'un programme. Il est donc possible de demander la génération d'un core dump qui pourra être chargé dans un débugger comme gdb pour analyse. 1. Définition Avec un débogueur post-mortem comme gdb, il est possible d'analyser l'état d'exécution d'un logiciel après un crash. L'analyse se fait sur la base d'un fichier core qui est une copie du contenu de la mémoire du programme au moment de son crash. Ce fichier est aussi appelé « core dump ». L'action par défaut de certains signaux est de forcer un processus à se terminer et de produire un fichier core dump, un fichier disque contenant une image de la mémoire du processus au moment où de sa terminaison. Dans la liste des signaux possible, les suivants ont pour action de générer des core dump : Signal Valeur Commentaire SIGQUIT 3 Demande « Quitter » depuis le clavier SIGILL 4 Instruction illégale SIGABRT 6 Signal d'arrêt depuis abort SIGFPE 8 Erreur mathématique virgule flottante. SIGSEGV 11 Référence mémoire invalide SIGSYS 12,-,12 Mauvais argument de fonction (SVr4) SIGTRAP 5 Point d'arrêt rencontré SIGXCPU 24,24,30 Limite de temps CPU dépassée (4.2BSD). SIGXFSZ 25,25,31 Taille de fichier excessive (4.2BSD) Jusqu'au Linux 2.2 inclus, l'action par défaut pour SIGSYS, SIGXCPU, SIGXFSZ, et (sur les architectures autres que Sparc ou Mips) SIGBUS était de terminer simplement le processus, sans fichier core. (Sur certains Unix, l'action par défaut pour SIGXCPU et SIGXFSZ est de finir le processus sans fichier core). Linux 2.4 se conforme à POSIX.1-2001 pour ces signaux, et termine le processus avec un fichier core. SIGEMT n'est pas spécifié par POSIX.1-2001 mais apparaît néanmoins sur la plupart des Unix, avec une action par défaut typique correspondant à une fin du processus avec fichier core. 2. Vérifications de la config. système Au préalable, il faut vérifier si les capacités du système permette la génération de fichier core dump. Pour ce faire, la commande ulimit permet de connaître les limites associées aux utilisateurs : $ ulimit -a core file size (blocks, -c) unlimited

Transcript of utilisation des core dump sous linux

Page 1: utilisation des core dump sous linux

Utilisation des core dumpThierry GAYET

Lorsque l'on développe, il peut parfois être utile de récupérer le contexte mémoire qui a été à l'origine de la terminaison anormale d'un programme. Il est donc possible de demander la génération d'un core dump qui pourra être chargé dans un débugger comme gdb pour analyse.

1. Définition

Avec un débogueur post-mortem comme gdb, il est possible d'analyser l'état d'exécution d'un logiciel après un crash. L'analyse se fait sur la base d'un fichier core qui est une copie du contenu de la mémoire du programme au moment de son crash. Ce fichier est aussi appelé « core dump ».

L'action par défaut de certains signaux est de forcer un processus à se terminer et de produire un fichier core dump, un fichier disque contenant une image de la mémoire du processus au moment où de sa terminaison.

Dans la liste des signaux possible, les suivants ont pour action de générer des core dump :

Signal Valeur Commentaire

SIGQUIT 3 Demande « Quitter » depuis le clavier

SIGILL 4 Instruction illégale

SIGABRT 6 Signal d'arrêt depuis abort

SIGFPE 8 Erreur mathématique virgule flottante.

SIGSEGV 11 Référence mémoire invalide

SIGSYS 12,-,12 Mauvais argument de fonction (SVr4)

SIGTRAP 5 Point d'arrêt rencontré

SIGXCPU 24,24,30 Limite de temps CPU dépassée (4.2BSD).

SIGXFSZ 25,25,31 Taille de fichier excessive (4.2BSD)

Jusqu'au Linux 2.2 inclus, l'action par défaut pour SIGSYS, SIGXCPU, SIGXFSZ, et (sur les architectures autres que Sparc ou Mips) SIGBUS était de terminer simplement le processus, sans fichier core. (Sur certains Unix, l'action par défaut pour SIGXCPU et SIGXFSZ est de finir le processus sans fichier core). Linux 2.4 se conforme à POSIX.1-2001 pour ces signaux, et termine le processus avec un fichier core.

SIGEMT n'est pas spécifié par POSIX.1-2001 mais apparaît néanmoins sur la plupart des Unix, avec une action par défaut typique correspondant à une fin du processus avec fichier core.

2. Vérifications de la config. système

Au préalable, il faut vérifier si les capacités du système permette la génération de fichier core dump. Pour ce faire, la commande ulimit permet de connaître les limites associées aux utilisateurs :

$ ulimit -a

core file size (blocks, -c) unlimited

Page 2: utilisation des core dump sous linux

data seg size (kbytes, -d) unlimited

scheduling priority (-e) 0

file size (blocks, -f) unlimited

pending signals (-i) 31477

max locked memory (kbytes, -l) 64

max memory size (kbytes, -m) unlimited

open files (-n) 1024

pipe size (512 bytes, -p) 8

POSIX message queues (bytes, -q) 819200

real-time priority (-r) 0

stack size (kbytes, -s) 8192

cpu time (seconds, -t) unlimited

max user processes (-u) 31477

virtual memory (kbytes, -v) unlimited

file locks (-x) unlimited

La première valeur est la plus importante concernant la génération de fichier core dump.

Si cette valeur est déjà positionnée à unlimited, il n'y a rien à faire. Dans le cas contraire il faut modifier cette limite de façon à éviter la création de core dump tronqués. Le modification de cette valeur peut être soit spécifique aux core dump ou bien globale à toutes les valeurs :

$ ulimit -c unlimited

On peut aussi contrôler les limites soft et hard :

$ ulimit -Sc

# ulimit -Hc

ou plus globalement :

$ ulimit unlimited

3. Configuration

Le noyau pouvant inclure ou non la fonctionnalité de générer des core dump, il faudra vérifier dans les sources du noyau GNU/Linux

General setup --->

Configure standard kernel features (for small systems) --->

Enable ELF core dumps

Pour les systèmes orienté linux embarqué, il faudra également vérifier la configuration d'autres briques logicielles :

• uClibc : activer le mode debug

La librairie uClibc doit être configuré différemment dans le but de supporter les backtrace. Si les applications sont multi-threadés vous aurez besoin d'activer la configuration suivante :

General Library Settings --->

Page 3: utilisation des core dump sous linux

Build pthreads debugging support

Il faudra également configurer uClibc pour désactiver le stripping de la librairie de façon à garder ses symboles :

uClibc development/debugging options --->

Strip libraries and executables

Enable Core Dump support in Busybox

• Busybox :

La busybox fournit le processus d'init du système qui est le père de tous les processus. La busybox peut aussi être configurer pour supporter les core dump pour tous fils (par héritage).

Acivez premièrement la configuration suivante :

Init Utilities --->

Support dumping core for child processes (debugging only)

Ensuite, creez un fichier vide à la racine du système de fichier du device avec le nom suivant :

“.init_enable_core“.

4. Modification à chaud des limites

Malgré ces limites systèmes, un processus peut connaître et redéfinir ses limites associé à ses ressources logicielle RLIMIT_CORE pour établir une limite haute sur la taille du fichier core dump qu'il produirait s'il recevait un signal qui aurait comme action de générer un fichier core dump.

RLIMIT_CORE définit donc la taille maximum du fichier core. Lorsqu'elle vaut zéro, aucun fichier d'image noyau (Ndt : core dump) n'est créé. Lorsqu'elle ne vaut pas zéro, les fichiers d'image noyau plus grands sont tronqués à cette taille.

La première étape consiste à activer la fonctionnalité par l'appel système prctl(). Le premier flag signifie si on lit ou modifie l'état et le second indique si le processus courant est « dumpable » (1-oui, 0-non).

Exemple d'usage :#include <sys/prctl.h>

int ret;

/* Vérifie l'état associé à la fonctionnalité des core dump */ ret = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); printf("PR_GET_DUMPABLE returned %d", ret);

/* Active la fionctionnalité des core dump */ret = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); printf("PR_SET_DUMPABLE returned %d", ret);

/* Vérifie l'état associé à la fonctionnalité des core dump après modification */ ret = prctl( PR_GET_DUMPABLE, 0, 0, 0, 0 ); printf( "PR_GET_DUMPABLE returned %d", ret );

Page 4: utilisation des core dump sous linux

La seconde étape de l'utilisation manuelle (via programmation) d'un core dump est de mofifier ses limites via l'appel système setrlimit() via la flag RLIMIT_CORE. Cette fonction prend en entrée une structure de données comportant deux champs. Le premier défini la limitation courante et le second la limitation maximale autorisé. Pour une limite non-limitée, il faut définir les deux valeurs de la structure à « RLIM_INFINITY ».

Exemple d'usage :#include <sys/time.h> #include <sys/resource.h>

int ret; struct rlimit rlim;

/* Vérifie la limitation associé aux core dump */ ret = getrlimit(RLIMIT_CORE, &rlim); printf("RLIMIT_CORE returned %d (%d, %d)", ret, rlim.rlim_cur, rlim.rlim_max);

/* Positionne les limitations associés aux core dump à unlimited */ rlim.rlim_cur = RLIM_INFINITY; rlim.rlim_max = RLIM_INFINITY; ret = setrlimit(RLIMIT_CORE, &rlim); printf("RLIMIT_CORE returned %d", ret);

/* Revérifie la limitation associé aux core dump après modification des limites */ ret = getrlimit(RLIMIT_CORE, &rlim); printf("RLIMIT_CORE returned %d (%d, %d)", ret, rlim.rlim_cur, rlim.rlim_max);

5. Personnalisation

Le noyau Linux propose plusieurs paramètres pour les core dump :

/proc/sys/kernel/core_pattern :

Par défaut, un fichier core dump est nommé core, mais le fichier /proc/sys/kernel/core_pattern (Depuis Linux 2.6 et 2.4.21) peut être configuré pour définir un modèle qui sera utilisé pour nommer les fichiers core dump.

Le modèle peut contenir des spécificateurs qui seront substitués par les valeurs suivantes lors de la création d'un fichier core dump :

%% Le caractère % si nécessaire

%p PID du processus « dumpé »

%u UID réel du processus « dumpé »

%g GID réel du processus « dumpé »

%s Numéro du signal ayant provoqué le « dump »

%t Heure du « dump » (secondes depuis le 1er janvier 1970, 00H00)

%h Nom d'hôte (pareil que 'nodename' renvoyé par uname(2))

%e Nom du fichier exécutable

Un seul % à la fin du modèle est rejeté du nom du fichier core comme si c'était la combinaison d'un % suivi par n'importe quel caractère autre que ceux listés ci-dessus. Tous les autres

Page 5: utilisation des core dump sous linux

caractères dans le modèle deviennent une partie littérale du nom de fichier core.

Le modèle peut comporter des caractères « / » qui seront interprétés comme des délimiteurs de noms de répertoires. La taille maximum du nom de fichier core résultant est 64 octets. La valeur par défaut dans ce fichier est « core ». Pour rétrocompatibilité, si /proc/sys/kernel/core_pattern n'inclut pas « %p » et si /proc/sys/kernel/core_uses_pid (voir plus loin) n'est pas nul, .PID sera ajouté au nom du fichier core.

Depuis la version 2.4, Linux fournit également /proc/sys/kernel/core_pattern, une méthode plus primitive de contrôle du nom du fichier core dump. Si le fichier /proc/sys/kernel/core_uses_pid contient la valeur 0, le fichier core dump est simplement nommé core. Si ce fichier contient une valeur non nulle, le fichier core dump inclura le PID dans un nom de la forme core.PID.

Ce paramètre permet de personnaliser un traitement lors de la traitement d'un core dump. Cela peut soit aboutir à la génération d'un fichier core ou core.PID, ou bien lancer un programme. Si le premier caractère est un pipe « | », le ligne est vu comme un programme a exécuter plutôt qu'une ligne à écrire.

Contraintes :

• Le programme doit avoir spécifier un chemin absolu depuis la racine du système de fichiers ;

• Le processus à exécuter, doit pouvoir être lancé sur les droits « utilisateur » et avec un groupe « root » ;

• Les arguments spécifiés au programmes sur la ligne de commandes (depuis 2.6.24) doivent être délimités par des espaces. La ligne ne doit pas excéder 128 octets ;

• Les arguments de la ligne de commande peut inclure les specificateurs à base de « % ». Par exemple, pour passer le PID au processus, il faut spécifier %p en argument.

Quelques exemple d'usages :

• |/usr/share/apport/apport %p %s %c : envoie le dump mémoire au programme append

• core : génère simplement un fichier core

Autre exemple pratique :

$ sudo mkdir -p /tmp/cores

$ sudo chmod a+rwx /tmp/cores

$ sudo echo "/tmp/cores/core.%e.%p.%h.%t" > /proc/sys/kernel/core_pattern

Pour que cela soit permanent, il suffit d'ajouter la ligne suivant au fichier de configuration « /etc/sysctl.conf » :

kernel.core_pattern=/tmp/cores/core.%e.%p.%h.%t

Pour réaliser un programme gérant les core dump, nous allons mettre en place un exemple pratique.

Partons du code source suivant « core_test.c » :

#define _GNU_SOURCE#include <sys/stat.h>#include <fcntl.h>#include <limits.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>

#define BUF_SIZE 1024

Page 6: utilisation des core dump sous linux

intmain(int argc, char *argv[]){ int tot, j; ssize_t nread; char buf[BUF_SIZE]; FILE *fp; char cwd[PATH_MAX];

/* Change our current working directory to that of the crashing process */

snprintf(cwd, PATH_MAX, "/proc/%s/cwd", argv[1]); chdir(cwd);

/* Write output to file "core.info" in that directory */

fp = fopen("core.info", "w+"); if (fp == NULL) exit(EXIT_FAILURE);

/* Display command-line arguments given to core_pattern pipe program */

fprintf(fp, "argc=%d\n", argc); for (j = 0; j < argc; j++) fprintf(fp, "argc[%d]=<%s>\n", j, argv[j]);

/* Count bytes in standard input (the core dump) */

tot = 0; while ((nread = read(STDIN_FILENO, buf, BUF_SIZE)) > 0) tot += nread; fprintf(fp, "Total bytes in core dump: %d\n", tot);

exit(EXIT_SUCCESS);}

Buildons le et incluons le dans la chaine lors de la génération d'un fichier core :

$ gcc core_test.c -o core_test

$ su

# echo "|$PWD/core_test %p UID=%u GID=%g sig=%s" > /proc/sys/kernel/core_pattern

# exit

Rejouons le core dump de façon à obtenir un fichier texte core.info en plus du fichier core :

$ ./coredump

Erreur de segmentation (core dumped)

Le core dump est bien présent :

$ ls -al core.1282

-rw-rw-r-- 1 tgayet tgayet 2046480 août 6 16:20 core.1282

$ file core.1282

core.1282: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from 'coredump'

Tout comme le fichier texte :

$ ls -al core.info

-rw-rw---- 1 root root 166 août 6 16:45 core.info

Page 7: utilisation des core dump sous linux

$ sudo file core.info

core.info: ASCII text

$ sudo cat core.info

[sudo] password for tgayet:

argc=5

argc[0]=</home/tgayet/workspace/core_pattern_pipe_test>

argc[1]=<2134>

argc[2]=<UID=1000>

argc[3]=<GID=1000>

argc[4]=<sig=11>

Total bytes in core dump: 204800

/proc/sys/kernel/core_uses_pid

Depuis la version 2.4, Linux fourni une méthode permettant de contrôler le nom du fichier core dump. Si le fichier /proc/sys/kernel/core_uses_pid contient la valeur 0, les fichiers core dump seront simplement nommé « core ». Dans le cas contraire, pour toute autre valeur non nulle, le fichier core dump comprendra l'ID du processus dans un nom généré comme core.PID.

/proc/sys/fs/suid_dumpable

Depuis Linux 2.6.13, la valeur de ce fichier détermine si les fichiers core dump sont produit pour set-user-ID ou autrement binaires protégés. Trois valeurs entières peuvent être spécifiées:

• 0 (par défaut) Ceci fournit le comportement traditionnel (pré-Linux 2.6.13). Un core dump ne sera pas produit d'un processus qui a changé ses droits (en appelant seteuid (2), setgid (2), ou similaire, ou en exécutant un set-user-ID ou le programme set-group-ID) ou dont le binaire n'a pas l'autorisation en lecture.

• 1 ("debug") tous les processus peuvent générer des core dump si possible. Le core dump aura les droits du processus ayant généré le dump. La sécurité n'est pas appliquée. Ce système est destiné aux siuations de debug.

• 2 ("suidsafe") Tout binaire ne génèrons pas de core dump (voir «0» ci-dessus). S'il est généré, le code dump sera en lecture seule par root. Cela permet à l'utilisateur de le supprimer mais pas de le lire pour des raisons de sécurité des vidages de la mémoire.

/proc/<pid>/coredump_filter

Quand la mémoire d'un processus est dumpé, toute la mémoire anonyme est écrite dans le fichier core tant que le fichier n'a pas atteint sa limite. Parfois, il peut être utile que certain segment de mémoire ne soient pas dumpés, par exemple avec de grosses zones de mémoires partagés.

D'un autre coté, on peut vouloir sauvegarder des segments de mémoire spécifique dans le fichier core.

/proc/<pid>/coredump_filter nous permet de personnaliser quel segment de mémoire doit être sauvegardé au moment de la génération d'un core dump. coredump_filter est un masque de bits des types de mémoires en charge. Si un des bits du masque est activé, le segment de mémoire correspondant est dumpé.

Les 7 types de mémoires suivantes sont supportés :

Page 8: utilisation des core dump sous linux

bit n°0 : mémoire anonyme privée

bit n°1 : mémoire anonyme partagée

bit n°2 : mémoire file-backed privée

bit n°3 : mémoire file-backed partagée

bit n°4: pages du header ELF dans la zone de mémoire file-backed privée (effectif seulement si le bit 2 n'est pas positionné)

bit n°5 : mémoire hugetlb privée

bit n°6 : mémoire hugetlb partagée

A noter que les pages MMIO tel qu'un framebuffer ne sont jamais dumpés alors que le pages VDSO le sont toujours indépendamment du status du masques de bits.

Les bits de 0 à 4 du masque n'ont aucun effet sur lé mémoire hugetlb qui sont plus affecté avec les bits 5 et 6.

La valeur par défaut pour un core dump est 0x23 ce qui signifie que tous les segments de mémoire partagée (privée et partagé) ainsi que la mémoire hugetlb privée.

Pour tout activer, il suffit de mettre tous les bits à 1 ce qui donne 0xFF :

$ echo 0xF > /proc/<pid>/coredump_filter

Si vous ne voulez pas dumper toute la mémoire partagée pour un processus donné dont le pid est 1234, vous pouvez changer les propriétés du processus directement :

$ echo 0x21 > /proc/1234/coredump_filter

Quand un nouveau processus est crée, il hérite son masque du processus parent. Il peut donc être utille de positionner coredump_filter avant de lancer un binaire :

$ echo 0x7 > /proc/self/coredump_filter

$ ./my_bin

Pour que cette option soit présente, il faut que le noyau ait été compilé avec l'option CONFIG_ELF_CORE.

6. Tests du support des core dump

Testons maintenant le bon fonctionnement de la génération d'un core dump :

$ sudo mkdir -p `pwd`/cores

$ sudo chmod a+rwx `pwd`/cores

$ sudo echo "`pwd`/cores/core.%e.%p.%h.%t" > /proc/sys/kernel/core_pattern

Écrivons un petit code de test « $ gcc -Wall -g -o coredump coredump.c » : #include <stdio.h>

int main(void) {

char *foo = (char*)0x12345; *foo = 'a'; return 0;

}

Générons le binaire à partir du code source :

$ gcc -Wall -g coredump.c -o coredump

Exécutons le :

$ ./coredump

Page 9: utilisation des core dump sous linux

Segmentation fault (core dumped)

On remarque la mention entre parenthèse (core dumped) qui spécifie que le handle de signal par défaut à été activé suite à la réception d'un signal d'erreur ce qui a entraîne la génération d'un fichier core dump.

Ce test est trivial, mais pour simuler la réception d'un signal d'erreur au processus ayant le PID 1234, nous aurions pu envoyer un signal à ce dernier de deux façon possible :

$ kill -11 1234

ou

$ kill -s SIGEGV 1234

On vérifie en effet que le fichier a bien été crée suivant le nommage et le path demandé :

$ tree cores/

cores/

└── core.coredump.31788.tgayet-desktop.1375796915

0 directories, 1 file

$ ls -al cores/core.coredump.31788.tgayet-desktop.1375796915

-rw------- 1 tgayet tgayet 204800 août 6 15:48 cores/core.coredump.31788.tgayet-desktop.1375796915

$ file cores/core.coredump.31788.tgayet-desktop.1375796915

cores/core.coredump.31788.tgayet-desktop.1375796915: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from './coredump'

On peut même tester de le charger dans gdb :

$ gdb ./coredump cores/core.coredump.31788.tgayet-desktop.1375796915

GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04

Copyright (C) 2012 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law. Type "show copying"

and "show warranty" for details.

This GDB was configured as "i686-linux-gnu".

For bug reporting instructions, please see:

<http://bugs.launchpad.net/gdb-linaro/>...

Reading symbols from /home/tgayet/workspace/coredump...done.

[New LWP 31788]

warning: Can't read pathname for load map: Erreur d'entrée/sortie.

Core was generated by `./coredump'.

Program terminated with signal 11, Segmentation fault.

#0 0x080483c4 in main () at coredump.c:6

6 *foo = 'a';

(gdb)

Le debugueur gdb, nous positionne bien sur la ligne ayant généré le problème.

La commande readelf nous donne quelques informations intéressantes :

$ readelf --all cores/core.coredump.31788.tgayet-desktop.1375796915

ELF Header:

Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00

Page 10: utilisation des core dump sous linux

Class: ELF32

Data: 2's complement, little endian

Version: 1 (current)

OS/ABI: UNIX - System V

ABI Version: 0

Type: CORE (Core file)

Machine: Intel 80386

Version: 0x1

Entry point address: 0x0

Start of program headers: 52 (bytes into file)

Start of section headers: 0 (bytes into file)

Flags: 0x0

Size of this header: 52 (bytes)

Size of program headers: 32 (bytes)

Number of program headers: 15

Size of section headers: 0 (bytes)

Number of section headers: 0

Section header string table index: 0

There are no sections in this file.

There are no sections to group in this file.

Program Headers:

Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align

NOTE 0x000214 0x00000000 0x00000000 0x0022c 0x00000 0

LOAD 0x001000 0x08048000 0x00000000 0x00000 0x01000 R E 0x1000

LOAD 0x001000 0x08049000 0x00000000 0x01000 0x01000 R 0x1000

LOAD 0x002000 0x0804a000 0x00000000 0x01000 0x01000 RW 0x1000

LOAD 0x003000 0xb75d6000 0x00000000 0x01000 0x01000 RW 0x1000

LOAD 0x004000 0xb75d7000 0x00000000 0x00000 0x1a3000 R E 0x1000

LOAD 0x004000 0xb777a000 0x00000000 0x02000 0x02000 R 0x1000

LOAD 0x006000 0xb777c000 0x00000000 0x01000 0x01000 RW 0x1000

LOAD 0x007000 0xb777d000 0x00000000 0x03000 0x03000 RW 0x1000

LOAD 0x00a000 0xb77a1000 0x00000000 0x02000 0x02000 RW 0x1000

LOAD 0x00c000 0xb77a3000 0x00000000 0x01000 0x01000 R E 0x1000

LOAD 0x00d000 0xb77a4000 0x00000000 0x00000 0x20000 R E 0x1000

LOAD 0x00d000 0xb77c4000 0x00000000 0x01000 0x01000 R 0x1000

LOAD 0x00e000 0xb77c5000 0x00000000 0x01000 0x01000 RW 0x1000

LOAD 0x00f000 0xbf99e000 0x00000000 0x23000 0x23000 RW 0x1000

There is no dynamic section in this file.

Page 11: utilisation des core dump sous linux

There are no relocations in this file.

There are no unwind sections in this file.

No version information found in this file.

Notes at offset 0x00000214 with length 0x0000022c:

Owner Data size Description

CORE 0x00000090 NT_PRSTATUS (prstatus structure)

CORE 0x0000007c NT_PRPSINFO (prpsinfo structure)

CORE 0x000000a0 NT_AUXV (auxiliary vector)

LINUX 0x00000030 Unknown note type: (0x00000200)

7. Génération d'un core dump depuis GDB

Depuis la console de gdb, il est possible de charger en dynamique un core dump.

Chargeons gdb avec le binaire non strippé, c'est à dire avec ses symboles de débug et ses infos associées. Ensuite chargeons le core dump préalablement crée. Nous en générerons un autre juste après :

$ gdb ./coredump

GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04

Copyright (C) 2012 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law. Type "show copying"

and "show warranty" for details.

This GDB was configured as "i686-linux-gnu".

For bug reporting instructions, please see:

<http://bugs.launchpad.net/gdb-linaro/>...

Reading symbols from /home/tgayet/workspace/coredump...done.

(gdb) core cores/core.coredump.31788.tgayet-desktop.1375796915

[New LWP 31788]

warning: Can't read pathname for load map: Erreur d'entrée/sortie.

Core was generated by `./coredump'.

Program terminated with signal 11, Segmentation fault.

#0 0x080483c4 in main () at coredump.c:6

6 *foo = 'a';

(gdb) bt

#0 0x080483c4 in main () at coredump.c:6

Pour demander la génération d'un core dump, il suffit de saisir la commande « generate-core-file » :

(gdb) generate-core-file

Saved corefile core.1282

gdb donne l'info suivante :

Page 12: utilisation des core dump sous linux

(gdb) help generate-core-file

Save a core file with the current state of the debugged process.

Argument is optional filename. Default filename is 'core.<process_id>'

8. Accès à la RAM de Linux

L'accès à la mémoire sous linux peut être utile dans certain cas. Le noyau GNU/Linux propose le device /dev/core qui est un lien symbolique vers /proc/kcore. En réalité, c'est une sorte d'alias vers la mémoire de l'ordinateur.

Le fichier à la taille de la RAM physique donc peut être assez important, auquel il faut ajouter 4 ko.

Le format est un fichier ELF core standard.

Avec le dump mémoire globale et un noyau GNULinux non-strippé (avec ses symboles), gdb est en mesure de donner l'état du noyau incluant ses structures de données :

$ sudo gdb vmlinux /proc/kcore

... snip ...

(gdb) p jiffies_64

$1 = 4326692196

(gdb)

9. Problème de génération possible

Il y a diverses circonstances dans lesquelles un fichier core dump peut ne pas être produit :

• Le processus n'a pas la permission d'écrire le fichier core. (Par défaut, le fichier core est appelé core et est créé dans le répertoire de travail courant. Voir plus loin pour les détails de nommage du fichier.) L'écriture du fichier core échouera si le répertoire dans lequel il doit être créé n'est pas accessible en écriture, ou si un fichier du même nom existe déjà et n'est pas accessible en écriture ou si ce n'est pas un fichier régulier (par exemple, c'est un répertoire ou un lien symbolique) ;

• Un fichier (régulier, accessible en écriture) avec le même nom qui serait utilisé pour le fichier core existe déjà, mais il y a plus d'un lien matériel vers ce fichier ;

• Le système de fichiers où le fichier core devrait être créé est plein ; ou n'a plus d'i-noeud ; ou est monté en lecture seule ; ou l'utilisateur a atteint son quota dans le système de fichiers ;

• Le répertoire dans lequel le fichier core dump doit être créé n'existe pas ;

• Le fichier core_pattern nomme un répertoire ou un fichier existant sur lequel on n'a pas la permission d'écriture ;

• Les limites de ressources RLIMIT_CORE ou RLIMIT_FSIZE pour un processus valent zéro ;

• Le binaire devant être exécuté par le processus n'a pas la permission de lecture ;

• Le processus exécute un programme Set-UID (Set-GID) qui appartient à un utilisateur

/dev/core

/proc/core

Page 13: utilisation des core dump sous linux

(groupe) autre que l'UID (GID) réel du processus. Il faut voir la description PR_SET_DUMPABLE de prctl(2) ainsi que /proc/sys/fs/suid_dumpable dans proc(5).

10. Remarques

Si un processus multithread ou, plus précisément, un processus qui partage sa mémoire avec un autre processus qui a été créé avec l'attribut CLONE_VM de clone(2) créé un fichier core dump, le PID est toujours ajouté au nom du fichier core, à moins que le PID ne soit déjà inclus quelque part dans le nom de fichier via une spécification %p dans /proc/sys/kernel/core_pattern.

Malheureusement, si votre application est équipé d'un gestionnaire de signaux personnalisée, aucun core dump ne sera généré, car ils sont générés uniquement par les gestionnaires de signaux par défaut.

L'appel au gestionnaire par défaut peut être sollicité à la fin du handle de signal, mais sans que cela soit puisse suffire. Il vaut mieux en effet restaurer le gestionnaire personnalisé en phase de débug.

11. Conclusion

Avec les core dump, nous voilà muni d'un outil de choix, permettant d'investiguer en cas de crash.

12. Liens

• http://man7.org/linux/man-pages/man5/core.5.html • http://www.bottomupcs.com/elf.html#coredump_gdb • http://linux.die.net/man/5/proc • http://www.linuxcertif.com/man/7/signal/ • http://www.linuxcertif.com/man/5/core/ • http://www.linuxcertif.com/man/1/gdb/ • http://www.linuxcertif.com/man/2/getrlimit/ • http://web.cecs.pdx.edu/~jrb/ui/linux/driver4.txt • https://www.kernel.org/doc/Documentation/filesystems/proc.txt