web-dev-qa-db-fra.com

Comment aller à la ligne précédente dans GDB?

Est-il possible dans gdb d’accéder à une ligne avant la ligne en cours d’exécution . Par exemple:


void my_fun( somePtrType** arr,int start,int end)
{
 // arr is an array of pointers to somePtrType
  //line a
 ... some assignments
 swap(&arr[ind1] , &arr[ind2] ) ;
 //line b (current line )
}

Je suis actuellement à la ligne b et peux y examiner les valeurs arr, mais je souhaite revenir à la ligne a et examiner le contenu de arr à ce moment-là.

Je pense que cela pourrait ne pas être possible car un débogueur peut exécuter un code au ralenti, mais ne peut pas le faire exécuter à l'envers.
Encore d'autres idées ..

58
sud03r

Oui! Avec la nouvelle version 7.0 gdb, vous pouvez faire exactement cela!

La commande serait "reverse-step" ou "reverse-next".

Vous pouvez obtenir gdb-7.0 sur ftp.gnu.org:/pub/gnu/gdb

Si vous rencontrez l’erreur: Target child does not support this command., essayez d’ajouter target record au début de l’exécution, après avoir lancé run.

Edit: Puisque GDB 7.6 target record est obsolète, utilisez plutôt target record-full.

94
Michael Snyder

