web-dev-qa-db-fra.com

Comment effectuer une action spécifique lorsqu'un certain point d'arrêt est atteint dans GDB?

Je cherche un moyen de faire une action lorsqu'un point d'arrêt particulier frappe dans gdb.

Fondamentalement, j'ai un peu de memleak dans mon programme. Lorsque malloc et la fonction libre frappent, je dois entrer dans la fonction (étape) et collecter des informations de base comme l'adr et la taille (en gros, y imprimer les valeurs). Une fois terminé, reprenez mon programme.

Avons-nous un bon moyen de le faire?

51
Thangaraj

Par exemple, voici comment utiliser les commandes de point d'arrêt pour imprimer la valeur de x à l'entrée dans foo chaque fois que x est positif.

break foo if x>0
commands
silent
printf "x is %d\n",x
cont
end

Si la première commande que vous spécifiez dans une liste de commandes est silent, le message habituel sur l'arrêt à un point d'arrêt n'est pas imprimé. Cela peut être souhaitable pour les points d'arrêt qui doivent imprimer un message spécifique, puis continuer. Si aucune des commandes restantes n'imprime quoi que ce soit, vous ne voyez aucun signe que le point d'arrêt a été atteint. silent n'a de sens qu'au début d'une liste de commandes de points d'arrêt.

Une application pour les commandes de point d'arrêt consiste à compenser un bogue afin que vous puissiez en tester un autre. Placez un point d'arrêt juste après la ligne de code erronée, donnez-lui une condition pour détecter le cas où quelque chose d'erroné a été fait et donnez-lui des commandes pour attribuer des valeurs correctes à toutes les variables qui en ont besoin. Terminez par la commande continue pour que votre programme ne s'arrête pas et commencez par la commande silencieuse pour qu'aucune sortie ne soit produite. Voici un exemple:

break 403
commands
silent
set x = y + 4
cont
end
57
Fredrik Pihl

Pour clarifier la réponse de Fredrik, commands (ou simplement command, semble-t-il) sait automatiquement que vous venez de définir un point d'arrêt. Autrement dit, ce que Fredrik montre n'est pas une commande break sur plusieurs lignes, ce sont deux commandes distinctes: break et commands. Cela ressemble à ceci:

(gdb) break 989 
Breakpoint 23 at 0x7fffe2761dac: file foo.cpp, line 989.
(gdb) command
Type commands for breakpoint(s) 23, one per line.
End with a line saying just "end".
>silent
>print result
>end
(gdb) c
Continuing.
$79 = {elems = {0, 0}}
(gdb) 
48
Ben

dprintf (Dynamique printf)

https://sourceware.org/gdb/onlinedocs/gdb/Dynamic-Printf.html

C'est la solution la plus pratique pour le cas spécifique de l'impression de choses:

dprintf <line>, "%u\n", variable

Il pourrait également être plus rapide que commands car il pourrait compiler et injecter du code, au lieu de redonner le contrôle à GDB pour interpréter des chaînes de commandes arbitraires. À FAIRE Je ne sais pas si cela se fait réellement. dprintf vs commands: Quelle est la différence entre dprintf vs break + commandes + continuer?

Exemple détaillé:

principal c

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

int main(void) {
    uint32_t i;
    uint32_t r = 0;
    for (i = 0; i < 10; ++i) {
        r += i*i + 13*r*i + 17;   /* LINE 10. */
    }
    printf("%" PRIu32 "\n", r);
    return EXIT_SUCCESS;
}

Alors:

gcc -ggdb3 -O0 -std=c99 -o main main.c
gdb -batch -nh -q -ex 'dprintf 10, "%u %u\n", i, r' -ex 'run' ./main

Production:

Dprintf 1 at 0x400545: file main.c, line 10.
0 0
1 17
2 256
3 6933
4 277346
5 14699371
6 970158528
7 3628079733
8 3070853710
9 317092431
3057168588
[Inferior 1 (process 14305) exited normally]

Testé dans Ubuntu 16.04, GDB 8.2.