dbx est un débogueur symbolique textuel.
dbx travaille de manière optimale sur un code compilé avec l'option -g (option -g3 recommandée) et sans optimisation (option -O0 recommandée). Cela a pour effet de rajouter des informations de déboguage dans le code objet. Ces informations permettent à dbx de voir les variables locales et de déterminer les numéros des lignes du source.
 

Introduction

dbx permet de déterminer l'origine d'un plantage en étudiant le fichier core généré pour analyser la pile d'appel du programme :
ex : dbx mon_prog core.
On utilise la commande where au prompt qui apparait. En retour s'affichent la file d'appels des fonctions employées ainsi que le nom des fichiers sources et les numéros des lignes où ont eu lieu ces appels jusqu'à la fonction responsable de l'erreur :
(dbx) where
>  0 foo2(i = 5) ["/usr/tmp/test.c":44, 0x1000109c]
   1 foo(i = 4) ["/usr/tmp/test.c":38, 0x1000105c]
   2 main(argc = 1, argv = 0xffffffad78) ["/usr/tmp/test.c":55, 0x10001104]
   3 __start() ["/shamu/crt1text.s":137, 0x10000ee4]
Dans ce cas, le programme test s'est planté à la ligne 44 du fichier source test.c en cours d'exécution de la routine foo2, appelée à la ligne 38 de la routine foo, elle-même appelée à la ligne 55 de la function main. Par la suite on utilisera d'autres commandes de dbx pour obtenir les valeurs de variables et connaitre les raisons du plantage.

Retour en début de page

_____________________________________

Lancement de dbx

 

Compilation d'un programme pour déboguer avec dbx

Avant d'utiliser dbx pour déboguer un programme, il faut le compiler avec au moins l'option -g. Celle-ci inclut des informations supplémentaires de déboguage dans le fichier objet qui permettent à dbx de lister les variables locales et de trouver les numéros des lignes de code source.
Si vous utilisez dbx sur un code qui n'a pas été compilé avec l'option -g, les variables locales sont invisibles pour dbx et les numéros des lignes ne sont pas cohérents en raison d'optimisations diverses. Il est plus difficile de déboguer un code sans références fiables aux lignes de code.
 

Appel à dbx

L'appel à dbx se fait à l'aide de la ligne de commande suivante :
dbx [options] [object_file [corefile] ]


Options de dbx
Les options suivantes peuvent être transmises lors de l'appel à dbx. Elles sont décrites dans la suite de cette section :
 
 
Option Description
-c file sélectionne un autre fichier de commande que le fichier .dbxinit lors du lancement de dbx
-d fournit des informations de lancement au shell lorsqu'un programme est lancé avec la commande run
-e num choisit une taille plus grande (num donnée en octets) pour la pile d'évaluation (la valeur par défaut est 20000 octets). Il faut relancer dbx avec cette option si le message d'erreur too large to evaluate apparait
-i utilise le mode interactif. Cette option permet d'entrer des valeurs comme un fichier d'entrée. Le caractère # n'est alors plus considéré comme un commentaire
-I dir spécifie le répertoire dans lequel dbx doit chercher les fichiers source. Mettre une option -I par répertoire si plusieurs répertoires source doivent être spécifiés
-k permet le déboguage du kernel
-N initialise à 1 la variable $nonstop : l'attachement à un processus ne l'arrête pas
-P name débogue le processus de nom name
-p pid débogue le processus spécifié par son pid
-R autorise les points d'arrêt (breakpoints) dans rld
-r program [args] exécute le programme appelé program lors du lancement de dbx avec les arguments args spécifiés. Le fichier .dbxinit est lu et exécuté après l'object_file. On ne peut pas spécifier de fichier core avec l'option -r

Spécifier un fichier objet et un fichier core
L'object_file est le nom de l'exécutable que l'on veut déboguer. Il comprend le code que dbx exécute et la table des symboles qui contient les noms des variables et procédures et la correspondance entre le code objet et le code source dans les fichiers source.
Un corefile (fichier core) est produit (core dumped) lorsque l'exécution ne se termine pas normalement. A l'aide du nom du fichier core, dbx permet de connaitre l'état mémoire du programme et l'endroit où l'erreur est survenue. On peut alors connaitre la pile d'appels des fonctions et les valeurs de variables pour déterminer la raison du plantage sans pour autant poursuivre l'exécution au-delà du crash. Si l'on ne spécifie pas de corefile, dbx cherche dans le répertoire courant un fichier appelé core. Si un fichier core est présent ou s'il semble en être un, dbx se comportera comme si ce fichier core lui avait été spécifié.
On peut spécifier l'object_file et le corefile soit comme arguments lors du lancement de dbx soit u travers de commandes lorsque l'on est dans dbx, en mode prompt.

Le prompt de dbx
Une fois dbx lancé, celui-ci affiche l'invite suivante :

(dbx)
On peut modifier cet affichage en changeant la valeur de la variable $prompt.

Spécifier des fichiers avec des commandes dbx
Les commandes de dbx, givenfile et corefile, permettent de préciser respectivement le fichier objet et le fichier core en cours d'exécution de dbx.
 
givenfile [file]
  si un nom de fichier est donné, dbx tue le processus en cours et charge l'exécutable de nom file et les informations de déboguage y figurant. Dans le cas contraire, dbx affiche le nom du programme en cours de déboguage sans l'altérer
corefile  [file]
  si un nom de fichier est donné, dbx utilise les informations présentes dans ce fichier core. Dans le cas contraire, dbx affiche le nom du fichier core en cours d'utilisation sans l'altérer

Lancement du programme sous dbx

On peut lancer le programme sous dbx à l'aide des commandes run ou rerun :
 
run   [run-args]
  la commande run démarre l'exécution du programme et lui transmet les arguments éventuellement fournis. La commande utilise le shell courant (valeur dans la variable d'environnement $SHELL) pour exécuter la commande run. La même syntaxe que dans un shell classique est supportée, i.e. les substitutions par ? ou * dans les noms de fichiers, les redirections des entrées et sorties standards

Une commande run doit apparaitre seule sur une ligne, ne peut être suivie par une autre commande dbx (séparée par un point-virgule) et doit se finir par un retour chariot.
 
rerun [run-args]
  la commande rerun sans argument répète la dernière commande run si elle existe. Autrement elle est équivalente à la commande run sans argument

Exemple :
Le programme sort reçoit un fichier en entrée et produit un fichier trié en sortie; on peut spécifier les fichiers d'entrée et de sortie par redirection ou par arguments en ligne de commande.
En ligne de commande, on a ainsi au choix :

% sort -i input -o output
% sort < input2 > output2
Si l'on débogue le programme sort, les commandes équivalentes de dbx sont :
(dbx) run -i input -o output
(dbx) run < input2 > output2
Si l'on exécute ces commandes dans l'ordre proposé, on peut répéter la dernière commande run en utilisant la commande rerun :
(dbx) rerun

Exécution automatique de commandes au lancement

Le fichier .dbxinit, crée avec un éditeur de texte classique, permet d'exécuter automatiquement des commandes lors du lancement de dbx. Si une commande nécessite des arguments, le système les demande lors du lancement de dbx. La recherche du fichier .dbxinit se fait d'abord dans le répertoire courant puis dans le home directory.
 

Aide en ligne

La commande help de dbx possède plusieurs options :
 
help affiche les commandes supportées par dbx
help keyword affiche des informations relatives à l'argument keyword, tel que alias, help, most_used, quit, playback, record, etc ...
help all ffiche la totalité du fichier d'aide de dbx

En tapant help all, dbx affiche le contenu du fichier d'aide en utilisant la commande dont le nom figure dans la variable $pager de dbx. Ce fichier d'aide est assez gros et peut être difficile à lire même avec la commande more. On peut ainsi spécifier $pager pour employer pour un éditeur de texte particulier. Par exemple pour vi, il faut mettre la ligne suivante dans le fichier .dbxinit :

set $pager = "vi"
Il suffit de quitter l'éditeur pour revenir dans dbx.
 

Plusieurs commandes sur une même ligne

On peut utiliser un point-virgule (;) comme séparateur pour inclure plusieurs commandes sur la même ligne. Cela peut être utile avec des commandes comme when. Par exemple :
(dbx) when at "myfile.c":37 {print a ; where ; print b}

Une commande sur plusieurs lignes

On peut utiliser le caractère backslash (\) à la fin d'une ligne entrée pour indiquer que la commande continue sur la ligne suivante. Cela peut être utile pour des commandes complexes comme la commande alias suivante :
(dbx) alias foll "print *(struct list *) $p ; \
set $p = (int)((struct list *) ($p))->next"

Appel d'un shell

La commande sh permet de créer un shell. Pour en sortir, il suffit de taper exit ou <Ctrl-d> et revenir ainsi à dbx. La syntaxe de la commande sh est :
 
sh appel à un shell
sh command exécute la commande en argument dans le shell crée

