128 votes

GDB corrompu frame de pile - Comment déboguer?

J'ai le texte suivant trace de la pile. Est-il possible de 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, quand nous recevons un Segmentation fault, et la trace de la pile n'est pas si utile?

REMARQUE: Si je poste le code, puis les experts, qui me donnera la réponse. Je veux prendre la direction de SI et de trouver la réponse moi-même, donc je ne suis pas poster le code ici. Des excuses.

162voto

Chris Dodd Points 39013

Ces fausses adresses (0x00000002), sont en fait des valeurs PC, pas de SP. Maintenant, quand vous obtenez ce genre de SEGV, avec un bidon (très petit) adresse du PC, 99% du temps c'est à cause d'appel par l'intermédiaire d'un bidon de pointeur de fonction. Notez que les appels virtuels en C++ sont mis en œuvre via des pointeurs de fonction, de sorte que tout problème avec un appel virtuel peuvent se manifester de la même manière.

Un appel indirect à l'instruction pousse juste le PC après l'appel sur la pile, puis de configurer le PC de la valeur cible (faux dans ce cas), donc si c' est ce qui s'est passé, vous pouvez facilement annuler manuellement en sautant le PC hors de la pile. En 32 bits x86 code que vous venez de faire:

(gdb) set $pc = *(void **)$esp
(gdb) set $esp = $esp + 4

Avec 64-bit x86 code dont vous avez besoin

(gdb) set $pc = *(void **)$rsp
(gdb) set $rsp = $rsp + 8

Ensuite, vous devriez être en mesure de faire une bt et le chiffre d'où le code est vraiment.

L'autre 1% du temps, l'erreur est due à l'écrasement de la pile, généralement par le débordement d'un tableau stocké sur la pile. Dans ce cas, vous pourriez être en mesure d'obtenir plus de clarté sur la situation en utilisant un outil comme valgrind

48voto

wallyk Points 33150

Si la situation est assez simple, Chris Dodd la réponse est la meilleure. Il ne ressemble, il a sauté par un pointeur NULL.

Toutefois, il est possible que le programme balle dans le pied, le genou, le cou, et les yeux avant de s'écraser—a remplacé la pile, foiré le pointeur de l'image, et d'autres maux. Si oui, alors démêler le hash n'est pas susceptible de vous montrer les pommes de terre et la viande.

La solution plus efficace sera d'exécuter le programme dans le débogueur, et l'étape sur les fonctions jusqu'à ce que le programme se bloque. Une fois un fracas de la fonction est identifiée, recommencer, et pas de plus dans cette fonction et de déterminer dans quelle fonction il appelle les causes de l'accident. Répétez jusqu'à ce que vous trouver la ligne de code malveillant. 75% du temps, le correctif sera alors évidente.

Dans les autres 25% des situations, la soi-disant ligne de code malveillant est un leurre. Il va réagir à (invalides) conditions de configurer le nombre de lignes avant—peut-être des milliers de lignes avant. Si c'est le cas, le meilleur choix dépend de nombreux facteurs: la plupart du temps votre compréhension du code et de l'expérience avec elle:

  • Peut-être un débogueur point d'observation ou de l'insertion de diagnostic printf's sur les variables critiques seront conduire à la nécessité d'Un ha!
  • Peut-être changer les conditions de tests avec différentes entrées de fournir plus de perspicacité que de débogage.
  • Peut-être une deuxième paire d'yeux va vous forcer à vérifier vos hypothèses ou de recueillir ignoré les éléments de preuve.
  • Parfois, il suffit d'aller dîner et de réflexion sur les preuves recueillies.

Bonne chance!

31voto

manabear Points 111

En supposant que le pointeur de pile est valide...

Il peut être impossible de savoir exactement où le SEGV se produit à partir de la trace -- je pense que les deux premières frames de pile sont complètement écrasés. 0xbffff284 semble être une adresse valide, mais les deux ne sont pas. Pour en savoir plus sur la pile, vous pouvez essayer ce qui suit:

gdb$ x/32ga $rsp

ou une variante (remplacer le 32 avec un autre numéro). Qui permet d'imprimer un certain nombre de mots (32) en commençant par le pointeur de pile de géant (g) taille de, sous la forme d'adresses (un). Tapez 'help x" pour plus d'informations sur le format.

Instrumentant votre code avec certains sentinelle "printf"s ne peut pas être une mauvaise idée, dans ce cas.

7voto

Michael Dorgan Points 7849

Regardez certains de vos autres registres pour voir si l'un d'entre eux est le pointeur de pile en cache en eux. À partir de là, vous pourriez être en mesure de récupérer une pile. Aussi, si ce n'est intégré, assez souvent pile est définie à un très particulier de l'adresse. En utilisant cela, vous pouvez aussi parfois obtenir un stack décent. Tout cela suppose que lorsque vous avez sauté en hyperespace, votre programme de ne pas vomir partout en mémoire le long du chemin...

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