Comment lire un message de log du noyau segfault

cela peut être une question très simple, j'essaie de déboguer une application qui génère l'erreur segfault 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. est-ce qu'il y a de la documentation sur ce que sont les nombres d'erreur diff sur segfault, dans ce cas c'est Erreur 6, mais j'ai vu erreur 4 ,5

  2. Que signifie l'information at bf794ef0 ip 0805130b sp bf794ef0 and myapp[8048000+24000] ?

Jusqu'à présent j'ai pu compiler 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 jusqu'à présent sont les suivantes:

  • sp = pointeur de pile?
  • ip = pointeur d'instruction
  • à = ????
  • myapp[8048000+24000] = adresse de symbole?
60
demandé sur Charles Duffy 2010-02-01 22:20:54

3 réponses

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

exécuter addr2line -e myapp 080513b (et répéter pour les autres valeurs de pointeur d'instruction données) pour voir où l'erreur se produit. Il est préférable d'obtenir une construction instrumentée par le débogage et de 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] , le NNNNNN est l'endroit où la bibliothèque a été chargée. Soustraire de la pointeur d'instruction ( ip ) et vous obtiendrez l'offset dans le .so de l'instruction incriminée. Ensuite, vous pouvez utiliser objdump -DCgl libfoo.so et rechercher l'instruction à cet offset. Vous devriez facilement être en mesure de comprendre quelle fonction il est à partir des étiquettes asm. Si le .so n'a pas optimisations, vous pouvez également essayer d'utiliser addr2line -e libfoo.so <offset> .

que signifie l'erreur

voici la répartition des champs:

  • address - l'emplacement dans la mémoire le code essaie d'accéder (il est probable que 10 et 11 sont des offsets d'un pointeur que nous nous attendons à être réglé à une valeur valide mais qui est plutôt pointé vers 0 )
  • ip - pointeur d'instruction, ie. d'où le code qui est en train de faire de cette vie
  • sp - pointeur de pile
  • error - Drapeaux spécifiques à l'Architecture; voir arch/*/mm/fault.c pour votre plate-forme.
39
répondu Charles Duffy 2014-05-08 18:08:39

D'après mes connaissances limitées, vos suppositions sont correctes.

  • sp = pointeur de pile
  • ip = pointeur d'instruction
  • myapp[8048000+24000] = adresse

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

le code d'erreur est juste le code d'erreur d'architecture pour les fautes de page et semble être spécifique à l'architecture. Ils sont souvent documentés dans arch/*/mm/fault.c dans le noyau source. Ma copie de Linux/arch/i386/mm/fault.c a la définition suivante pour error_code:

  • bit 0 = = 0 signifie aucune page trouvée, 1 signifie défaut de protection
  • bit 1 = = 0 signifie lire, 1 signifie écrire
  • bit 2 = = 0 signifie noyau, 1 signifie mode utilisateur

ma copie de Linux/arch/x86_64/mm/fault.c Ajoute ce qui suit:

  • bit 3 = = 1 signifie qu'un défaut était un fetch d'instruction
36
répondu jschmier 2017-05-23 11:54:53

si c'est une bibliothèque partagée

vous êtes drogué, malheureusement; il n'est pas possible de savoir où le les bibliothèques ont été placées en mémoire par le linker dynamique après le fait .

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

donc vous voulez d'abord importer la structure link_map dans GDB. Permet donc de compiler un programme avec lui avec le symbole de débogage et de l'ajouter à la GDB.

lien.c

#include <link.h>
toto(){struct link_map * s = 0x400;}

get_baseaddr_from_coredump.sh

#!/bin/bash

BINARY=$(which myapplication)

IsBinPIE ()
{
    readelf -h |grep 'Type' |grep "EXEC">/dev/null || return 0
    return 1
}

Hex2Decimal ()
{
    export number="`echo "" | sed -e 's:^0[xX]::' | tr '[a-f]' '[A-F]'`"
    export number=`echo "ibase=16; $number" | bc`
}

GetBinaryLength ()
{
    if [ $# != 1 ]; then
    echo "Error, no argument provided"
    fi
    IsBinPIE  || (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  |grep LOAD |awk '{print }'|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 "
    IsBinPIE  && (echo "NOT ET_EXEC, need a base_address..."; exit 0)
    BINARY=
fi

gcc -g3 -fPIC -shared link.c -o link.so

GOTADDR=$(readelf -S $BINARY|grep -E '\.got.plt[ \t]'|awk '{print }')

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 <<EOF
set $linkmapaddr = *(0x$GOTADDR + 4)
set $mylinkmap = (struct link_map *) $linkmapaddr
while ($mylinkmap != 0)
if ($mylinkmap->l_addr)
printf "add-symbol-file .%s %#.08x\n", $mylinkmap->l_name, $mylinkmap->l_addr
end
set $mylinkmap = $mylinkmap->l_next
end

il vous imprimera le contenu entier de link_map, dans un ensemble de la commande GDB.

lui-même il pourrait sembler unnesseray mais avec le base_addr de l'objet partagé dont nous parlons, vous pourriez obtenir plus d'informations à partir d'une adresse en déboguant directement l'objet partagé impliqué dans une autre instance GDB. Gardez le premier gdb à avoir une idee du symbole.

NOTE : le script est plutôt incomplet je soupçonne que vous pouvez ajouter au deuxième paramètre d'add-symbol-file imprimé la somme avec cette valeur:

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

où $ SO_PATH est le première l'argument de l'add-symbole-fichier

j'Espère que ça aide

6
répondu scripthelps 2012-06-06 17:14:26