web-dev-qa-db-fra.com

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

Je dirige habituellement un programme en tant que:

./a.out arg1 arg2 <file

Je voudrais le déboguer en utilisant gdb.

Je connais la fonctionnalité set args, mais cela ne fonctionne que depuis l'invite gdb.

206
user277465

Passez les arguments à la commande run à partir de gdb.

$ gdb ./a.out
(gdb) r < t
Starting program: /dir/a.out < t
133
marcog

Tu peux le faire:

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

Le bit magique étant --args.

Il suffit de taper run dans la console de commande gdb pour lancer le débogage.

406
rubenvb

Si vous voulez avoir la commande nue run dans gdb pour 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 ne pouvais pas obtenir le même comportement avec le paramètre --args, gdb échappe farouchement 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 elle-même, pas ce que nous voulons vraiment ici

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

Lancez GDB sur votre projet. 

  1. Allez dans le répertoire du projet, où vous avez déjà compilé l'exécutable du projet. Émettez la commande gdb et le nom de l'exécutable comme ci-dessous:

    gdb projetNomExécutable

Cela démarre gdb et affiche les éléments suivants: GNU gdb (Ubuntu 7.11.1-0ubuntu1 ~ 16.04) 7.11.1 Tous droits réservés (C) 2016 Free Software Foundation, Inc ....... ........................................... Tapez "à propos de Word "pour rechercher des commandes associées à" Word "... Lecture des symboles à partir de projectExecutablename ... done . (gdb)

  1. Avant de lancer votre programme, vous souhaitez définir 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 d'exécution lance l'exécution de l'exécutable. Si le programme que vous déboguez requiert des arguments de ligne de commande, vous les spécifiez dans la commande d'exécution. Si vous voulez exécuter mon programme sur le fichier "xfiles" (qui se trouve dans un dossier "mulder" dans le répertoire du projet), procédez comme 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 probablement été développé à l'Université de Stanford .

1
Ehsan

Ne serait-il pas agréable de simplement taper debug devant une commande pour pouvoir le déboguer avec gdb au niveau du shell?

En dessous, cette fonction. Cela fonctionne même avec ce qui suit:

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

Ceci 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, two et three sont des commandes arbitraires qui consomment ou produisent des données qui ne doivent pas être endommagées.

Après la fonction bash, gdb est invoqué presque 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 sur la façon d'appliquer ceci: Il suffit de taper debug devant:

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 de déboguer avec gdb. Sauf quelques détails ou plus:

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

  • Vous ne pouvez pas facilement transmettre argv0 au programme comme avec exec -a arg0 command args. Si vous devez suivre cette procédure, procédez comme suit: Après exec-wrapper, remplacez "exec par "exec -a \"\${DEBUG_ARG0:-\$1}\".

  • Il y a des FD au-dessus de 1000 ouverts, qui sont normalement fermés. Si cela pose un problème, changez 0<&1000 1>&1001 2>&1002 pour lire 0<&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/tty par "${DEBUGTTY:-/dev/tty}". Dans un autre TTY, tapez tty; sleep inf et utilisez ensuite le TTY imprimé (i. E. /dev/pts/60) pour le débogage, comme dans DEBUGTTY=/dev/pts/60 debug command arg... C'est la puissance 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>&0 restaure les 3 premiers FD pour qu'ils pointent vers votre téléscripteur actuel. Vous pouvez donc contrôler gdb.
  • /usr/bin/gdb -q -nx -nw exécute gdb invoque gdb sur 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 sur 1000 et plus
  • -ex r démarre le programme en utilisant le exec-wrapper
  • --args "$@" passe les arguments comme donné

N'était-ce pas facile?

0
Tino