J'ai la trace de pile suivante. Est-il possible d'en faire quelque chose d'utile pour le débogage?
Program received signal SIGSEGV, Segmentation fault.
0x00000002 in ?? ()
(gdb) bt
#0 0x00000002 in ?? ()
#1 0x00000001 in ?? ()
#2 0xbffff284 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb)
Par où commencer à regarder le code lorsque nous obtenons un Segmentation fault
, et que la trace de la pile n'est pas si utile?
REMARQUE: Si je poste le code, les experts SO me donneront la réponse. Je veux suivre les conseils de SO et trouver la réponse moi-même, donc je ne poste pas le code ici. Toutes mes excuses.
-fno-omit-frame-pointer
? En outre, pour la corruption de la mémoire,valgrind
peut être un outil plus approprié, si c'est une option pour vous.Réponses:
Ces fausses adresses (0x00000002 et autres) sont en fait des valeurs PC, pas des valeurs SP. Maintenant, lorsque vous obtenez ce type de SEGV, avec une fausse (très petite) adresse PC, 99% du temps, c'est dû à un appel via un faux pointeur de fonction. Notez que les appels virtuels en C ++ sont implémentés via des pointeurs de fonction, donc tout problème avec un appel virtuel peut se manifester de la même manière.
Une instruction d'appel indirect pousse simplement le PC après l'appel sur la pile, puis définit le PC sur la valeur cible (faux dans ce cas), donc si c'est ce qui s'est passé, vous pouvez facilement l'annuler en faisant sortir manuellement le PC de la pile. . En code x86 32 bits, il vous suffit de faire:
Avec le code x86 64 bits dont vous avez besoin
Ensuite, vous devriez être capable de faire un
bt
et de déterminer où se trouve réellement le code.L'autre 1% du temps, l'erreur sera due à l'écrasement de la pile, généralement en débordant un tableau stocké sur la pile. Dans ce cas, vous pourrez peut-être obtenir plus de clarté sur la situation en utilisant un outil comme valgrind
la source
gdb executable corefile
ouvrira gdb avec l'exécutable et le fichier de base, à quel point vous pouvez le fairebt
(ou les commandes ci-dessus suivies debt
) ...sp
, pasesp
oursp
, et son instruction d'appel stocke l'adresse de retour dans lelr
registre, pas sur la pile. Donc, pour ARM, tout ce dont vous avez vraiment besoin pour annuler l'appel estset $pc = $lr
. Si$lr
n'est pas valide, vous avez un problème beaucoup plus difficile à résoudre.Si la situation est assez simple, la réponse de Chris Dodd est la meilleure. Il semble avoir sauté à travers un pointeur NULL.
Cependant, il est possible que le programme se soit tiré dans le pied, le genou, le cou et l'œil avant de s'écraser - il a écrasé la pile, a foiré le pointeur d'image et d'autres maux. Si tel est le cas, démêler le haschich ne vous montrera probablement pas des pommes de terre et de la viande.
La solution la plus efficace sera d'exécuter le programme sous le débogueur et de parcourir les fonctions jusqu'à ce que le programme se bloque. Une fois qu'une fonction en panne est identifiée, recommencez et entrez dans cette fonction et déterminez quelle fonction elle appelle provoque le crash. Répétez jusqu'à ce que vous trouviez la seule ligne de code incriminée. 75% du temps, le correctif sera alors évident.
Dans les 25% restants, la ligne de code dite offensante est un hareng rouge. Il réagira à des conditions (invalides) définies avant de nombreuses lignes, peut-être des milliers de lignes auparavant. Si tel est le cas, le meilleur cours choisi dépend de nombreux facteurs: principalement votre compréhension du code et votre expérience avec celui-ci:
printf
sur des variables critiques conduira au A ha!Bonne chance!
la source
En supposant que le pointeur de pile est valide ...
Il peut être impossible de savoir exactement où se produit le SEGV à partir de la trace arrière - je pense que les deux premiers cadres de pile sont complètement écrasés. 0xbffff284 semble être une adresse valide, mais les deux suivants ne le sont pas. Pour examiner de plus près la pile, vous pouvez essayer ce qui suit:
gdb $ x / 32ga $ rsp
ou une variante (remplacez le 32 par un autre numéro). Cela affichera un certain nombre de mots (32) à partir du pointeur de pile de taille géante (g), formatés en adresses (a). Tapez 'help x' pour plus d'informations sur le format.
Instrumenter votre code avec des 'printf' sentinelles n'est peut-être pas une mauvaise idée, dans ce cas.
la source
info symbol
façon de le faire dans gdb.x/256wa $sp
=)Regardez certains de vos autres registres pour voir si l'un d'eux a le pointeur de pile mis en cache. À partir de là, vous pourrez peut-être récupérer une pile. De plus, si cela est intégré, la pile est souvent définie à une adresse très particulière. En utilisant cela, vous pouvez également parfois obtenir une pile décente. Tout cela suppose que lorsque vous avez sauté dans l'hyperespace, votre programme n'a pas vomi de la mémoire en cours de route ...
la source
S'il s'agit d'un écrasement de pile, les valeurs peuvent bien correspondre à quelque chose de reconnaissable par le programme.
Par exemple, je me suis retrouvé à regarder la pile
et
0x342d
est 13357, qui s'est avéré être un identifiant de nœud lorsque j'ai saisi les journaux d'application pour cela. Cela a immédiatement aidé à réduire les sites candidats où l'écrasement de la pile aurait pu se produire.la source