La commande suivante permet d'afficher la fin du fichier datafile :

(dbx) sh tail datafile

Quitter dbx

Pour terminer une session dbx, il suffit de taper quit :
(dbx) quit


Retour en début de page

_____________________________________

Examen du code source

 

Spécifier les répertoires source

A partir des informations contenues dans la table des symboles du fichier objet, dbx détermine les fichiers sources à partir desquels le programme a été compilé et affiche les parties appropriées. Les fichiers objets compilés avec l'option -g contiennent le chemin absolu vers les fichiers sources. A chaque fois que dbx a besoin d'un fichier source il cherche dans un premier temps dans le chemin absolu pour ce fichier source. Si le fichier source n'est pas présent (ou si le fichier objet n'a pas été compilé avec l'option -g) dbx parcourt sa propre liste de répertoires à la recherche de ce fichier.

Par défaut, la liste des répertoires connus de dbx ne contient que le répertoire courant (répertoire de lancement de dbx) et le répertoire du fichier objet (s'il est différent du précédent). A chaque recherche, dbx parcourt cette liste dans l'ordre dans lequel les répertoires ont été insérés.

Spécifier des répertoires source par argument
On peut spécifier des répertoires supplémentaires lors du lancement de dbx avec l'option -I, une occurence par répertoire à ajouter.

Spécifier des répertoires source avec des commandes dbx
Les commandes dir et use permettent de spécifier des répertoire source alors que dbx est lancé.
 
dir [dir ...]
  si on fournit un ou plusieurs répertoires, dbx les ajoute à la fin de la liste des répertoires source. Sans argument, dbx affiche la liste de répertoires
use [dir ...]
  si on fournit un ou plusieurs répertoires, dbx remplace la liste des répertoires source avec ces répertoires. Sans argument, dbx affiche la liste des répertoires

 Ces deux commandes acceptent les chemins relatifs et absolus mais ne reconnaissent pas le caractère tilde (~) ou les variables d'environnement (e.g. $HOME/src).

Modification de path
Les informations de déboguage pour les programmes compilés avec l'option -g contiennent le chemin complet vers les fichiers sources. Par défaut, dbx utilise ces chemins pour chercher les fichiers sources. Cependant, si on débogue un programme compilé à un autre endroit et que l'on souhaite spécifier un nouveau chemin vers les fichiers source, on peut faire une modification des chemins. Ainsi on peut remplacer un élément d'un chemin par un autre élément afin que dbx trouve les fichiers.
 
dir elt1:elt2
  la commande dir (ou use) permet de modifier des répertoires et de spécifier un nouveau chemin vers les sources. dbx substitue elt2 à elt1

Par exemple le code source d'un programme compilé est /x/y/z/kk.c et le source a été déplacé dans /x/y/zzz/kk/kk.c. La commande dir (ou use) permet de modifier le chemin :

(dbx) dir /z/:/zzz/kk/
Le nouveau chemin est alors /x/y/zzz/kk/kk.c .
 

Changer de fichier source

La commande file permet de remplacer le fichier source courant par le fichier source spécifié. Le nouveau fichier devient alors le fichier source courant sur lequel on effectue les recherches et autres opérations.
Pour fixer le fichier source courant :
(dbx) file procedure.c
Généralement le programme que l'on débogue a son code source dans plusieurs fichiers. dbx sélectionne automatiquement le bon fichier et la section du code examiné. Ainsi, de nombreuses commandes dbx re-initialisent le fichier source courant, de manière implicite.
La commande file sans argument renvoie le fichier source courant :
(dbx) file
procedure.c
On peut aussi changer le fichier source courant par :
(dbx) func procedure

Listage de code source

La commande list affiche des lignes de code source. La variable $listwindow de dbx contient le nombre de lignes de source affichées par défaut. La commande list utilise la ligne active du fichier source courant à moins d'être annulée par une commande file (n'importe quelle exécution du programme modifie le fichier source courant).
La syntaxe de la commande list est la suivante :
 
list affiche $listwindow lignes de source à partir de la ligne courante du code source (ou à partir de la ligne du programcounter - pc )
list exp affiche $listwindow lignes de source à partir de la ligne donnée par l'expression exp
list exp1:exp2 affiche exp2 lignes à partir de la ligne exp1
list exp1,exp2 affiche le code source entre les lignes exp1 et exp2 incluses
list func affiche $listwindow lignes à partir de la procedure func
list func,exp affiche le code source entre les procédures func et exp incluses
list func:exp affiche exp lignes à partir de func

Le symbole > à gauche d'une ligne indique la ligne courante.
Le symbole * indique la position courante du pc.
 

Liste de routines inlinées

Le compilateur peut inliner des routines pour améliorer les performances du code, i.e. remplacer un appel par le code correspondant à la routine. La commande listinlines trouve les routines concernées si suffisamment d'information de déboguage est présente.
 
listinlines  affiche la liste des routines inlinées avec les adresses de début et de fin
listinlines func affiche toutes les instances inlinées de la routine func avec leurs adresses de début et de fin

Recherche dans le code source

On utilise le caractère slash (/) et le point d'interrogation (?) pour rechercher des expressions régulières au sein du fichier source courant. Pour une description d'expressions régulières, on peut consulter la manpage de l'éditeur UNIX ed. Les commandes de recherche ont la syntaxe suivante :
 
/[reg_exp] recherche en avant de l'expression régulière rep_exp dans le fichier source courant à partir de la ligne courante. Si dbx atteint la fin du fichier sans trouver l'expression, il poursuit à partir du début de celui-ci. dbx affiche la ligne source correspondant à la première occurrence trouvée. Sans argument, dbx fait une recherche en avant de la dernière expression fournie
?[rep_exp] recherche en arrière de l'expression régulière rep_exp dans le fichier source courant à partir de la ligne courante. Si dbx atteint le début du fichier sans trouver l'expression, il poursuit à partir de la fin de celui-ci. dbx affiche la ligne source correspondant à la première occurrence trouvée. Sans argument, dbx fait une recherche en arrière de la dernière expression fournie

Recherche en avant de la prochaine occurrence de la chaine "errno" :

(dbx) /errno
Recherche en arrière de la précédente occurence de "img" ou "Img" :
(dbx) ?[iI]mg

Appel d'un éditeur de texte

La commande edit permet d'éditer des fichiers à l'intérieur de dbx :
 
edit la commande edit appelle un éditeur de texte (vi par défaut) pour le fichier source courant. Si la variable $editor de dbx est renseignée avec un nom d'éditeur de texte, celui-ci est alors employé. Si elle n'est pas renseignée, dbx vérifie la variable d'environnement $EDITOR et, si elle est renseignée, appelle cet éditeur de texte. Quitter l'éditeur renvoie dans dbx
edit file appelle l'éditeur de texte avec le fichier file
edit procedure appelle l'éditeur de texte pour le fichier qui contient le code source de la routine spécifiée. Toutefois, on ne peut visualiser que des routines que dbx peut trouver à partir d'un nom simple : routines dans la pile activée et procédures globales uniquement

On peut aussi utiliser la commande edit pour concevoir des scripts dbx.

Retour en début de page

_____________________________________

Controle de dbx

 

Création et destruction de variables dbx

dbx autorise la définition de variables que l'on peut utiliser pour stocker des valeurs. Ces variables appartiennent à dbx et sont indépendantes du programme débogué. On peut par exemple les employer pour du stockage temporaire d'indices de tableau ou de pointeurs.

dbx possède une importante liste de variables prédéfinies pour controler de nombreuses commandes. Une variable dbx n'a pas de type fixe, on peut assigner à une variable une valeur de n'importe quel type même si elle avait auparavant une valeur d'un autre type. Cependant, une variable prédéfinie par dbx possède un type prédéfini fixe.
Presque tous les mots peuvent être utilisés comme nom de variables dbx. Une bonne règle est de mettre un caractère dollar ($) comme premier caractère de toutes les variables dbx pour éviter les conflits avec les variables du programme. Toutes les variables prédéfinies par dbx commencent par un caractère $.

Les paragraphes qui suivent ne s'appliquent que sur les variables dbx et pas les variables du programme débogué.

Initialisation de variables dbx
La commande set permet d'affecter une valeur à une variable dbx, la définissant si elle n'existait pas.
 
set var = exp définit (ou redéfinit) la variable dbx spécifiée var et lui affecte la valeur fournie par l'expression exp

On peut connaitre la valeur d'une variable dbx à l'aide de la commande print, par exemple :

(dbx) set $k = 1
(dbx) print $k
1
(dbx) set $k = $k + 23
(dbx) print $k
24
(dbx) print $k / 11
2
Dans l'exemple précédent, dbx réalise une division entière puisque $k et la constante 11 sont de type entier. Si on assigne une valeur de type réelle à $k et que l'on re-évalue l'expression à nouveau, dbx réalise une division réelle :
(dbx) set $k = 24.0
(dbx) print $k
24.0
(dbx) print $k / 11
2.1818181818181817
Il est recommandé de faire commencer toute variable dbx par un caractère $ pour éviter toute confusion avec une variable du programme. En effet une variable dbx sans le caractère $ masque la variable du programme qui a le même nom. Le seul moyen de voir la variable du programme est de détruire la variable dbx au moyen de la commande unset.

