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:
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
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:
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.
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
.
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
) 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:
Ma copie de Linux/arch/x86_64/mm/fault.c
ajoute ce qui suit:
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