Examen des données de programme

Cette section explique comment examiner, tester et modifier des données de programme.

Traitement des signaux

Le programme de débogage dbx peut soit intercepter, soit ignorer les signaux avant qu'ils ne soient envoyés à votre programme. Chaque fois que votre programme doit recevoir un signal, le programme dbx est notifié. Si le signal doit être ignoré, il est transmis à votre programme ; sinon, le programme dbx arrête le programme et vous informe qu'un signal a été intercepté. Le programme dbx ne peut pas ignorer le signal SIGTRAP s'il provient d'un processus en dehors du processus de débogage. Dans un programme à unités d'exécution multiples, un signal peut être envoyé à une unité d'exécution particulière via la sous-routine pthread_kill . Par défaut, le programme dbx s'arrête et vous informe qu'un signal a été intercepté. Si vous demandez qu'un signal soit transmis à votre programme à l'aide de la sous-commande ignore , le programme dbx ignore le signal et le transmet à l'unité d'exécution. Utilisez les sous-commandes catch et ignore pour modifier le traitement par défaut.

Dans l'exemple suivant, un programme utilise SIGGRANT et SIGREQUEST pour gérer l'allocation des ressources. Pour que le programme dbx continue chaque fois qu'un de ces signaux est reçu, entrez:

(dbx) ignore GRANT
(dbx) ignore SIGREQUEST
(dbx) ignore
CONT CLD ALARM KILL GRANT REQUEST

Le programme de débogage dbx peut bloquer des signaux vers votre programme si vous définissez la variable $sigblock . Par défaut, les signaux reçus via le programme dbx sont envoyés au programme source ou au fichier objet spécifié par le paramètre dbx ObjectFile . Si la variable $sigblock est définie à l'aide de la sous-commande set , les signaux reçus par le programme dbx ne sont pas transmis au programme source. Si vous souhaitez qu'un signal soit envoyé au programme, utilisez la sous-commande cont et fournissez le signal en tant qu'opérande.

Vous pouvez utiliser cette fonction pour interrompre l'exécution d'un programme exécuté sous le programme de débogage dbx . Le statut du programme peut être examiné avant de poursuivre l'exécution comme d'habitude. Si la variable $sigblock n'est pas définie, l'interruption de l'exécution entraîne l'envoi d'un signal SIGINT au programme. Cela entraîne l'exécution, lorsqu'elle se poursuit, d'une branche vers un gestionnaire de signaux s'il en existe un.

L'exemple de programme suivant montre comment l'exécution à l'aide du programme de débogage dbx change lorsque la variable $sigblock est définie:

#include <signal.h>
#include <stdio.h>
void inthand( ) {
        printf("\nSIGINT received\n");
        exit(0);
}
main( )
{
        signal(SIGINT, inthand);
        while (1) {
                  printf(".");
                  fflush(stdout);
                sleep(1);
        }
}

L'exemple de session suivant avec le programme dbx utilise le programme précédent comme fichier source. Lors de la première exécution du programme, la variable $sigblock n'est pas définie. Lors de la réexécution, la variable $sigblock est définie. Les commentaires sont placés entre des crochets à droite:

dbx version 3.1.
Type 'help' for help.
reading symbolic information ...
(dbx) run
.........^C                      <User pressed Ctrl-C here!>
interrupt in sleep at 0xd00180bc
0xd00180bc (sleep+0x40) 80410014         1        r2,0x14(r1)
(dbx) cont
SIGINT received
execution completed
(dbx) set $sigblock
(dbx) rerun
[ looper ]
..............^C                  <User pressed Ctrl-C here!>
interrupt in sleep at 0xd00180bc
0xd00180bc (sleep+0x40) 80410014          1        r2,0x14(r1)
(dbx) cont
....^C   <Program did not receive signal, execution continued>
interrupt in sleep at 0xd00180bc
0xd00180bc (sleep+0x40) 80410014          1         r2,0x14(r1)
(dbx) cont 2                     <End program with a signal 2>
SIGINT received
execution completed
(dbx)

Calling Procedures

Vous pouvez appeler vos procédures de programme à partir du programme dbx pour tester différents arguments. Vous pouvez également appeler des routines de diagnostic qui formatent les données pour faciliter le débogage. Utilisez la sous-commande call ou la sous-commande print pour appeler une procédure.

Affichage d'une trace de pile

