Was sind die besten Möglichkeiten, um eine GDB-Debugging-Sitzung zu automatisieren?


73

Verfügt GDB über einen integrierten Skriptmechanismus, sollte ich ein Expect-Skript codieren oder gibt es eine noch bessere Lösung?

Ich sende jedes Mal die gleiche Befehlsfolge und speichere die Ausgabe jedes Befehls in einer Datei (höchstwahrscheinlich unter Verwendung des in GDB integrierten Protokollierungsmechanismus, es sei denn, jemand hat eine bessere Idee).


Antworten:


64

gdbführt die Datei .gdbinitnach dem Ausführen aus. Sie können also Ihre Befehle zu dieser Datei hinzufügen und prüfen, ob dies für Sie in Ordnung ist. Dies ist ein Beispiel für .gdbinitdas Drucken der Rückverfolgung für alle f()Anrufe:

set pagination off
set logging file gdb.txt
set logging on
file a.out
b f
commands
bt
continue
end
info breakpoints
r
set logging off
quit

2
Gibt es eine Umgebungsvariable, die ich festlegen kann, damit GDB beim Start eine andere Datei ausführt?
Anonym

27
@Anonymous nein, aber es gibt eine Befehlszeilenoption: --command = FILE, -x GDB-Befehle aus FILE ausführen.
Matt

86

Ich habe gerade etwas Ähnliches durchgemacht und mir ein einfaches Beispiel ausgedacht - und da ich wusste, dass ich es bald vergessen werde, dachte ich, ich sollte es besser posten. :)Also werde ich es hier posten, da es mit der Frage zusammenhängt.

Grundsätzlich wollte ich in diesem Beispiel einige Variablenwerte an bestimmten Stellen des Codes erhalten. und lassen Sie sie ausgeben, bis das Programm abstürzt. Hier ist zunächst ein kleines Programm, das garantiert in wenigen Schritten abstürzttest.c :

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

int icount = 1; // default value

main(int argc, char *argv[])
{
  int i;

  if (argc == 2) {
    icount = atoi(argv[1]);
  }

  i = icount;
  while (i > -1) {
    int b = 5 / i;
    printf(" 5 / %d = %d \n", i, b );
    i = i - 1;
  }

  printf("Finished\n");
  return 0;
}

Der einzige Grund, warum das Programm Befehlszeilenargumente akzeptiert, besteht darin, die Anzahl der Schritte vor dem Absturz auswählen zu können - und zu zeigen, dass diese im Batch-Modus gdbignoriert --argswerden. Dies kompiliere ich mit:

gcc -g test.c -o test.exe

Dann bereite ich das folgende Skript vor - der Haupttrick hier besteht darin, commandjedem einen zuzuweisen breakpoint, der schließlich continue(siehe auch gdb automatisieren: Rückverfolgung bei jedem Aufruf von Funktions-Puts anzeigen ). Dieses Skript nenne ich test.gdb:

# http://sourceware.org/gdb/wiki/FAQ: to disable the
# "---Type <return> to continue, or q <return> to quit---"
# in batch mode:
set width 0
set height 0
set verbose off

# at entry point - cmd1
b main
commands 1
  print argc
  continue
end

# printf line - cmd2
b test.c:17
commands 2
  p i
  p b
  continue
end

# int b = line - cmd3
b test.c:16
commands 3
  p i
  p b
  continue
end

# show arguments for program
show args
printf "Note, however: in batch mode, arguments will be ignored!\n"

# note: even if arguments are shown;
# must specify cmdline arg for "run"
# when running in batch mode! (then they are ignored)
# below, we specify command line argument "2":
run 2     # run

#start # alternative to run: runs to main, and stops
#continue

Beachten Sie, dass Sie, wenn Sie es im Batch-Modus verwenden möchten, das Skript am Ende mit runoder startoder ähnlichem "starten" müssen .

Mit diesem Skript kann ich gdbim Batch-Modus aufrufen, wodurch die folgende Ausgabe im Terminal generiert wird:

$ gdb --batch --command=test.gdb --args ./test.exe 5
Breakpoint 1 at 0x804844d: file test.c, line 10.
Breakpoint 2 at 0x8048485: file test.c, line 17.
Breakpoint 3 at 0x8048473: file test.c, line 16.
Argument list to give program being debugged when it is started is "5".
Note, however: in batch mode, arguments will be ignored!

Breakpoint 1, main (argc=2, argv=0xbffff424) at test.c:10
10    if (argc == 2) {
$1 = 2

Breakpoint 3, main (argc=2, argv=0xbffff424) at test.c:16
16      int b = 5 / i;
$2 = 2
$3 = 134513899

Breakpoint 2, main (argc=2, argv=0xbffff424) at test.c:17
17      printf(" 5 / %d = %d \n", i, b );
$4 = 2
$5 = 2
 5 / 2 = 2 

Breakpoint 3, main (argc=2, argv=0xbffff424) at test.c:16
16      int b = 5 / i;
$6 = 1
$7 = 2

Breakpoint 2, main (argc=2, argv=0xbffff424) at test.c:17
17      printf(" 5 / %d = %d \n", i, b );
$8 = 1
$9 = 5
 5 / 1 = 5 

Breakpoint 3, main (argc=2, argv=0xbffff424) at test.c:16
16      int b = 5 / i;
$10 = 0
$11 = 5

Program received signal SIGFPE, Arithmetic exception.
0x0804847d in main (argc=2, argv=0xbffff424) at test.c:16
16      int b = 5 / i;

Beachten Sie, dass sich die Schleife, während wir das Befehlszeilenargument 5 angeben, immer noch nur zweimal dreht (wie in der Spezifikation runim gdbSkript angegeben). Wenn runkeine Argumente vorhanden sind, dreht es sich nur einmal (der Standardwert des Programms) und bestätigt, dass dies --args ./test.exe 5ignoriert wird.

Da dies jetzt jedoch in einem einzigen Aufruf und ohne Benutzerinteraktion ausgegeben wird, kann die Befehlszeilenausgabe mithilfe der bashUmleitung einfach in einer Textdatei erfasst werden , z. B.:

gdb --batch --command=test.gdb --args ./test.exe 5 > out.txt

Es gibt auch ein Beispiel für die Verwendung von Python zur Automatisierung von GDB in c - GDB Auto Stepping - automatischer Ausdruck von Zeilen bei freiem Lauf?

Hoffe das hilft,
Prost!


3
Vielen Dank für das Teilen, dies ist nützlich
Gearoid Murphy

1
zu fehlerhaft für mich. detachInnerhalb commandmacht gdbAbsturz, continueinnerhalb coammandführt zu seltsamen Selected thread is running.Warnungen.
Phil294

10

Wenn -xIhnen ein mit einer Datei zu viel ist, verwenden Sie einfach mehrere -ex.

Dies ist ein Beispiel für die Verfolgung eines laufenden Programms, das die Rückverfolgung bei Abstürzen anzeigt (und speichert)

sudo gdb -p "$(pidof my-app)" -batch \
  -ex "set logging on" \
  -ex continue \
  -ex "bt full" \
  -ex quit
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.