Comment lisez-vous un message de journal du kernel segfault?

Cela peut être une question très simple, je tente de déboguer une application qui génère l’erreur kern.log suivante dans le kern.log

kernel: myapp[15514]: segfault at 794ef0 ip 080513b sp 794ef0 error 6 in myapp[8048000+24000]

Voici mes questions:

  1. Y a-t-il une documentation indiquant quels sont les numéros d’erreur diff sur segfault, dans ce cas, il s’agit de l’erreur 6, mais j’ai vu l’erreur 4, 5

  2. Quelle est la signification de l’information at bf794ef0 ip 0805130b sp bf794ef0 and myapp[8048000+24000] ?

Jusqu’à présent, j’ai pu comstackr avec des symboles, et quand je fais un x 0x8048000+24000 il renvoie un symbole, est-ce la bonne façon de le faire? Mes hypothèses à ce jour sont les suivantes:

  • sp = pointeur de stack?
  • ip = pointeur d’instruction
  • à = ????
  • myapp [8048000 + 24000] = adresse du symbole?

Lorsque le rapport pointe vers un programme, pas une bibliothèque partagée

Exécutez addr2line -e myapp 080513b (et répétez pour les autres valeurs de pointeur d’instruction fournies) pour voir où l’erreur se produit. Mieux vaut obtenir une version instrumentée pour le débogage et reproduire le problème sous un débogueur tel que gdb.

Si c’est une bibliothèque partagée

Dans la partie libfoo.so[NNNNNN+YYYY] , NNNNNN est l’endroit où la bibliothèque a été chargée. Soustrayez ceci du pointeur d’instruction ( ip ) et vous obtiendrez le décalage dans le .so de l’instruction incriminée. Ensuite, vous pouvez utiliser objdump -DCgl libfoo.so et rechercher l’instruction à ce décalage. Vous devriez facilement être en mesure de déterminer la fonction à partir des étiquettes d’asm. Si le .so ne dispose pas d’optimisations, vous pouvez également essayer d’utiliser addr2line -e libfoo.so .

Que signifie l’erreur

Voici la répartition des champs:

  • address – l’emplacement en mémoire auquel le code tente d’accéder (il est probable que 10 et 11 soient des décalages à partir d’un pointeur que nous attendons à être défini sur une valeur valide, mais qui pointe vers 0 )
  • pointeur d’instruction ip , c.-à-d. où le code qui tente de faire cela vit
  • sp – pointeur de stack
  • error – Drapeaux spécifiques à l’architecture; voir arch/*/mm/fault.c pour votre plate-forme.

D’après mes connaissances limitées, vos hypothèses sont correctes.

  • sp = pointeur de stack
  • ip = pointeur d’instruction
  • myapp[8048000+24000] = adresse

Si je déboguais le problème, je modifierais le code pour produire un core dump ou enregistrer un backtrace de stack sur le crash. Vous pouvez également exécuter le programme sous (ou attacher) GDB.

Le code d’erreur est simplement le code d’erreur architectural pour les défauts de page et semble être spécifique à l’architecture. Ils sont souvent documentés dans arch/*/mm/fault.c dans les sources du kernel. Ma copie de Linux/arch/i386/mm/fault.c a la définition suivante pour error_code:

  • bit 0 == 0 signifie qu’aucune page n’a été trouvée, 1 signifie un défaut de protection
  • bit 1 == 0 signifie lire, 1 signifie écrire
  • bit 2 == 0 signifie kernel, 1 signifie mode utilisateur

Ma copie de Linux/arch/x86_64/mm/fault.c ajoute ce qui suit:

  • bit 3 == 1 signifie que la faute était une instruction

Si c’est une bibliothèque partagée

Tu es malheureusement arraché; Il n’est pas possible de savoir où les bibliothèques ont été placées en mémoire par l’éditeur de liens dynamic après le fait .

Eh bien, il y a toujours une possibilité de récupérer les informations, pas à partir du binary, mais à partir de l’object. Mais vous avez besoin de l’adresse de base de l’object. Et cette information est toujours dans le coredump, dans la structure link_map.

Donc, vous voulez d’abord importer la struct link_map dans GDB. Donc, compilons un programme avec le symbole de débogage et ajoutons-le à la BDG.

link.c

 #include  toto(){struct link_map * s = 0x400;} 

get_baseaddr_from_coredump.sh

 #!/bin/bash BINARY=$(which myapplication) IsBinPIE () { readelf -h $1|grep 'Type' |grep "EXEC">/dev/null || return 0 return 1 } Hex2Decimal () { export number="`echo "$1" | sed -e 's:^0[xX]::' | tr '[af]' '[AF]'`" export number=`echo "ibase=16; $number" | bc` } GetBinaryLength () { if [ $# != 1 ]; then echo "Error, no argument provided" fi IsBinPIE $1 || (echo "ET_EXEC file, need a base_address"; exit 0) export totalsize=0 # Get PT_LOAD's size segment out of Program Header Table (ELF format) export sizes="$(readelf -l $1 |grep LOAD |awk '{print $6}'|tr '\n' ' ')" for size in $sizes do Hex2Decimal "$size"; export totalsize=$(expr $number + $totalsize); export totalsize=$(expr $number + $totalsize) done return $totalsize } if [ $# = 1 ]; then echo "Using binary $1" IsBinPIE $1 && (echo "NOT ET_EXEC, need a base_address..."; exit 0) BINARY=$1 fi gcc -g3 -fPIC -shared link.c -o link.so GOTADDR=$(readelf -S $BINARY|grep -E '\.got.plt[ \t]'|awk '{print $4}') echo "First do the following command :" echo file $BINARY echo add-symbol-file ./link.so 0x0 read echo "Now copy/paste the following into your gdb session with attached coredump" cat <l_addr) printf "add-symbol-file .%s %#.08x\n", \$mylinkmap->l_name, \$mylinkmap->l_addr end set \$mylinkmap = \$mylinkmap->l_next end 

il vous affichera tout le contenu link_map, dans un ensemble de commandes GDB.

Si elle semble anormale, mais avec le fichier base_addr de l’object partagé dont nous sums en train de parler, vous pourriez obtenir plus d’informations d’une adresse en déboguant directement l’object partagé impliqué dans une autre instance GDB. Gardez le premier gdb pour avoir une idée du symbole.

REMARQUE: le script est plutôt incomplet Je suppose que vous pouvez append au deuxième paramètre de add-symbol-file imprimé la sum avec cette valeur:

 readelf -S $SO_PATH|grep -E '\.text[ \t]'|awk '{print $5}' 

où $ SO_PATH est le premier argument du fichier add-symbol

J’espère que cela aide