Pour répertorier les appels de procédure précédant un arrêt de programme, utilisez la commande where .

Dans l'exemple suivant, le fichier d'objet exécutable, hello, se compose de deux fichiers source et de trois procédures, y compris la procédure standardmain. Le programme s'est arrêté à un point d'arrêt de la procéduresub2.

(dbx) run
[1] stopped in sub2 at line 4 in file "hellosub.c"
(dbx) where
sub2(s = "hello", n = 52), line 4 in "hellosub.c"
sub(s = "hello", a = -1, k = delete), line 31 in "hello.c"
main(), line 19 in "hello.c"

La trace de pile affiche les appels dans l'ordre inverse. A partir de la fin, les événements suivants se sont produits:

  1. Shell appelémain.
  2. mainappelésubprocédure à la ligne 19 avec des valeurss = "hello",a = -1etk = delete.
  3. subappelésub2procédure à la ligne 31 avec des valeurss = "hello"etn = 52.
  4. Le programme s'est arrêté danssub2procédure à la ligne 4.
Une partie de la trace de pile à partir du numéro de cadre0au numéro de trame1peut être affiché à l'aide de where 0 1.
(dbx)run
[1] stopped in sub2 at line 4 in file "hellosub.c"
(dbx) where 0 1
sub2(s = "hello", n = 52), line 4 in "hellosub.c"
sub(s = "hello", a = -1, k = delete), line 31 in "hello.c"
Remarque: définissez la variable de programme de débogage $noargs pour désactiver l'affichage des arguments transmis aux procédures. Définissez la variable de programme de débogage $stack_details pour afficher le numéro de cadre et le registre défini pour chaque fonction ou procédure active.

Vous pouvez également afficher des parties de la pile avec up, down, et les sous-commandes frame .

Affichage et modification des variables

Pour afficher une expression, utilisez la sous-commande print . Pour imprimer les noms et les valeurs des variables, utilisez la sous-commande dump . Si la procédure indiquée est un point, toutes les variables actives sont imprimées. Si le paramètre PATTERN est spécifié, au lieu d'afficher uniquement le symbole spécifié, tous les symboles correspondant à PATTERN sont imprimés. Pour modifier la valeur d'une variable, utilisez la sous-commande assign .

Dans l'exemple suivant, un programme C comporte une variable entière automatiquexavec la valeur 7, etsetnparamètres dans lesub2Procédure :

(dbx) print x, n
7 52
(dbx) assign x = 3*x
(dbx) print x
21
(dbx) dump
sub2(s = "hello", n = 52)
x = 21

Affichage des informations relatives aux unités d'exécution

Pour afficher des informations sur les unités d'exécution utilisateur, les mutex, les conditions et les objets d'attribut, utilisez l' unité d'exécution, mutex, conditionet sous-commandes attribute . Vous pouvez également utiliser la sous-commande print sur ces objets. Dans l'exemple suivant, l'unité d'exécution en cours d'exécution est l'unité d'exécution 1. L'utilisateur définit l'unité d'exécution en cours comme unité d'exécution 2, répertorie les unités d'exécution, imprime les informations sur l'unité d'exécution 1 et enfin imprime les informations sur plusieurs objets liés aux unités d'exécution.

(dbx) thread current 2
(dbx) thread
 thread  state-k   wchan state-u   k-tid mode held scope function
*$t1     run             running   12755   u   no   pro  main
>$t2     run             running   12501   k   no   sys  thread_1
(dbx) print $t1
(thread_id = 0x1, state = run, state_u = 0x0, tid = 0x31d3, mode = 0x1, held = 0x0, priority = 0x3c,
    policy = other, scount = 0x1, cursig = 0x5, attributes = 0x200050f8)
(dbx) print $a1,$c1,$m2
(attr_id = 0x1, type = 0x1, state = 0x1, stacksize = 0x0, detachedstate = 0x0, process_shared = 0x0,
 contentionscope = 0x0, priority = 0x0, sched = 0x0, inherit = 0x0, protocol = 0x0, prio_ceiling = 0x0)
(cv_id = 0x1, lock = 0x0, semaphore_queue = 0x200032a0, attributes = 0x20003628)
(mutex_id = 0x2, islock = 0x0, owner = (nil), flags = 0x1, attributes = 0x200035c8)

Établissement de la portée des noms

