Mettre en place un watchpoint matériel GDB / comment mettre en place un watchpoint logiciel

Une question précédente a expliqué que sur x86 la taille des objets observés est limitée par les registres de débogage. Comme prévu, je peux "regarder" une double variable. Mais je ne peux pas regarder un double datamember, par exemple,

watch pObject->dPrice

produit

Hardware watchpoint 1: pObject->dPrice

mais quand vous essayez de continuer l'exécution, ça dit

ne pouvait pas insérer de points de rupture matériels: Vous pourriez avoir demandé trop de matériel les points d'arrêt/de points d'observation.

même si c'est le point d'arrêt/point d'observation.

je suis curieux de savoir pourquoi il en est ainsi, mais plus important encore, y a-t-il un moyen de le contourner? Selon la documentation de GDB, il peut utiliser des watchpoints logiciels s'il ne peut pas utiliser du matériel. Dans ce cas, il ne tente pas d'utiliser un watchpoint Logiciel -- y a-t-il un moyen de le forcer à le faire?

17
demandé sur Peter Mortensen 2010-08-12 22:15:24

3 réponses

Oui, vous pouvez:

peut-utilisation-hw-les points d'observation 0

5.1.2 Mise En Place De Points De Surveillance:

vous pouvez forcer GDB à n'utiliser que les watchpoints du Logiciel avec la commande can-use-hw-watchpoints 0. Avec cette variable fixée à zéro, GDB n'essaiera jamais d'utiliser des watchpoints matériels, même si le système sous-jacent les prend en charge. (Notez que les points de surveillance assistés par le matériel qui ont été réglés avant le réglage peuvent-utiliser-HW-watchpoints to zero utilisera toujours le mécanisme matériel de surveillance des valeurs d'expression.)

set can-use-hw-watchpoints

définir s'il faut ou non utiliser des points de contrôle matériels.

show can-use-hw-watchpoints

afficher le mode courant d'utilisation des watchpoints du matériel.

16
répondu karlphillip 2018-01-31 01:16:11

je ne suis pas sûr à 100%, mais ma compréhension est que lorsque vous montre pObject->dPrice, gdb essaie de regarder tout ce qui peut changer la valeur observée.

en utilisant des watchpoints logiciels, après chaque étape GDB vérifie si l'expression a changé. Gdb doit définir un watchpoint pour dprice comme vous vous attendez, mais aussi pour pObject.

Maintenant, vous avez étiqueté la question 'x86'. Sur x86, Vous pouvez définir des points de rupture pour un maximum de quatre octets. Un double est de huit octets. Si vous si vous voulez regarder un double, je suppose que GDB aurait besoin de deux watchpoints. Vous avez besoin d'un watchpoint supplémentaire pour pObject. Je suppose que GDB essaie de regarder pObject, qui remonte au problème en question est lié à la question.

Quand je veux faire quelque chose de semblable, si je suis certain que le pointeur pObject pas de changement, j'ai l'habitude de faire:

p &pObject->dprice

disons que GDB dit que l'adresse est (double *) 0xabcdef10, maintenant, je faire:

watch (double *) *0xabcdef10

et montre seulement ce que je veux.

Note: je n'ai pas gdb ouvert devant moi, donc je peux avoir la syntaxe exacte pour le watch commande wrong (concernant l'emplacement du *), alors vérifiez d'abord.

7
répondu Nathan Fellman 2018-01-31 01:18:36

brève réponse: utiliser watch -location pObject->dPrice, ou la forme courte watch -l.

réponse: citant le manuel GDB:

regarder des expressions complexes qui font référence à de nombreuses variables peut également épuiser les ressources disponibles pour les points de repère assistés par le matériel. C'est parce que GDB doit surveiller chaque variable dans l'expression avec des ressources allouées séparément.

gdb observe littéralement l'expression elle-même, pas n'importe quelle adresse il indique. Dans ce cas, cela signifie que le point de rupture frappera si pObject lui-même est modifié pour pointer vers un nouveau dPrice; il n'y a pas un point d'observation pour pObject->dPrice, mais aussi pObject lui-même. Cela peut être plus que ce qui est disponible.

un exemple plus complet:

// Set a watchpoint on '*p' before running
#include <stdio.h>

int a = 0;
int b = 0;
int c = 0;
int* p = &a;

int main()
{
    puts("Hi"); // Dummy lines to make the results clearer, watchpoints stop at the line after the change
    *p = 1; // Breaks: *p was changed from 0 to 1
    puts("Hi");
    a = 2; // Breaks: a is *p, which changed from 1 to 2
    puts("Hi");
    p = &b; // Breaks: p is now b, changing *p from 2 to 0
    puts("Hi");
    p = &c; // Doesn't break: while p changed, *p is still 0
    puts("Hi");
    p = NULL; // Breaks: *p is now unreadable
    puts("Hi");
    return 0;
}

en théorie, c'est une fonctionnalité utile; vous pouvez regarder une expression complexe, se cassant dès qu'elle est fausse, un peu comme une assertion constamment testée. Pour exemple, vous pouvez watch a==b dans le programme ci-dessus.

en pratique, c'est inattendu, ça déclenche souvent ce problème, et ce n'est généralement pas ce que vous voulez.

Pour regarder l'adresse cible, utilisez watch -location pObject->dPrice. (Disponible à partir de gdb 7.3, sorti en juillet 2011; si vous utilisez quelque chose de plus ancien, utilisez print &pObject->dPrice et watch *(double*)0x12345678, ou l'adresse qu'elle imprime.)

5
répondu Alcaro 2018-01-31 01:20:33