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?
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.
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.
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.)