Les noms sont d'abord résolus à l'aide de la portée statique de la fonction en cours. La portée dynamique est utilisée si le nom n'est pas défini dans la première portée. Si les recherches statiques et dynamiques ne produisent pas de résultat, un symbole arbitraire est choisi et le messageusing QualifiedNameest imprimé. Vous pouvez remplacer la procédure de résolution de nom en qualifiant un identificateur avec un nom de bloc (tel que Module.Variable). Les fichiers source sont traités comme des modules nommés par le nom de fichier sans le suffixe. Par exemple, la variable x , qui est déclarée dans lesubdans le fichier hello.c , possède le nom qualifié complet hello.sub.x. Le programme lui-même a un point pour un nom.

Les sous-commandes quoi et whereis peuvent être utiles pour déterminer quel symbole est trouvé lorsque plusieurs symboles du même nom existent.

Utilisation d'opérateurs et de modificateurs dans les expressions

Le programme dbx peut afficher un large éventail d'expressions. Spécifiez des expressions avec un sous-ensemble commun de syntaxe C, avec des extensions FORTRAN.

* (astérisque) ou ^ (caret)
Indique le déréférencement de l'indirection ou du pointeur.
[ ] (crochets) ou () (parenthèses)
Indique les expressions de tableau d'indice.
. (point)
Utilisez cet opérateur de référence de zone avec des pointeurs et des structures. Cela rend l'opérateur C-> (flèche) inutile, bien qu'il soit autorisé.
& (perluète)
Extrait l'adresse d'une variable.
.. (deux points)
Sépare les limites supérieure et inférieure lors de la spécification d'une sous-section d'un tableau. Par exemple: n [ 1 .. 4 ].

Les types d'opération suivants sont valides dans les expressions:

Algébrique
=, -, *,/(division flottante), div (division intégrale), mod, exp (exponentiation)
Au niveau du bit
-, I, bitand, xor, ~, < <, > >
Logique
ou, et, pas, II, & &
Comparaison
<, >, < =, > =, < > ou ! =, = ou ==
Autre
taillede

Les expressions logiques et de comparaison sont autorisées en tant que conditions dans les sous-commandes stop et trace .

Vérification des types d'expression

Le programme de débogage dbx vérifie les types d'expression. Vous pouvez remplacer le type d'expression à l'aide d'un opérateur de changement de nom ou de transtypage. Il existe trois formes de renommage de type:

  • Typename (Expression)
  • Expression \ Typename
  • ( Nom de type ) Expression

Remarque: Lorsque vous effectuez un transtypage vers ou depuis une structure, une union ou une classe, le transtypage est justifié à gauche. Toutefois, lors du transtypage d'une classe vers une classe de base, les règles de syntaxe C++ sont respectées.

Par exemple, pour renommer la variable x où x est un entier avec une valeur de 97, entrez:

(dbx) print char (x), x \ char, (char) x, x,
'a' 'a' 'a' 97

Les exemples suivants montrent comment utiliser la forme (Typename) Expression de type renommage:

print (float) i
print ((struct qq *) void_pointer)->first_element

Les restrictions suivantes s'appliquent à la typecasting de style C pour le programme de débogage dbx :

  • Les types Fortran (integer*1, integer*2, integer*4, logical*1, logical*2, logical*4, etc.) ne sont pas pris en charge en tant qu'opérateurs de transtypage.
  • Si une variable active a le même nom que l'un des types de base ou des types définis par l'utilisateur, le type ne peut pas être utilisé comme opérateur de transtypage pour la typecasting de style C.

La sous-commande whatis imprime la déclaration d'un identificateur, que vous pouvez ensuite qualifier avec des noms de bloc.

Utilisez la construction '$$ 'Nom de l'étiquette pour imprimer la déclaration d'une balise d'énumération, de structure ou d'union.

Le type de l'expression de sous-commande assign doit correspondre au type de variable que vous avez affecté. Si les types ne correspondent pas, un message d'erreur s'affiche. Modifiez le type d'expression à l'aide d'un changement de nom de type. Désactivez la vérification de type en définissant une variable spéciale dbx debug program $unsafeassign .

Variables de pliage en minuscules et en majuscules

Par défaut, le programme dbx plie les symboles en fonction du langage en cours. Si le langage en cours est C, C + + ou non défini, les symboles ne sont pas pliés. Si la langue en cours est Fortran, les symboles sont pliés en minuscules. Le langage en cours n'est pas défini si le programme se trouve dans une section de code qui n'a pas été compilée avec l'indicateur debug . Vous pouvez remplacer le traitement par défaut par la sous-commande case .