Listage de variables dbx
La commande set sans argument entraine l'affichage de toutes les variables dbx actuellement définies, les variables prédéfinies incluses. Exemple de résultat partiel :

(dbx) set
$addrfmt        "0x%x"
$addrfmt64      "0x%llx"
$assignverify   1
$casesense      2
$ctypenames     1
$curevent       3
$curline        44
$curpc          268439708
...
$stacktracelimit  1024
$stdc           0
$stepintoall    0
$tagfile        "tags"


destruction de variables dbx
La commande unset permet de détruire une variable dbx

(dbx) unset $k

Utilisation de l'historique des commandes

L'historique des commandes dbx est analogue à celui du C shell dans le sens où il permet de répéter des commandes entrées précédemment. Cependant, contrairement au mécanisme du C shell, dbx n'autorise la re-exécution de commandes qu'en début d'une ligne. De même il ne supporte pas non plus la substitution d'arguments comme le !$ du C shell.

Examen de l'historique
dbx stocke toutes les commandes entrées dans une liste. La valeur de la variable $lines de dbx détermine le nombre de commandes stockées dans cette liste. La valeur par défaut est 100. La commande history permet d'afficher cette liste. Par exemple, après la mise en place d'un point d'arrêt (breakpoint), le lancement du programme et l'examen de quelques variables, l'historique des commandes ressemble à :

(dbx) history
1    set $prompt = "(dbx)"
2    set $page = 0
3    set $pimode = 1
4    stop in main
5    history


Répétition de commande
On peut exécuter n'importe quelle commande contenue dans l'historique, il suffit de la faire précéder d'un point d'exclamation (!) :
 
!! répète la dernière commande. Si la valeur de la variable $repeatmode de dbx est égale à 1, un retour chariot sur une ligne vide est alors équivalent à !!. Par défaut, $repeatmode vaut 0
!string répète la plus récente commande qui commence par la chaine string
!integer répète la commande qui est associée au numéro integer dans l'historique
!-integer répète la commande présente integer places avant la commande courante; ainsi !-1 exécute la dernière commande, !-2 l'avant-dernière

On peut utiliser la commande !! pour faire du pas à pas dans le programme; ainsi l'exemple suivant permet d'avancer dans l'exécution du programme par pas de 5 lignes :

(dbx) next 5
...
(dbx) !!
(!! = next 5)
Un autre usage pratique est le rappel d'une commande par le début de son nom. Cela s'applique jusqu'à ce qu'une commande plus récente avec le même début de nom soit entrée.
En utilisant !integer, on rappelle n'importe quelle commande de l'historique.

L'éditeur d'historique
L'éditeur d'historique, hed, permet d'utiliser l'éditeur de texte référencé sur n'importe quelle commande présente dans l'historique de dbx. Lors de l'appel à hed, dbx copie une partie ou la totalité de l'historique dans un fichier temporaire que l'on peut éditer. En quittant l'éditeur, les commandes laissées dans le fichier temporaire sont alors automatiquement exécutées par dbx.
Si la variable $editor de dbx est renseignée avec un nom d'éditeur de texte, celui-ci est alors employé. Si elle n'est pas renseignée, dbx vérifie la variable d'environnement $EDITOR et, si elle est renseignée, appelle cet éditeur de texte, autrement vi est pris par défaut.
La syntaxe pour la commande hed est :
 
hed édite uniquement la dernière ligne de l'historique (i.e. la dernière commande exécutée)
hed num1 édite la ligne num1 de l'historique
hed num1,num2 édite les lignes de l'historique comprises entre la ligne num1 et la ligne num2 incluses
hed all édite la totalité de l'historique

Par défaut, dbx n'affiche pas les commandes exécutées suite à l'utilisation de hed (la variable prédéfinie $pimode vaut 0). Si $pimode vaut 1, dbx affiche les commandes lorsqu'il les exécute.
 

Création et destruction d'aliases pour dbx

On peut créer des aliases pour les commandes dbx. On peut les employer comme n'importe quelle commande dbx. Lorsque dbx rencontre un alias, il le développe suivant sa définition.
dbx possède un ensemble d'aliases prédéfinis que l'on peut modifier ou détruire.
De plus, on peut inclure les définitions des aliases dans le fichier .dbxinit afin qu'ils soient définis pour chaque session de déboguage.

Listage des aliases
On peut afficher l'ensemble des aliases avec la commande alias :
 
alias affiche tous les aliases existants
alias name affiche la définition de l'alias name

Création d'aliase de commandes
On définit de nouveaux aliases avec la commande alias :
 
alias name command
  définit name comme un alias de command
alias name "string"
  définit name comme un alias de string. Avec cette forme de la commande alias, on peut mettre des arguments de commandes
alias name (arg1 [,...argN])
  définit name comme un alias de string. arg1 à argN sont des arguments de l'alias, apparaissant dans la définition string. Lorsque l'on utilise l'alias, on doit fournir des valeurs pour ces arguments, que dbx substitue alors à string

La forme la plus simple d'un alias est la redéfinition d'une commande dbx avec un nom plus court, c'est le cas pour un bon nombre d'aliases prédéfinis :