Oui, cela est possible et simple maintenant, avec du matériel réel (c'est-à-dire pas uniquement avec une VM) . GDB-7.0 prend en charge le débogage inversé avec des commandes telles que reverse-step et reverse-continue, sur des machines Linux x86 natives.

Il y a un tutoriel ici: http://www.sourceware.org/gdb/wiki/ProcessRecord/Tutorial

12
Michael Snyder

Réponse courte : Non. 

Pour contournement lire ci-dessous.

Bien qu’à la ligne b, il ne soit pas possible de déterminer la valeur de la ligne a, il est possible de consigner la valeur de arr en a et b et d’autres emplacements en ne touchant qu’un seul point d'arrêt.

  • Utilisez la commande "display" (display nom_variable où nom_variable doit être remplacé par arr, * arr, ** arr en fonction de ce que vous recherchez) afin que le contenu du nom_variable soit être jeté sur l'écran. Notez que vous pouvez ajouter des éléments à la liste d'affichage lorsque le nom de variable est dans la portée, ce qui peut vous obliger à attendre votre premier point d'arrêt. 
  • Créez des points d'arrêt à divers emplacements de code où vous souhaitez enregistrer la valeur de nom_variable. Un tel point d'arrêt serait à la ligne a.
  • Pour chaque point d'arrêt, utilisez la commande (command numéro_pause) et indiquez à votre point d'arrêt de ne pas interrompre l'exécution du programme. La commande à utiliser est continue suivie de end. Voir exemple ci-dessous.

(gdb) commande 1 

Tapez des commandes pour le moment où le point d'arrêt 1 est atteint, une par ligne. Terminez avec une ligne disant simplement "fin".

continuer

fin

  • Placez un point d'arrêt sur la ligne b.

Désormais, lorsque tous les autres points d'arrêt de journalisation sont atteints, la valeur d'arr sera sauvegardée à l'écran, mais le point d'arrêt n'attendra pas l'interaction de l'utilisateur et se poursuivra automatiquement. Lorsque vous frappez un point d'arrêt à la ligne b, vous pouvez voir les valeurs passées d'arr qui seraient enregistrées dans gdb lui-même. 

Selon la situation, vous pouvez également vider (et afficher) de nombreuses informations utiles. Par exemple, vous voudrez peut-être aussi vider un compteur de boucle (disons i) si la fonction ci-dessus est appelée 10000 fois dans une boucle. Cela dépend vraiment de ce que vous essayez d’atteindre.

4
mohit

mozilla rr

https://github.com/mozilla/rr

L’enregistrement et la relecture intégrés de GDB présentent de sérieuses limitations, par exemple: aucune prise en charge des instructions AVX: Le débogage inversé gdb échoue avec "L'enregistrement de processus ne prend pas en charge l'instruction 0xf0d à l'adresse"

Les inconvénients de rr:

  • beaucoup plus fiable actuellement
  • offre également une interface GDB avec le protocole gdbserver, ce qui en fait un excellent remplacement
  • petite baisse de performance pour de nombreux programmes

L'exemple suivant présente certaines de ses fonctionnalités, notamment les commandes reverse-next, reverse-step et reverse-continue.

Installez Ubuntu 16.04:

Sudo apt-get install rr linux-tools-common linux-tools-generic linux-cloud-tools-generic
Sudo cpupower frequency-set -g performance

Mais envisagez également de compiler à partir des sources pour obtenir les dernières mises à jour, ce n'était pas difficile.

Programme de test:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int f() {
    int i;
    i = 0;
    i = 1;
    i = 2;
    return i;
}

int main(void) {
    int i;

    i = 0;
    i = 1;
    i = 2;

    /* Local call. */
    f();

    printf("i = %d\n", i);

    /* Is randomness completely removed?
     * Recently fixed: https://github.com/mozilla/rr/issues/2088 */
    i = time(NULL);
    printf("time(NULL) = %d\n", i);

    return EXIT_SUCCESS;
}

compiler et exécuter:

gcc -O0 -ggdb3 -o reverse.out -std=c89 -Wextra reverse.c
rr record ./reverse.out
rr replay

Vous êtes maintenant dans une session GDB et vous pouvez inverser correctement le débogage:

(rr) break main
Breakpoint 1 at 0x55da250e96b0: file a.c, line 16.
(rr) continue
Continuing.

Breakpoint 1, main () at a.c:16
16          i = 0;
(rr) next
17          i = 1;
(rr) print i
$1 = 0
(rr) next
18          i = 2;
(rr) print i
$2 = 1
(rr) reverse-next
17          i = 1;
(rr) print i
$3 = 0
(rr) next
18          i = 2;
(rr) print i
$4 = 1
(rr) next
21          f();
(rr) step
f () at a.c:7
7           i = 0;
(rr) reverse-step
main () at a.c:21
21          f();
(rr) next
23          printf("i = %d\n", i);
(rr) next
i = 2
27          i = time(NULL);
(rr) reverse-next
23          printf("i = %d\n", i);
(rr) next
i = 2
27          i = time(NULL);
(rr) next
28          printf("time(NULL) = %d\n", i);
(rr) print i
$5 = 1509245372
(rr) reverse-next
27          i = time(NULL);
(rr) next
28          printf("time(NULL) = %d\n", i);
(rr) print i
$6 = 1509245372
(rr) reverse-continue
Continuing.

Breakpoint 1, main () at a.c:16
16          i = 0;

selon http://sourceware.org/gdb/current/onlinedocs/gdb.html#SEC51 , et "si l'environnement cible le prend en charge", oui.

2
ax.

Si votre programme est court, le truc habituel est,

  1. Placez un nouveau point d'arrêt sur la ligne précédente
    • firerpour relancer le débogage

GDBa été fait pour faire ça!

2
nik

Pas gdb mais vous pouvez revenir en arrière facilement en utilisant un débogueur appelé qira. Vous pouvez utiliser les flèches haut et bas pour aller et venir, il indique également quels registres ont changé. 

 enter image description here

1
briankip

Si votre code d'installation pour arr est juste au-dessus de "line a" (un scénario très courant), vous pouvez le faire comme ceci:

tbreak myfilename.c:123 (la ligne 123 est le début du code de configuration pour arr), puis

jump 123

Le "tbreak" empêche gdb de continuer (reprendre) le programme après le saut.

alors vous pouvez parcourir le code de configuration ou simplement définir un point d'arrêt sur "ligne a" et continuer

0
slonik

Tout le monde souhaite un débogueur Omniscient comme celui-ci: http://www.lambdacs.com/debugger/ , mais ils sont (selon la langue/la machine) difficiles à créer et ont beaucoup de comptabilité à faire.

Pour le moment, sur du matériel réel et non dans une VM, il est presque impossible de le faire. 

0
Tobias Langner