L'utilisation de la sous-commande case sans arguments affiche le mode de cas en cours.

Le compilateur Fortran convertit tous les symboles de programme en minuscules ; ce n'est pas le cas du compilateur C. Cependant, certains compilateurs Fortran peuvent ne pas toujours générer de symboles en minuscules. Par exemple, à l'aide d'une procédure nommée proc1 dans un module nommé mod2, le compilateur XLF Fortran génère le symbole __mod2_MOD_proc1 , qui est une casse mixte. Dans de telles situations, vous devez remplacer la casse dans le programme dbx par la casse mixte .

Modification de la sortie d'impression avec des variables de programme de débogage spéciales

Utilisez la sous-commande définir pour définir les variables de programme de débogage dbx spéciales suivantes afin d'obtenir des résultats différents à partir de la sous-commande impression :

$hexints
Imprime des expressions entières au format hexadécimal.
$hexchars
Imprime les expressions de caractères au format hexadécimal.
$hexchaînes
Imprime l'adresse de la chaîne de caractères, et non la chaîne elle-même.
octints
Imprime des expressions entières dans octal.
$unions d'extension
Imprime des zones dans une union.
$jolie
Affiche les types C et C++ complexes au format pretty .
$print_dynamique
Imprime le type dynamique des objets C + +.
$show_vft
Imprime la table de fonctions virtuelles lors de l'impression des objets C + +.

Définissez et annulez la définition des variables du programme de débogage pour obtenir les résultats souhaités. Par exemple :

(dbx) whatis x; whatis i; whatis s
int x;
char i;
char *s;
(dbx) print x, i, s
375 'c' "hello"
(dbx) set $hexstrings; set $hexints; set $hexchars
(dbx) print x, i, s
0x177 0x63 0x3fffe460
(dbx) unset $hexchars; set $octints
(dbx) print x, i
0567 'c'
(dbx) whatis p
struct info p;
(dbx) whatis struct info
struct info {
    int x;
    double position[3];
    unsigned char c;
    struct vector force;
};
(dbx) whatis struct vector
struct vector {
    int a;
    int b;
    int c;
};
(dbx) print p
(x = 4, position = (1.3262493258532527e-315, 0.0, 0.0), 
c = '\0', force = (a = 0, b = 9, c = 1))(dbx) set $pretty="on"
(dbx) print p
{
    x = 4
    position[0] = 1.3262493258532527e-315
    position[1] = 0.0
    position[2] = 0.0
    c = '\0'
    force = {
        a = 0
        b = 9
        c = 1
    }
}
(dbx) set $pretty="verbose"
(dbx) print p
x = 4
position[0] = 1.3262493258532527e-315
position[1] = 0.0
position[2] = 0.0
c = '\0'
force.a = 0
force.b = 9
force.c = 1

Lorsque show_vft n'est pas défini et qu'un objet est imprimé à l'aide de la sous-commande print, la table de fonctions virtuelles (VFT) n'est pas imprimée. S'il est défini, VFT s'affiche. Par exemple :

(dbx) p *d
    B1:(int_in_b1 = 91)
    B2:(int_in_b2 = 92)
(int_in_d = 93)
(dbx) p *b2
(int_in_b2 = 20)
(dbx)set $show_vft
(dbx) p *d
    B1:(B1::f1(), int_in_b1 = 91)
    B2:(D::f2(), int_in_b2 = 92)
(int_in_d = 93)
(dbx) p *b2
(B2::f2(), int_in_b2 = 20)
(dbx)  

Lorsque print_dynamic n'est pas défini, l'objet est affiché conformément au modèle de type statique (ce qui est défini dans le code source). Sinon, il sera affiché selon le modèle du type dynamique (ce qu'était un objet avant qu'il ne soit transtypé). Par exemple :

(dbx) r
[1] stopped in main at line 57
   57   A *obj1 = new A();
(dbx) n
stopped in main at line 58
   58   A *obj2 = new B();
(dbx) n
stopped in main at line 59
   59   cout<<" a = "<<obj2->a<<" b = "<<obj2->b<<endl; 
(dbx) p *obj2
(a = 1, b = 2)
(dbx)set $print_dynamic
(dbx) print *obj2
    A:(a = 1, b = 2)
(c = 3, d = 4)
(dbx)