(dbx) alias gf givenfile
(dbx) alias gf
"givenfile"
(dbx) gf
No current givenfile
Des définitions plus complexes d'aliases nécessitent plus que le nom de la commande. Dans ces cas, il faut alors inclure toute la définition de l'alias dans des double quotes ("). Il faut utiliser le caractère antislash (\) pour inclure le caractère double quote comme partie de la définition de l'alias. Par exemple, on peut définir un alias court pour afficher la valeur d'une variable que l'on examine fréquemment :
(dbx) alias pa "print \"a = \", a"
(dbx) alias pa
"print  "a = ", a"
(dbx) pa
a = 3
On peut aussi définir un alias à qui on doit transmettre des arguments. Lorsque l'on utilise l'alias il faut inclure des valeurs pour les arguments. dbx substitue alors les valeurs fournies aux arguments de la définition de l'alias :
(dbx) alias p(arg1, arg2, arg3, arg4) "print '|arg1|arg2|arg3|arg4|'"
(dbx) alias p
(arg1, arg2, arg3, arg4) "print '|arg1|arg2|arg3|arg4|'"
L'alias p reçoit 4 arguments et les affiche avec des barres verticales (|) de part et d'autre :
(dbx) p(1,2,3,4)
(dbx) p( first, second, 3rd,4)
| first| second| 3rd|4|
Dans cet exemple, dbx a préservé les espaces insérés lors de l'appel à l'alias.
On peut aussi omettre des arguments en appelant l'alias mais il faut laisser la virgule comme séparateur :
(dbx) p(a,,b,c)
|a||b|c|
(dbx) p(,first missing, preceding space, )
||first missing| preceding space| |


Destruction d'aliases de commandes
La commande unalias détruit l'alias fourni en argument. On peut détruire des aliases prédéfinis mais ils sont restaurés lors de la prochaine session dbx.
 

Recording et Playing Back d'input et output de dbx

dbx permet de dupliquer les commandes passées (l'entrée ou input de dbx) et d'enregistrer les valeurs en sortie (ou output de dbx). dbx sauvegarde l'information capturée dans des fichiers, ce qui permet de créer des scripts réutilisables pour des sessions ultérieures de dbx.

Enregistrement des commandes entrées
La commande record input démarre la session d'enregistrement des commandes entrées. Une fois cela fait, toutes les commandes données à dbx sont copiées dans le fichier spécifié. Si ce fichier existe déjà, dbx ajoute les informations à la fin de celui-ci. On peut avoir simultanément plusieurs sessions d'enregistrement.
A chaque session d'enregistrement est assigné un numéro lorsque l'on l'initialise. Ce numéro est utile pour arrêter l'enregistrement avec la commande unrecord.
Ensuite, la commande playback input appliquée au fichier de commandes crée permet d'exécuter à nouveau toutes les commandes s'y trouvant.

(dbx) record input script
[4] record input script (0 lines)
Si aucun nom de fichier n'est spécifié, dbx crée un fichier temporaire dans le répertoire /tmp. Le nom de ce fichier est stocké dans la variable $defaultin que l'on peut connaitre en faisant :
(dbx) print $defaultin
Il est préférable de spécifier un nom de fichier car les fichiers temporaires de dbx sont détruits en fin de session de déboguage.

Fin d'une session d'enregistrement
Pour terminer une session d'enregistrement (d'input ou d'output), il faut utiliser la commande unrecord :
 
unrecord session1 [, session2 ...]
  termine les sessions spécifiées et ferme leur fichier respectif
unrecord all termine toutes les sessions et ferme tous les fichiers

Par exemple, la commande suivante arrête la session 4 :

(dbx) unrecord 4
la commande suivante arrête toutes les sessions :
(dbx) unrecord all
La commande status ne fournit pas d'information sur les sessions d'enregistrement.

Exécution d'enregistrements des commandes entrées
On utilise la commande playback input pour exécuter les commandes enregistrées avec la commande record input. Deux aliases existent pour la commande playback input : pi et source. Si on ne spécifie pas de nom de fichier, dbx utilise le fichier temporaire courant crée par la commande record input. Si la variable $pimode de dbx est non nulle alors les commandes exécutées sont affichées. La valeur par défaut est zéro.

Enregistrement des affichages
On utilise la commande record output pour démarrer une session d'enregistrement des affichages dans dbx. Durant une telle session, dbx copie sa sortie écran vers un fichier. Si le fichier spécifié existe déjà, dbx ajoute les informations à la fin de celui-ci. On peut démarrer autant de sessions d'enregistrement que nécessaire.
Par défaut, les commandes entrées ne sont pas copiées vers le fichier de sortie; si la variable $rimode est non nulle alors dbx fait aussi une copie des commandes entrées.
A chaque session d'enregistrement est assigné un numéro lorsque l'on l'initialise. Ce numéro est utile pour arrêter l'enregistrement avec la commande unrecord.
La commande record output est très utile lorsque la sortie écran est trop importante pour tenir dans un seul écran. Dans dbx, on utilise la commande playback output pour visualiser les informations enregistrées. Hors dbx, cela peut se faire avec un éditeur de text comme vi.

Pour enregistrer les sorties dans un fichier appelé gaffa :

(dbx) record output gaffa
Pour enregistrer les commandes et les sorties :
(dbx) set $rimode = 1
(dbx) record output gaffa
Si aucun nom de fichier n'est spécifié, dbx crée un fichier temporaire dans le répertoire /tmp qui sera détruit à la fin de la session dbx. Il est donc préférable de donner un nom à la commande record output. Le nom du fichier temporaire est stocké dans la variable $defaultout que l'on peut connaitre avec :
(dbx) print $defaultout


Exécution d'enregistrements des affichages
La commande playback output affiche les sorties enregistrées avec la commande record output. Elle fonctionne de manière analogue à la commande UNIX cat. Si on ne spécifie pas de nom de fichier, dbx utilise le fichier temporaire courant crée par la commande record output.

(dbx) playback output script


Liste des sessions d'enregistrements actives
La commande record affiche toutes les sessions record input et record output actives :

(dbx) record
[4] record input /usr/demo/script (12 lines)
[5] record output /tmp/dbxoXa17992 (5 lines)

Exécution de scripts dbx

On peut créer des scripts de commandes dbx en utilisant un éditeur de texte classique puis les exécuter ensuite à l'aide de la commande playback input (ou pi). C'est un mode pratique pour créer et exécuter des scripts de test.
On peut inclure des commentaires dans de tels scripts. Pour cela, il faut que la ligne commence par le caractère dièse (#). Pour inclure l'opérateur # dans un script, il faut mettre deux caractères # consécutifs.

Retour en début de page

_____________________________________

Examen et modification des données

 

Utilisation d'expressions

De nombreuses commandes dbx acceptent une ou plusieurs expressions comme arguments. Les expressions peuvent être des constantes, des variables dbx, des variables de programme et des opérateurs. Cette partie s'intéresse aux opérateurs et aux constantes. Les variables dbx sont traitées dans la partie création et destruction de variables dbx. et les variables du programme dans la partie affichage et modification de variables du programme.

Opérateurs
En général, dbx reconnait la plupart des opérateurs du C, du Fortran 77 et du Pascal. dbx possède aussi ses propres opérateurs. Les opérateurs suivent les règles de priorité du C.
 
 
Opérateur Description
not opérateur unaire renvoyant faux si l'opérande est vrai
or opérateur logique binaire renvoyant vrai si un des deux opérandes est vrai ou non nul
xor opérateur binaire renvoyant le OR exclusif de ses opérandes
/ opérateur binaire de division
div opérateur binaire divisant ses opérandes après leur conversion en entier
mod opérateur binaire renvoyant op1 modulo op2
#exp opérateur unaire retournant l'adresse de la ligne source spécifiée par exp
"file"#exp opérateur unaire retournant l'adresse de la ligne source spécifiée par exp dans le fichier file
proc#exp opérateur unaire renvoyant l'adresse de la ligne source spécifiée par exp dans le fichier contenant la procédure proc

L'opérateur # prend le numéro de ligne spécifié par l'expression qui le suit et renvoie l'adresse de cette ligne de code source. Si l'opérateur est précédé d'un nom de fichier entre double quote ("), il renvoie l'adresse de la ligne de code source du fichier spécifié. Si l'opérateur # est précédé par le nom d'une procédure alors dbx identifie le fichier source qui la contient et renvoie l'adresse de la ligne de code source dans ce fichier.
Comme le caractère # indique le début d'une ligne de commentaires dans les scripts dbx, il faut en mettre deux consécutifs pour inclure l'opérateur # dans un tel script.

Opérateurs du langage C reconnus par dbx :
 
Type Opérateurs
Unaire !  &  +  -  *  sizeof()
Binaire % << >> == <= >= != <> & && | || + - * / [] -> .

Le OR exclusif du langage C, "^", n'est pas supporté par dbx; il faut employer l'opérateur xor de dbx.

Opérateurs du Pascal reconnus par dbx :
 
Type Opérateurs
Unaire not  ^  +  -
Binaire mod  =  <=  >=  <>  <  >  and  or  +  -  *  /  div  []

Opérateurs du Fortran 77 et Fortran 90 reconnus par dbx :
 
Type Opérateurs
Unaire +  -
Binaire +  -  *  /  %

Les indices de tableaux en Fortran 77 ou Fortran 90 peuvent être mis dans des crochets, [ ], ou des parenthèses, ( ), et l'opérateur de sélection de champ, %, du Fortran 90 est reconnu. Par contre dbx ne reconnait pas les opérateurs logiques comme .or. ou .TRUE. .

Constantes
On peut utiliser des contantes numériques ou des chaines de caractères mais les expressions ne peuvent pas contenir des constantes définies par le #define du préprocesseur du langage C.
 

  • Constantes numériques
  • On peut utiliser n'importe quelle constante valide entière ou flottante. Par défaut, dbx suppose que les constantes numériques sont décimales. On peut mettre en octal la base de représentation par défaut en affectant une valeur non nulle à la variable $octin. De même pour l'hexadécimal avec la constante $hexin. Si les deux sont définies alors $hexin a préséance.
    On peut imposer le type par défaut des valeurs en entrée à l'aide des préfixes "0x" pour l'hexadécimal ou "0t" pour le décimal.
    Par défaut, dbx affiche la valeur des constantes numériques en décimal. On peut mettre la base pour la représentation en octal en donnant une valeur non nulle à la variable $octints de dbx. On peut mettre la base pour la représentation en hexadécimal en donnant une valeur non nulle à la variable $hexints de dbx. Si les deux sont définies alors $hexints a préséance.
     
  • Constantes chaines de caractères
  • La plupart des expressions de dbx ne peuvent contenir des constantes chaines de caractères. Les commandes print et printf sont deux commandes de dbx qui acceptent des chaines de caractères comme arguments. On peut utiliser la commande set pour affecter une valeur chaine de caractères à une variable dbx.
    Les constantes chaines de caractères peuvent aussi être utilisées comme arguments pour les functions appelées de manière interactive.
    On peut utiliser soit les double quotes (") soit les simples quotes avant (') pour délimiter les constantes chaines de caractères dans dbx. En général dbx reconnait les caractères suivants dans les chaines de caractères entre quotes :
    \\  \n  \r  \f  \b  \t  \'  \"  \a
    Délimiter une chaine de caractères avec les simples quotes arrières (`) indique que l'ensemble de la chaine de caractères est le nom d'un élément du programme.
     

    Affichage d'expressions

    dbx fournit les commandes suivantes pour afficher les valeurs des expressions :
     
    print  [exp1 [, exp2, ...] ]
      affiche les valeurs des expressions spécifiées
    printd [exp1 [, exp2, ...] ]
      affiche les valeurs des expressions spécifiées en décimal (pd est un alias pour printd)
    printo [exp1 [, exp2, ...] ]
      affiche les valeurs des expressions spécifiées en octal (po est un alias pour printo)
    printx [exp1 [, exp2, ...] ]
      affiche les valeurs des expressions spécifiées en hexadécimal (px est un alias de printx)

    Si la donnée affichée est de type pointer, dbx utilise le format spécifié dans la variable $addrfmt ou $addrfmt64 (uniquement pour les processus 64 bits).
     
    printf string [, exp1 [, exp2, ...] ]
      affiche les valeurs des expressions spécifiées dans le format spécifié par string

    Transtypage

    On peut utiliser des types de données pour faire des conversions de type (transtypage ou casting) en insérant le type de données entre parenthèses avant l'expression à convertir :
    (dbx) print (int) 'b'
    98
    (dbx) print (char) 67
    'C'
    La syntaxe est la même que pour le transtypage en langage C.
     

    Qualification de noms d'éléments de programme

    On peut utiliser le même nom pour différents éléments de programme comme les variables, les functions, les étiquettes se situant dans différents endroits du programme. C'est plus pratique et il n'y a pas de risque d'ambiguité. Ainsi on peut utiliser un compteur temporaire "i" dans plusieurs functions. La portée de chaque variable est locale, l'espace mémoire alloué est pour elle lors de l'entrée dans la function et libéré lors de la sortie. Cependant, il est parfois nécessaire de distinguer plusieurs occurrences d'un même nom.
    dbx autorise les références sans ambiguité à tous les éléments du programme en utilisant les noms des fichiers source et des routines comme informations qualificatives. Pour déterminer le nom complet de la version active d'un nom d'élément, on utilise la commande which. Pour trouver tous les noms complets de toutes les versions d'un nom, on utilise la commande whereis. dbx cherche dans la totalité du programme (ou une partie seulement) toutes les occurrences du nom et renvoie les noms complets. L'étendue de la recherche est déterminée par la valeur de la variable $whereisdsolimit de dbx. Par défaut sa valeur est 1 et alors seul l'exécutable principal est parcouru. Si la valeur est 0 tous les fichiers objects sont parcourus. Pour obtenir les n premières occurrences, il suffit de lui affecter la valeur n.

    Le nom complètement déterminé d'un élément de programme permet de référencer des variables de même nom au sein d'une procédure mais aussi des éléments de programme à l'extérieur de la pile d'appels active.
    dbx complète le nom avec le fichier, la procédure, un bloc ou une structure.

    mrx.main.i
    Dans cet exemple i est le nom de la variable, main est une procédure dans laquelle elle apparait et mrx est le fichier source (sans l'extension) dans lequel la procédure est définie.

    dbx fournit un nom spécial, __aout, pour la base de l'exécutable. Ainsi on peut utiliser __aout.main pour faire référence à la function C appelée main de l'exécutable. On peut aussi utiliser le nom de l'exécutable pour référencer une function. Pour les variables présentes dans les librairies dynamiques (objets DSO), la règle est la même : libc.strcpy fait référence à la function strcpy de la librairie libc.so.1 .

    Enfin, on peut avoir des fichiers portant le même nom dans différents répertoires. dbx lève l'ambiguité en préfixant le nom complet par une étiquette numérique. Ainsi deux fichiers myfile.c seront référencés de manière globale dans le programme par __aout._$1_myfile et __aout._$1_myfile. Les commandes which et whereis permettent de connaitre cette étiquette.
     
     

    Affichage et modification de variables du programme

    On peut utiliser les valeurs de variables du programme dans des expressions dbx. On peut aussi modifier ces valeurs lorsque l'exécution du programme a lieu sous le controle de dbx.

    Portée d'une variable
    On peut accéder à la valeur d'une variable uniquement lorsque l'on se trouve dans sa portée (zone de visibilité), i.e. si le bloc ou la procédure auquel elle est associée est actif. Dans la pratique, cela signifie que les variables locales d'une procédure ne sont visibles qu'à l'intérieur de cette routine et à partir des procédures appelées par celle-ci.

    Affichage de la valeur d'une variable
    On peut afficher la valeur d'une variable à l'aide des commandes printd, printf, printo et printx.
    Pour afficher un tableau dans son intégralité, il suffit de donner son nom comme argument de la commande print :

    (dbx) print array
    Pour afficher un seul élément ...
    (dbx) print array[5]
    Modification de la valeur d'une variable
    La commande assign permet de changer la valeur de variables existant dans le programme. Elle s'applique aussi aux valeurs des registres du processeur. La syntaxe de cette commande est :
    assign variable = expressionassigne la valeur de expression à la variable du programme variable
    Par exemple
    (dbx) assign x = 27
    27
    (dbx) assign y = 37.5
    37.5
    Si dbx renvoie une erreur, types incompatibles, lors de l'assignation d'une valeur à un pointer, le transtypage permet de réalisation cette affectation.

    Conflits entre nom de variables et mots-clés
    Il est préférable de ne pas appeler des variables de programme avec le nom de mots-clés dbx. Si c'est le cas, la tentative d'utilisation de la variable dans une commande dbx entraine une syntax error. On peut forcer dbx à la traiter comme une variable en l'entourant de parenthèses :

    (dbx) print in
    print in
          ^ syntax error
    (dbx) print (in)
    34
    all, and, at, div, if, in, mod, not, or, pgrp, pid, sizeof, to, xor sont des nots-clés.

    Distinction majuscules/minuscules
    La sensibilité de dbx aux majuscules/minuscules dépend de la valeur de la variable $casesense :
    2 le langage dans lequel la variable est définie est pris en compte (le langage C/C++ est sensible aux majuscules/minuscules ce qui n'est pas le cas de Pascal, Fortran)
    1 la distiction est toujours faite
    0 la distinction n'est jamais faite

    Il faut noter que les noms de fichiers sont toujours sensibles aux majuscules/minuscules puisqu'il s'agit de noms de fichiers UNIX.
     

    Affichage/modification de variables d'environnement utilisées par le programme

    On peut controler les valeurs des variables d'environnement utilisées par le programme sans affecter le shell. Les commandes printenv, setenv et unsetenv de dbx controlent l'environnement de déboguage mieux que leur équivalent csh controlent l'environnement shell. Toutefois les modifications n'agissent que durant le déboguage du programme. dbx transmet les valeurs données par la commande printenv au shell comme étant l'environnement à utiliser par les commandes run et rerun.
    Les commandes suivantes controlent les variables d'environnement du programme :
     
    printenv affiche la liste des variables d'environnement affectant le programme débogué
    setenv idem que printenv
    setenv VAR définit la variable VAR
    setenv VAR value
      affecte la valeur value à la variable VAR, value n'étant pas une variable dbx
    setenv VAR $var
      affecte la valeur $var à la variable VAR, $var étant une variable dbx
    setenv VAR "charstring"
      affecte la chaine charstring à la variable VAR
    unsetenv VAR retire la variable d'environnement VAR

    La modification des variables d'environnement PAGER et EDITOR, entraine un comportement non défini de dbx.
     

    Affichage des déclarations de type

    La commande whatis affiche la déclaration de type de la variable spécifiée ou de la procédure du programme
    (dbx) whatis i
    int i;
    Pour une procédure, dbx renvoie le type retourné ainsi que la déclaration des différents arguments
    (dbx) whatis foo
    int foo(i)
    int i;
    (dbx) whatis main
    int main (argc, argv)
    int argc;
    char** argv;

    Suivi de la stack

    A chaque procédure exécutée, le programme stocke dans la stack (pile) active les informations relatives à l'appel effectué. Ainsi la stack contient les arguments transmis à la procédure, toutes ses variables locales. Chaque procédure dans la stack définit un niveau d'activation ou frame. La procédure la plus récemment appelée porte le numéro 0, celle qui vient de l'appeler porte le numéro 1 et ainsi de suite jusqu'au dernier niveau d'activation qui est le programme principal.
    La stack détermine la portée de nombreuses commandes et expressions de dbx. A moins de qualifier complètement une variable, dbx suppose que les variables référencées sont locales au niveau d'activation courant. Si ce n'est pas le cas, dbx parcourt les niveaux précédents d'activation dans la stack jusqu'à ce qu'il trouve la variable référencée. Le nombre maximal de niveaux d'activation est donnée par la variable $stacktracelimit et sa valeur par défaut est 100.

    Affichage de traces dans la stack
    La commande where affiche les traces de la stack, i.e. les niveaux d'activation courants de la stack.
    Si on compile un programme sans l'option -g ou avec l'option -g0, peu d'informations de déboguage sont présentes dans le fichier objet et dbx connait juste le nombre d'arguments des routines au lieu de la séquence d'appel complète des routines.

    Déplacement dans la stack
    Les commandes up et down permettent de se déplacer entre les niveaux d'activation de la stack dont la syntaxe est la suivante :
     
    up   [num] remonte dans la stack du nombre de niveau spécifié, le défaut est un niveau
    down [num] descend dans la stack de nombre de niveau spécifié, le défaut est un niveau

    Le fait de se déplacer dans la stack entraine une modification de la visibilité. En effet à moins de qualifier complètement une variable, dbx suppose toujours que les variables référencées sont locales au niveau d'activation courant.

    Déplacement vers une routine spécifiée
    La commande func permet de se déplacer au sein de la stack active. On peut spécifier le nouveau niveau d'activation avec soit le nom de la routine soit le numéro du niveau d'activation.
     
    func {activation_level | procedure}
      change le niveau d'activation courant en utilisant soit le numéro du niveau soit le nom de la routine. En cas d'appels récursif, l'appel le plus récent est alors pris
    func affiche le nom de la routine correspondant au niveau d'activation

    Le fait de se déplacer dans la stack entraine une modification de la visibilité. En effet à moins de qualifier complètement une variable, dbx suppose toujours que les variables référencées sont locales au niveau d'activation courant. De même, dbx prend le fichier source contenant le code source de la routine comme fichier source courant et se place sur la première ligne.
    Si on utilise la commande func pour aller dans une routine qui n'est pas dans la stack active, dbx ne change que le fichier source courant et se place sur sa première ligne.

    Affichage des informations du niveau d'activation
    La commande dump affiche les informations des variables du niveau d'activation
     
    dump affiche les informations des variables de la routine courante
    dump procedure
      affiche les informations des variables de la routine spécifiée. Celle-ci doit être active
    dump . affiche les informations des variables de toutes les procédures de tous les niveaux d'activation

    Appels interactifs de functions
    On peut appeler de manière interactive des routines du programme au travers de dbx. Si la routine retourne une valeur, on peut utiliser celle-ci au sein d'une expression dbx.

    Retour au début de la page

    _____________________________________

    Controle de l'exécution du programme

    Généralement, un programme s'exécute jusqu'à la fin ou lorsqu'il rencontre une erreur fatale. On peut utiliser dbx pour arrêter le programme sous certaines conditions, faire du pas à pas, arrêter l'exécution lors de la réception d'un signal et exécuter des commandes conditionnelles basées sur l'état du programme.
     

    Mise en place de breakpoints

    Les breakpoints (points d'arrêt) permettent d'arrêter l'exécution du programme. Ils peuvent être inconditionnels, le programme s'arrête à chaque passage ou bien conditionnels, le programme s'arrête seulement si un test spécifié est vérifié.
    Il faut noter que tous les breakpoints arrêtent le programme avant d'exécuter la ligne sur laquelle ils sont placés.
    Chaque breakpoint reçoit un numéro lors de sa création; on l'utilise dans diverses commandes qui permettent de gérer les points d'arrêt.

    Points d'arrêt inconditionnel
    Pour mettre un point d'arrêt inconditionnel, il suffit de spécifier l'endroit où l'on veut que le programme s'arrête à l'aide d'une des formes de la commande stop :
     
    stop at met un point d'arrêt sur la ligne courante
    stop at line met un point d'arrêt sur la ligne spécifiée
    stop in procedure
      met un point d'arrêt dès l'entrée dans la procédure. L'exécution s'arrête pour tout clone ou inlining de la procedure
    stop at file:line
      met un point d'arrêt sur la ligne spécifiée du fichier spécifié

    Point d'arrêt conditionnel
    Le point d'arrêt inconditionnel est la forme la plus simple du point d'arrêt : le programme s'arrête à chaque passage. D'un autre coté le point d'arrêt conditionnel arrête le programme uniquement si une condition spécifiée est vérifiée. Les deux conditions que l'on peut tester sont :

    1. est-ce que la valeur d'une variable ou d'une donnée en mémoire a changé ?
    2. est-ce que cette expression est vraie ?
    Arrêt du programme si une variable ou une donnée en mémoire a changé
    En incluant une variable dans la commande stop, on peut faire arrêter dbx si la valeur de la variable ou le contenu de la donnée en mémoire a changé.
    Si on ne fournit que le nom d'une variable alors dbx arrête le programme si sa valeur a changé depuis la dernière fois que dbx l'a testée. Si à la place d'un nom de variable, on met une expression de type pointer, dbx vérifie la donnée pointée. Si la donnée pointée est de tpe structure, alors dbx vérifie cette structure. Si l'expression fournie à dbx n'est pas de type pointer alors dbx évalue l'expression et utilise le résultat comme une adresse en mémoire. Le point d'arrêt stoppe le programme si le contenu de la case mémoire (32 bits) a changé depuis la dernière vérification par dbx.
    La fréquence à laquelle dbx vérifie la valeur d'une variable ou d'une donnée en mémoire dépend de la manière dont le point d'arrêt a été mis en place.
     
    stop [expression|variable]
      inspecte la valeur avant d'exécuter chaque ligne source. Si expression est de type pointer, la donnée pointée est considérée et suivie jusqu'à ce qu'elle change. Si expression n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression est alors vue comme une adresse mémoire)
    stop [expression|variable] at line
      inspecte la valeur à la ligne source spécifiée : arrêt si elle a changé. Si expression est de type pointer, la donnée pointée est considérée; dans le cas contraire, dbx considère les 32bits se trouvant à cette adresse (expression est alors vue comme une adresse mémoire)
    stop [expression|variable] in procedure
      inspecte la valeur à chaque ligne source de la procédure spécifiée. Si expression est de type pointer, la donnée pointée est considérée; dans le cas contraire, dbx considère les 32bits se trouvant à cette adresse (expression est alors vue comme une adresse mémoire)

    Fast data breakpoints
    On peut utiliser des points de suivi rapide, data breakpoints, avec la commande stop. Un tel point suit une variable ou une adresse mémoire spécifiée en limitant l'impact sur les performances du programme débogué.
    En effet, dbx utilise un mécanisme de verrouillage de la mémoire virtuelle qui permet au programme de s'exécuter normalement jusqu'à ce que la variable suivie change effectivement.
    Le programme débogué s'arrête seulement lorsque la page mémoire virtuelle contenant cette variable subit une opération d'écriture. Si la valeur de la variable suivie ne change pas, dbx continue l'exécution du processus, autrement dbx signale la modification.
    Sans ce mécanisme dbx vérifie la valeur après chaque instruction ... et fait donc du pas à pas.

    dbx a malgré tout besoin de ce mécanisme du pas à pas lorsque la commande stop contient une expression à suivre, telle que (global est une variable)

    stop if global == 1
    La performance du programme débogué peut être fortement améliorée en ajoutant une variable à suivre dans la commande. Par exemple avec
    stop global if global == 1
    Cela indique au débogueur de vérifier l'expression global == 1 seulement si la valeur de global a changé. Dans les cas ou l'expression à suivre ne dépend pas d'une variable particulière comme pour stop if global == 3 * x, le pas à pas est la seule approche pour aboutir.

    Arrêt du programme si une expression est vraie
    En incluant un test dans une commande stop, on peut faire arrêter dbx si la valeur d'une expression est vraie. On peut employer n'importe quelle expression numérique valide pour le test. Si le résultats de l'expression est non nul, l'expression est vraie et le test alors positif.

    La fréquence à laquelle dbx vérifie la valeur d'une variable ou d'une donnée en mémoire dépendent de la manière dont le point d'arrêt a été mis en place.
     
    stop if expression
      évalue l'expression avant d'exécuter chaque ligne source. L'exécution du code est alors très lente
    stop at line if expression
      évalue l'expression à la ligne spécifiée
    stop in procedure if expression
      évalue l'expression à chaque ligne source de la procédure spécifiée

    Points d'arrêt conditionnel combinant variable et tests d'expression
    On peut créer des points d'arrêt conditionnel qui combine à la fois une variable et des tests d'expression. Il faut alors que toutes les composantes soient vraies pour que l'arrêt ait lieu. Les formes suivantes de la commande stop combinent variable et tests d'expression :
     
    stop [expression1|variable] if expression2
      teste les deux conditions avant chaque ligne source : arrêt si les deux sont vérifiées. Si expression1 est de type pointer, la donnée pointée est considérée et suivie jusqu'à ce qu'elle change. Si expression1 n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression1 est alors vue comme une adresse mémoire)
    stop [expression1|variable] at line if expression2
      teste les deux conditions à la ligne source spécifiée : arrêt si les deux sont vérifiées. Si expression1 est de type pointer, la donnée pointée est considérée et suivie jusqu'à ce qu'elle change. Si expression1 n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression1 est alors vue comme une adresse mémoire)
    stop [expression1|variable] in procedure if expression2
      teste les deux conditions à chaque ligne source de la procédure spécifiée : arrêt si les deux sont vérifiées. Si expression1 est de type pointer, la donnée pointée est considérée et suivie jusqu'à ce qu'elle change. Si expression1 n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression1 est alors vue comme une adresse mémoire)

    Poursuite de l'exécution après un point d'arrêt

    La commande cont permet de reprendre l'exécution du programme après n'importe quel point d'arrêt. Dans le cas le plus simple, le programme continue son exécution jusqu'à la fin ou le prochain point d'arrêt. On peut aussi faire poursuivre dbx jusqu'à une ligne source ou une procédure spécifiée, un peu comme un point d'arrêt temporaire, à usage unique. La syntaxe de la commande cont est
     
    cont continue l'exécution avec la ligne courante
    cont [at|to] line
      place un point d'arrêt temporaire sur la ligne source spécifiée puis reprend l'exécution sur la ligne courante. Lorsque le programme atteint ce point d'arrêt sur la ligne line, dbx stoppe le programme et détruit le point d'arrêt temporaire. Les mots-clés at et to sont équivalents
    cont in procedure
      place un point d'arrêt temporaire à l'entrée de la procédure spécifiée puis reprend l'exécution sur la ligne courante. Lorsque le programme atteint ce point d'arrêt dans procedure, dbx stoppe le programme et détruit le point d'arrêt temporaire

    Si le programme s'arrête parce que dbx reçoit un signal destiné au programme, alors dbx renvoie le signal lorsque l'on poursuit l'exécution (poursuite après réception d'un signal).
     

    Trace de l'exécution du programme

    La commande trace permet de suivre la progression du programme lors de son exécution. Avec elle, on peut voir :
    1. les valeurs de variables à des points spécifiques du programme ou lorsque les valeurs des variables changent
    2. les arguments transmis en entrée et retournés en sortie des functions
    A chaque trace est assigné un nombre lors de sa création. On utilise ce nombre pour la référencer dans diverses commandes qui permettent de gérer les traces (e.g. disable, enable, delete, dans gestion des points d'arrêt, traces et commandes conditionnelles). La syntaxe de la commande trace est
     
    trace variable
      lorsque la valeur de variable change, dbx affiche l'ancienne et la nouvelle valeur
    trace procedure
      lors de l'entrée et de la sortie de la procédure, dbx affiche les valeurs des paramètres transmis
    trace [expression|variable] at line
      à chaque passage sur la ligne spécifiée, dbx affiche la valeur de variable si elle a changé. Si expression est de type pointer, la donnée pointée est considérée et inspectée jusqu'à ce qu'elle change. Si expression n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression est alors vue comme une adresse mémoire)
    trace [expression|variable] in procedure
      lorsque la valeur de variable change dans procedure, dbx affiche l'ancienne et la nouvelle valeur. Si expression est de type pointer, la donnée pointée est considérée et inspectée jusqu'à ce qu'elle change. Si expression n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression est alors vue comme une adresse mémoire)
    trace [expression1|variable] at line if expression2
      affiche la valeur de variable (si différente) à chaque passage sur la ligne spécifiée et si expression2 est vraie. Si expression1 est de type pointer, la donnée pointée est considérée et inspectée jusqu'à ce qu'elle change. Si expression1 n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression1 est alors vue comme une adresse mémoire)
    trace [expression1|variable] in procedure if expression2
      lorsque la valeur de variable change dans procedure, dbx affiche son ancienne et sa nouvelle valeur si expression2 est vraie. Si expression1 est de type pointer, la donnée pointée est considérée et inspectée jusqu'à ce qu'elle change. Si expression1 n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression1 est alors vue comme une adresse mémoire)

    Pour examiner les paramètres passés et les valeurs retournées par une function, on peut tracer cette function. Par exemple pour tracer la function foo

    (dbx) trace foo
    Lorsque l'on exécute le programme, dbx affiche les valeurs des arguments passés à foo à chaque appel et la valeur retournée en sortie
    (dbx) run
    [3] calling foo(text=0x10000484 = "Processing... \n", i = 4) from function main
    [4] foo returning -1 from foo
    Dans cet exemple la function foo reçoit 2 arguments : une chaine de caractères et un entier. En sortie, elle renvoie la valeur -1.

    Lorsque l'on trace une variable il faut être attentif à la confirmation que renvoie dbx : dbx peut ne pas avoir sélectionné la bonne occurrence de la variable si le même nom est employé à plusieurs endroits dans le programme. Dans ce cas il faut détruire la trace (gestion des points d'arrêt, traces et commandes conditionnelles) et en en créer une nouvelle quitte à qualifier la variable.
     

    Ecriture de commandes conditionnelles

    Une commande conditionnelle créée par la commande when est semblable à un point d'arrêt crée par la commande stop sauf que plutot arrêter le programme, dbx exécute une liste de commandes. Cette liste peut être formée de n'importe quelle commande dbx, séparées par des virgules (,) s'il y en a plus d'une. On peut aussi inclure la commande stop dans cette liste. Chaque commande conditionnelle reçoit un numéro lorsqu'elle est créée. On utilise ce nombre pour la référencer dans diverses commandes qui permettent de manipuler les commandes conditionnelles (e.g. disable, enable, delete dans gestion des points d'arrêt, traces et commandes conditionnelles). La syntaxe de la commande when est
     
    when [expression|variable] {command-list}
      inspecte la valeur avant d'exécuter chaque ligne source : si elle a changé alors exécute command-list. Si expression est de type pointer, la donnée pointée est considérée et suivie jusqu'à ce qu'elle change. Si expression n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression est alors vue comme une adresse mémoire)
    when [expression|variable] at line {command-list}
      inspecte la valeur à la ligne source spécifiée : si elle a changé alors exécute command-list. Si expression est de type pointer, la donnée pointée est considérée et suivie jusqu'à ce qu'elle change. Si expression n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression est alors vue comme une adresse mémoire)
    when [expression|variable] in procedure {command-list}
      inspecte la valeur à chaque ligne source de la procédure spécifiée : si elle a changé alors exécute command-list. Si expression est de type pointer, la donnée pointée est considérée; dans le cas contraire, dbx considère les 32bits se trouvant à cette adresse (expression est alors vue comme une adresse mémoire)
    when if expression {command-list}
      évalue expression avant d'exécuter chaque ligne source : si elle est vraie alors exécute command-list. L'exécution du programme est alors très lente
    when at line if expression {command-list}
      évalue expression sur la ligne source spécifiée : si elle est vraie alors exécute command-list
    when in procedure if expression {command-list}
      évalue expression à chaque ligne source de la procédure spécifiée : si elle est vraie alors exécute command-list
    when [expression1|variable] if expression2 {command-list}
      inspecte la valeur de variable. Si elle a changé et que expression2 est vraie alors exécute command-list. Si expression1 est de type pointer, la donnée pointée est considérée et suivie jusqu'à ce qu'elle change. Si expression1 n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression1 est alors vue comme une adresse mémoire)
    when [expression1|variable] at line if expression2 {command-list}
      inspecte la valeur de variable à chaque fois que la ligne source est exécutée. Si elle a changé et que expression2 est vraie alors exécute command-list. Si expression1 est de type pointer, la donnée pointée est considérée et suivie jusqu'à ce qu'elle change. Si expression1 n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression1 est alors vue comme une adresse mémoire)
    when [expression1|variable] in procedure if expression2 {command-list}
      inspecte la valeur de variable à chaque ligne source de procedure. Si elle a changé et que expression2 est vraie alors exécute command-list. Si expression1 est de type pointer, la donnée pointée est considérée et suivie jusqu'à ce qu'elle change. Si expression1 n'est pas de type pointer, dbx considère la donnée (32bits) se trouvant à l'adresse (expression1 est alors vue comme une adresse mémoire)

    Gestion des points d'arrêt, traces et commandes conditionnelles

    dbx fournit des commandes qui permettent d'activer, de désactiver, détruire et examiner le statut des points d'arrêt, traces et commandes conditionnelles que l'on crée dans un programme.
    A chaque point d'arrêt, trace et commande conditionnelle est assigné un nombre lors sa création. Ces nombres servent d'identifiant pour les diverses commandes de gestions de ces controles.

    Liste des points d'arrêt, traces et commandes conditionnelles
    La commande status affiche l'ensemble des points d'arrêt, traces et commandes conditionnelles qui sont crées et indique s'ils sont activés ou désactivés.
    Si on considère les commandes suivantes lors du déboguage d'un programme appelé test :

    (dbx) stop in foo
    Process     0: [3] stop in foo
    (dbx) rerun
    Process 22631 (test) started
    [3] Process 22631 (test) stopped at [foo:38 ,0x10001050]
      38  r = foo2(i+1)
    (dbx) trace total
    Process 22631: [4] trace total in foo
    (dbx) when at 60 {print i,j }
    Process 22631: [5] when at "/usr/var/tmp/dbx_examples/test.c":60 {print i,j }
    La commande status renvoie alors
    (dbx) status
    Process 22631: [3] stop in foo
    Process 22631: [4] trace total in foo
    Process 22631: [5] when at "/usr/var/tmp/dbx_examples/test.c":60 {print i,j }


    Désactivation de points d'arrêt, traces et commandes conditionnelles
    La commande disable permet de désactiver temporairement un point d'arrêt, une trace ou une commande conditionnelle, i.e. le rendre inopérant et sans effect sur l'exécution du programme. dbx garde trace de toutes les informations concernant un point d'arrêt, une trace ou une commande conditionnelle désactivé. La syntaxe de cette commande est :
     
    disable item [, item...]
      désactive le(s) point(s) d'arrêt, trace(s), commandes conditionnelles spécifié(e)(s). Cette commande n'a pas d'effet sur un objet déjà désactivé.

    Pour désactiver la commande conditionnelle de l'exemple précédent, il suffit de faire

    (dbx) disable 5
    (dbx) status
    Process 22631: [3] stop in foo
    Process 22631: [4] trace total in foo
    Process 22631: [5] (disabled) when at "/usr/var/tmp/dbx_examples/test.c":60 {print i,j }
    Activation de points d'arrêt, traces et commandes conditionnelles
    La commande enable annule les effets de la commande disable. Le point d'arrêt, trace ou commande conditionnelle spécifiée est restauré et affecte l'exécution du programme. La syntaxe de la commande est
     
    enable item [, item...]
      réactive le(s) point(s) d'arrêt, trace(s), commandes conditionnelles spécifié(e)(s).

    Pour réactiver la commande conditionnelle désactivée quelques lignes au-dessus, il suffit de faire

    (dbx) enable 5
    (dbx) status
    Process 22631: [3] stop in foo
    Process 22631: [4] trace total in foo
    Process 22631: [5] when at "/usr/var/tmp/dbx_examples/test.c":60 {print i,j }


    Destruction de points d'arrêt, traces et commandes conditionnelles
    La commande delete permet de détruire des points d'arrêt, traces ou commandes conditionnelles
     
    delete {item [, item...] | all}
      détruit le(s) point(s) d'arrêt, trace(s), commandes conditionnelles spécifié(e)(s). Le mot-clé all entraine la destruction de tous les points d'arrêt, traces et commandes conditionnelles

    Pour détruire le point d'arrêt et la trace de l'exemple précédent, il suffit de faire

    (dbx) delete 3, 4
    (dbx) status
    Process 22631: [5] when at "/usr/var/tmp/dbx_examples/test.c":60 {print i,j }

    Utilisation des signaux

    dbx peut détecter les signaux que reçoit le programme et arrêter ce dernier si c'est demandé.

    Détection des signaux
    La commande catch permet de dire à dbx d'arrêter le programme lors de l'arrivée d'un signal précis. La commande ignore défait les effets de la commande catch. La syntaxe de ces commandes est la suivante :
     
    catch {signal|all}
      dbx arrête le programme le signal spécifique. Si le mot-clé all est employé, dbx considère tous les signaux
    ignore {signal|all}
      dbx ignore le signal spécifié. Si le mot-clé all est employé, dbx ignore tous les signaux
    catch affiche la liste de tous les signaux reçus
    ignore affiche la liste de tous les signaux ignorés

    On peut utiliser les noms et numéros des signaux données dans la manpage signal. en majuscules ou minuscules avec ou sans le préfixe SIG (à l'exception de SIGINT qui ne peut être abrégé en munuscules)

    Si dbx doit arrêter un programme sur un signal donné, cela se fera quel que soit le moment où arrive le signal. Le programme ne reçoit le signal que lorsque l'on fait repartir le programme avec la commande cont. Si le programme a une routine qui gère les signaux, le signal est transmis au programme; autrement le programme ne voit pas le signal. On peut supprimer la transmission du signasl au programme en prenant les commandes step ou next au lieu de cont.

    Poursuite de l'exécution après réception d'un signal
    La commande cont permet de poursuivre l'exécution après réception d'un signal. On peut aussi utiliser la commande cont pour envoyer un autre signal au programme que celui reçu initialement. De plus, avec la même syntaxe on peut envoyer un signal au programme, lors de la poursuite, même si le programme ne s'est pas arrêté en raison du signal reçu :
     
    cont [signal]
      continue l'exécution avec la ligne courante et envoie le signal spécifié au programme
    cont [signal] {at|to} line
      place un point d'arrêt temporaire à la ligne source spécifiée puis reprend l'exécution avec la ligne courante et envoie le signal spécifié au programme
    cont [signal] in procedure
      place un point d'arrêt temporaire pour arrêter le programme à l'entrée de procedure, puis reprend l'exécution avec la ligne courante et envoie le signal spécifié au programme

    Si le programme s'arrête car dbx a détecté un SIGINT, dbx renvoie automatiquement ce signal au programme avec

    (dbx) cont
    Si le programme contient une routine, alarm_handler, pour gérer les signaux d'alarme reçus, on peut arrêter le programme à son entrée pour la parcourir au pas à pas à l'aide de
    (dbx) cont SIGALRM in alarm_handler
    Cette commande place un point d'arrêt temporaire qui provoque l'arrêt du programme à l'entrée de la procédure alarm_handler et envoie le signal SIGALRM au programme. Lors de l'entrée dans la routine alarm_handler, le programme s'arrête et on peut faire du pas à pas.
     

    Exécution du programme point à point

    Il s'agit de faire exécuter un nombre précis de lignes source et de rendre automatiquement le controle à dbx. dbx fournit deux commandes pour réaliser ce type de progression : step et next. Dans les deux cas, dbx ne compte que les lignes qui correspondent réellement à du code source et ignore les lignes blanches ou commentées.
    Ces commandes diffèrent dans leur traitement des appels aux procédures. Lorsque step rencontre un appel à une procédure, il rentre à l'intérieur de celle-ci et continue l'exécution pas à pas en comptant les lignes dans la procédure. Par contre, lorsque next rencontre un appel à une procédure, il exécute l'appel comme une ligne classique soit sans entrer dans la procédure et sans compter les lignes qu'elle contient et reste donc dans la procédure courante.
    La portion de code suivante illustre la différence entre step et next
     55 foo( arg1, arg2 )
     56 int arg1, arg2;
     57 {
     58      if ( arg1 < arg2 ) {
     ...        ...
     78       return( 0 );
     79 }
    ...
    211 x = foo( i, j );
    212 y = 2 * x;
    Dans cet exemple, si un step est exécuté à la ligne 211 pour avancer d'une ligne, dbx autorise le processus à continuer à la ligne 58 (première ligne code de la procédure foo). Par contre, si on exécute un next, dbx exécute la ligne 211 (appel à foo) et avance le processus à la ligne 212.

    Utilisation de la commande step
    La syntaxe de la commande step est
     
    step [integer]
      exécute le nombre de lignes source spécifié en entrant dans les procédures si nécessaire. Sans argument, step n'exécute qu'une seule ligne source. S'il rencontre des points d'arrêt, step stoppe l'exécution

    Par défaut, step rentre dans les routines qui sont compiléees avec l'une des options de déboguage -g, -g2, -g3 pour lesquelles les numéros des lignes source sont disponibles dans la table des symboles. Cela ne concerne pas les routines des librairies standard car elles ne sont pas compilées avec ces options.
    On peut forcer dbx à entrer dans les routines non compilées avec ces options en modifiant la valeur de la variable $stepintoall :
     
    Valeur  Effet sur la commande step
    0 (défaut) rentre dans toutes les routines qui sont compilées avec l'une des options de déboguage -g, -g2, -g3
    1 en plus des procédures précédentes, entre dans les routines pour lesquelles le code source est disponible (même si les sauts peuvent être irréguliers)
    2 entre dans toutes les procédures. Si dbx ne peut pas trouver le source, il n'affiche pas les numéros des lignes source

    Si le programme fait appel à des librairies dynamiques (DSO), il faut mettre à 1 la variable d'environnement LD_BIND_NOW avant l'exécution du programme. Cela perlmet de ne pas considérer le run-time linker comme faisant partie du code et compliquer le déboguage

    (dbx) setenv LD_BIND_NOW 1


    Utilisation de la commande next
    La syntaxe de la commande next est
     
    next [integer]
      exécute le nombre de lignes source spécifié sans entrer dans les procédures. Sans argument, next n'exécute qu'une seule ligne source. S'il rencontre des points d'arrêt, next stoppe l'exécution

    Utilisation de la commande return
    Si en faisant du pas à pas dans une routine, on décide de ne pas finir de la parcourir de cette manière on peut utiliser la commande return pour terminer son exécution et revenir à la procédure appelante.
    La syntaxe de la commande return est
    return
      continue l'exécution jusqu'au retour à la procédure appelante
    return proc
      continue l'exécution jusqu'à la fin de la procédure spécifiée. L'exécution continue à moins de rencontrer un point d'arrêt ou d'atteindre la dernière référence de la routine appelée par proc au moment où la commande est passée

    Partir d'une ligne spécifiée

    On utilise la commande goto pour reprendre l'exécution suite à un arrêt du à la commande cont.
     
    goto line
      commence l'exécution à la ligne spécifiée. Elle ne peut reprendre qu'à partir d'une ligne source de la procédure courante

    Pour plus d'informations consultez la manpage de dbx.

    Retour au début de la page.

    _____________________________________

    Documentation SGI

    Liste complète des commandes dbx (sur le serveur SGI)

    dbx User's Guide (sur le serveur de SGI)
     

    Retour au début de la page.