Ist es in gdb möglich, zu einer Zeile vor der aktuell ausgeführten Zeile zu wechseln.
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 )
}
Ich bin derzeit in Zeile b und kann die arr
-Werte dort überprüfen, aber ich möchte zurück zu Zeile a und den Inhalt von arr
prüfen.
Ich denke, es ist möglicherweise nicht möglich, weil ein Debugger Code in Zeitlupe ausführen kann, aber nicht rückwärts ausführen kann.
.__ Weitere Einblicke ..
Ja! Mit der neuen Version 7.0 von gdb können Sie genau das tun!
Der Befehl wäre "reverse-step
" oder "reverse-next
".
Sie können gdb-7.0 von ftp.gnu.org:/pub/gnu/gdb erhalten
Wenn Sie auf den Fehler stoßen: Target child does not support this command.
, versuchen Sie, target record
zu Beginn der Ausführung hinzuzufügen, nachdem Sie run
gestartet haben.
Bearbeiten: Da GDB 7.6 target record
veraltet ist, verwenden Sie stattdessen target record-full
.
Ja, es ist jetzt möglich und unkompliziert mit echter Hardware (dh nicht nur mit einer VM) . GDB-7.0 unterstützt das umgekehrte Debugging mit Befehlen wie reverse-step und reverse-continue auf nativen Linux-x86-Computern.
Es gibt hier ein Tutorial: http://www.sourceware.org/gdb/wiki/ProcessRecord/Tutorial
Kurze Antwort : Nein.
Für Workaround lesen Sie unten.
In Zeile b ist es nicht möglich, den Wert in Zeile a zu bestimmen. Es ist jedoch möglich, den Wert von arr an a und b und an anderen Orten zu protokollieren, indem nur ein Haltepunkt getroffen wird.
(gdb) Befehl 1
Geben Sie Befehle für den Haltepunkt 1 ein, einen pro Zeile. Beenden Sie mit einer Zeile, die nur "Ende" sagt.
fortsetzen
ende
Wenn nun alle anderen Haltepunkte für die Protokollierung erreicht werden, wird der Wert von arr auf dem Bildschirm ausgegeben, der Haltepunkt wartet jedoch nicht auf die Benutzerinteraktion und wird automatisch fortgesetzt. Wenn Sie einen Haltepunkt in Zeile b treffen, können Sie die früheren Werte von arr sehen, die in gdb selbst protokolliert würden.
Je nach Situation können Sie auch viele nützliche Informationen ausgeben (und anzeigen). Beispielsweise möchten Sie möglicherweise auch einen Schleifenzähler ausgeben (z. B. i), wenn die obige Funktion in einer Schleife 10000-mal aufgerufen wird. Das hängt wirklich davon ab, was Sie erreichen wollen.
mozilla rr
Die eingebaute Aufzeichnung und Wiedergabe von GDB unterliegt strengen Einschränkungen, z. Keine Unterstützung für AVX-Anweisungen: gdb reverse debugging schlägt fehl mit "Prozessdatensatz unterstützt keine Anweisung 0xf0d an Adresse"
Vorteile von rr:
Das folgende Beispiel zeigt einige seiner Funktionen, insbesondere die Befehle reverse-next
, reverse-step
und reverse-continue
.
Installieren Sie Ubuntu 16.04:
Sudo apt-get install rr linux-tools-common linux-tools-generic linux-cloud-tools-generic
Sudo cpupower frequency-set -g performance
Aber auch das Kompilieren aus dem Quellcode, um die neuesten Updates zu erhalten, war nicht schwer.
Testprogramm:
#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;
}
kompilieren und ausführen:
gcc -O0 -ggdb3 -o reverse.out -std=c89 -Wextra reverse.c
rr record ./reverse.out
rr replay
Jetzt bleiben Sie in einer GDB-Sitzung und können das Debuggen ordnungsgemäß rückgängig machen:
(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;
laut http://sourceware.org/gdb/current/onlinedocs/gdb.html#SEC51 und "wenn die Zielumgebung dies unterstützt", ja.
Wenn Ihr Programm kurz ist, lautet der übliche Trick:
r
um den Debug neu zu startenGDBwurde dazu gemacht!
Wenn sich Ihr Setup-Code für arr genau über "Zeile a" befindet (ein sehr häufiges Szenario), können Sie dies wie folgt tun:
tbreak myfilename.c:123
(Zeile 123 ist der Start des Setup-Codes für arr), dann
jump 123
Der "tbreak" verhindert, dass gdb das Programm nach dem Sprung fortsetzt (fortsetzt).
dann können Sie den Setup-Code schrittweise durchgehen oder einfach einen Haltepunkt in "Zeile a" setzen und fortfahren
Jeder wünscht sich einen allwissenden Debugger wie diesen: http://www.lambdacs.com/debugger/ , aber er ist (je nach Sprache/Maschine) schwierig zu erstellen und hat viel Buchhaltung.
Im Moment ist es auf echter Hardware und nicht in einer VM nahezu unmöglich, dies zu tun.