Comment passer des arguments et rediriger stdin d'un fichier vers un programme exécuté dans gdb?

210

Je lance généralement un programme comme:

./a.out arg1 arg2 <file

Je voudrais le déboguer en utilisant gdb.

Je connais la set argsfonctionnalité, mais cela ne fonctionne qu'à partir de l'invite gdb.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source

Réponses:

136

Passez les arguments à la runcommande depuis gdb.

$ gdb ./a.out
(gdb) r < t
Starting program: /dir/a.out < t
moinudin
la source
3
rest l'abréviation de runet vous pouvez le suivre avec n'importe quel argument. Comme dans cette question, ce serait: r arg1 arg2 <fileou cela pourrait êtrerun arg1 arg2 <file
phyatt
Pour moi ça ne marche pas. Ensuite, j'ai essayé $ gdb ./a.outce (gdb) r < t arg1 arg2qui fonctionne bien pour moi. Dans mon cas a.out = nft arg1 = import arg2 = json ett = file containing json rules
mystictot
410

Tu peux le faire:

gdb --args path/to/executable -every -arg you can=think < of

Le morceau magique étant --args.

Tapez simplement runla console de commande gdb pour démarrer le débogage.

rubenvb
la source
24
Je pensais que je lisais mal au début; étrange --args précède l'exécutable. Mais il en est ainsi!
Kaolin Fire
8
@Kaolin --args doit précéder l'exécutable car il s'agit d'un commutateur pour gdb. Si cela venait après, comment gdb le distinguerait-il d'un argument que vous souhaitiez passer dans l'exécutable que vous déboguez?
codehippo
9
@codehippo: Eh bien, si vous ne l'avez pas spécifié --args, aucun argument n'est transmis à l'exécutable, ce n'est donc pas ambigu.
Courses de légèreté en orbite
14
Je suppose que c'est parce que classiquement argv[0]est le nom de l'exécutable
Claudiu
3
cela redirigera l'entrée de gdblui - même vers le offichier et fera en sorte que gdb essaie d'exécuter des commandes depuis celui
unkulunkulu
4

Si vous voulez avoir une runcommande nue gdbpour exécuter votre programme avec des redirections et des arguments, vous pouvez utiliser set args:

% gdb ./a.out
(gdb) set args arg1 arg2 <file
(gdb) run

Je n'ai pas pu obtenir le même comportement avec le --argsparamètre, gdbéchappe férocement aux redirections, c'est-à-dire

% gdb --args echo 1 2 "<file"
(gdb) show args
Argument list to give program being debugged when it is started is "1 2 \<file".
(gdb) run
...
1 2 <file
...

Celui-ci redirige en fait l'entrée de gdb lui-même, pas ce que nous voulons vraiment ici

% gdb --args echo 1 2 <file
zsh: no such file or directory: file
unkulunkulu
la source
1

Démarrez GDB sur votre projet.

  1. Accédez au répertoire du projet, où vous avez déjà compilé l'exécutable du projet. Exécutez la commande gdb et le nom de l'exécutable comme ci-dessous:

    gdb projectExecutablename

Cela démarre gdb, imprime ce qui suit: GNU gdb (Ubuntu 7.11.1-0ubuntu1 ~ 16.04) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. ............... .................................. Tapez "mot approprié" pour rechercher des commandes liées à "mot" .. . Lecture des symboles depuis projectExecutablename ... done. (gdb)

  1. Avant de lancer l'exécution de votre programme, vous souhaitez configurer vos points d'arrêt. La commande break vous permet de le faire. Pour définir un point d'arrêt au début de la fonction nommée main:

    (gdb) b main

  2. Une fois que vous avez l'invite (gdb), la commande run démarre l'exécution de l'exécutable. Si le programme que vous déboguez nécessite des arguments de ligne de commande, vous les spécifiez dans la commande d'exécution. Si vous vouliez exécuter mon programme sur le fichier "xfiles" (qui est dans un dossier "mulder" dans le répertoire du projet), vous feriez ce qui suit:

    (gdb) r mulder / xfiles

