61 votes

Comment avez-vous lu une erreur de segmentation du noyau du message de journal

Cela peut être une question très simple, je suis essayez de déboguer une application qui génère les éléments suivants erreur de segmentation d'erreur dans l' kern.log

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

Voici mes questions:

  1. Est-il de la documentation à ce que sont les diff numéros d'erreur sur erreur, dans ce cas, il est 6 erreur, mais j'ai vu d'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 été en mesure de compiler avec les symboles, et quand je fais un x 0x8048000+24000 il retourne un symbole, est-ce la bonne façon de le faire? Mes hypothèses à ce jour sont les suivants:

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

43voto

Charles Duffy Points 34134

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

Exécutez addr2line -e myapp 080513b (et répétez l'opération pour l'autre pointeur d'instruction valeurs) pour voir où est l'erreur qui se passe. Mieux, obtenir un debug-instrumentée de construire, et de reproduire le problème sous un débogueur tels que gdb.

Si c'est une bibliothèque partagée

Dans l' libfoo.so[NNNNNN+YYYY] partie, l' NNNNNN est où la bibliothèque a été chargé. Soustraire de le pointeur d'instruction (ip) et vous obtiendrez le décalage dans l' .so de la délinquance de l'instruction. Ensuite, vous pouvez utiliser objdump -DCgl libfoo.so et de recherche pour l'enseignement de la compenser. Vous devriez être facilement en mesure de comprendre la fonction c'est à partir de l'asm étiquettes. Si l' .so n'ont pas d'optimisations, vous pouvez également essayer d'utiliser addr2line -e libfoo.so <offset>.

L'erreur signifie

Voici la liste des champs:

  • address - l'emplacement en mémoire le code tente d'accès (il est probable que l' 10 et 11 sont des décalages à partir d'un pointeur, nous nous attendons à être fixé à une valeur valide, mais qui est plutôt pointant 0)
  • ip - pointeur d'instruction, c'est à dire. d'où le code qui est en train de faire de cette vie
  • sp - pointeur de pile
  • error - Architecture-des indicateurs spécifiques; voir arch/*/mm/fault.c pour votre plate-forme.

36voto

jschmier Points 8088

Basé sur mes connaissances limitées, vos hypothèses sont correctes.

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

Si je ont été de débogage, le problème, je voudrais modifier le code pour produire un core dump ou journal d'un stack trace sur le crash. Vous pouvez également exécuter le programme sous (ou joindre) GDB.

Le code d'erreur est juste de l'architecture code d'erreur pour les erreurs de page et semble être spécifiques à l'architecture. Ils sont souvent documentées dans arch/*/mm/fault.c dans le source du noyau. Ma copie de Linux/arch/i386/mm/fault.c est la définition suivante pour code_erreur:

  • bit 0 == 0 signifie aucune page trouvée, 1 signifie que la protection de l'anomalie
  • bit 1 == 0 signifie lire, 1 signifie écrire
  • bit 2 == 0 signifie que le noyau, 1 utilisateur-mode

Ma copie de Linux/arch/x86_64/mm/fault.c ajoute le suivant:

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

6voto

scripthelps Points 51

Si c'est une bibliothèque partagée

Vous êtes arrosé, malheureusement, il n'est pas possible de savoir où l' les bibliothèques ont été placés dans la mémoire par l'éditeur de liens dynamique après le fait.

Eh bien, il est encore possible de récupérer les informations, pas de la binaire, mais à partir de l'objet. Mais vous avez besoin de l'adresse de base de l'objet. Et cette information est encore dans le processus, dans le link_map structure.

Alors d'abord vous souhaitez importer la structure link_map dans GDB. Donc permet de compiler un programme avec des symboles de débogage et 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 $1|grep 'Type' |grep "EXEC">/dev/null || return 0
    return 1
}

Hex2Decimal ()
{
    export number="`echo "$1" | 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 $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 <<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 permet d'imprimer l'ensemble du link_map contenu, à l'intérieur d'un ensemble de commande GDB.

Il lui seul, il peut semble unnesseray mais avec le base_addr de l'objet partagé, nous sommes sur le point, vous risquez d'obtenir des informations un peu plus d'une adresse par debuging directement impliquées objet partagé dans un autre GDB instance. Garder la première gdb pour avoir une idee du symbole.

REMARQUE : le script est plutôt incomplète je soupçonne que vous pouvez ajouter à la deuxième paramètre de ajouter-symbole-fichier imprimé la somme avec cette valeur :

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

où $SO_PATH est le premier argument de l'add-symbole-fichier

J'espère que ça aide

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X