J'espère que cela t'aides.

Avertissement: Cette solution n'est pas la mienne, elle est adaptée de https://web.stanford.edu/class/cs107/guide_gdb.html Ce petit guide de gdb a, très probablement, été développé à l'Université de Stanford.

Ehsan
la source
0

Ne serait-il pas agréable de taper juste debugdevant une commande pour pouvoir la déboguer gdbau niveau du shell?

En dessous, cette fonction. Il fonctionne même avec les éléments suivants:

"$program" "$@" < <(in) 1> >(out) 2> >(two) 3> >(three)

C'est un appel où vous ne pouvez rien contrôler, tout est variable, peut contenir des espaces, des sauts de ligne et des métacaractères shell. Dans cet exemple, in, out, twoet d' threeautres commandes arbitraires qui consomment ou produisent des données qui ne doivent pas être lésés.

La bashfonction suivante invoque gdbpresque proprement dans un tel environnement [ Gist ]:

debug()
{
  1000<&0 1001>&1 1002>&2 \
  0</dev/tty 1>/dev/tty 2>&0 \
  /usr/bin/gdb -q -nx -nw \
  -ex 'set exec-wrapper /bin/bash -c "exec 0<&1000 1>&1001 2>&1002 \"\$@\"" exec' \
  -ex r \
  --args "$@";
}

Exemple d'application: il suffit de taper debugdevant:

Avant:

p=($'\n' $'I\'am\'evil' "  yay  ")
"b u g" "${p[@]}" < <(in) 1> >(out) 2> >(two) 3> >(three)

Après:

p=($'\n' $'I\'am\'evil' "  yay  ")
debug "b u g" "${p[@]}" < <(in) 1> >(out) 2> >(two) 3> >(three)

C'est tout. Maintenant, c'est une évidence pour déboguer gdb. Sauf pour quelques détails ou plus:

  • gdbne se ferme pas automatiquement et maintient donc la redirection IO ouverte jusqu'à ce que vous quittiez gdb. Mais j'appelle cela une fonctionnalité.

  • Vous ne pouvez pas facilement passer argv0au programme comme avec exec -a arg0 command args. Ce qui suit devrait faire cette astuce: après le exec-wrapperchangement "execde"exec -a \"\${DEBUG_ARG0:-\$1}\" .

  • Il existe des FD au-dessus de 1000 ouverts, qui sont normalement fermés. Si c'est un problème, changez 0<&1000 1>&1001 2>&1002pour lire0<&1000 1>&1001 2>&1002 1000<&- 1001>&- 1002>&-

  • Vous ne pouvez pas exécuter deux débogueurs en parallèle. Il peut également y avoir des problèmes si une autre commande consomme /dev/tty(ou STDIN). Pour résoudre ce problème, remplacez /dev/ttypar "${DEBUGTTY:-/dev/tty}". Dans un autre type de TTY tty; sleep inf, puis utilisez le TTY imprimé (i. E. /dev/pts/60) pour le débogage, comme dans DEBUGTTY=/dev/pts/60 debug command arg... C'est le pouvoir de Shell, habituez-vous!

Fonction expliquée:

  • 1000<&0 1001>&1 1002>&2 éloigne les 3 premiers FD
    • Cela suppose que les FD 1000, 1001 et 1002 sont libres
  • 0</dev/tty 1>/dev/tty 2>&0restaure les 3 premiers FD pour pointer vers votre ATS actuel. Vous pouvez donc contrôler gdb.
  • /usr/bin/gdb -q -nx -nwexécute gdbinvoque gdbsur shell
  • -ex 'set exec-wrapper /bin/bash -c "exec 0<&1000 1>&1001 2>&1002 \"\$@\"" crée un wrapper de démarrage, qui restaure les 3 premiers FD qui ont été enregistrés à 1000 et plus
  • -ex r démarre le programme en utilisant le exec-wrapper
  • --args "$@" passe les arguments comme indiqué

N'était-ce pas facile?

Tino
la source