An earlier question explained that on x86 the size of objects being watched is limited by debug registers. As expected, I can "watch" a double variable. But I can't watch a double datamember, for example,
watch pObject->dPrice
produces
Hardware watchpoint 1: pObject->dPrice
开发者_如何学Python
But when you try to continue execution, it says
Could not insert hardware breakpoints: You may have requested too many hardware breakpoints/watchpoints.
even though this is the only breakpoint/watchpoint.
I'm curious why this is so, but more importantly is there a way around it? According to GDB documentation it may use software watchpoints if it can't use hardware. In this case it makes no attempt to use a software watchpoint -- is there a way to force it to do so?
Yes, you can:
set can-use-hw-watchpoints 0
From 5.1.2 Setting Watchpoints:
You can force GDB to use only software watchpoints with the set can-use-hw-watchpoints 0 command. With this variable set to zero, GDB will never try to use hardware watchpoints, even if the underlying system supports them. (Note that hardware-assisted watchpoints that were set before setting can-use-hw-watchpoints to zero will still use the hardware mechanism of watching expression values.)
set can-use-hw-watchpoints
Set whether or not to use hardware watchpoints.
show can-use-hw-watchpoints
Show the current mode of using hardware watchpoints.
Short answer: Use watch -location pObject->dPrice
, or the short form watch -l
.
Long answer: Quoting the GDB manual:
Watching complex expressions that reference many variables can also exhaust the resources available for hardware-assisted watchpoints. That's because GDB needs to watch every variable in the expression with separately allocated resources.
GDB quite literally watches the expression itself, not whatever address it points to. In this case, it means that the breakpoint will hit if pObject
itself is changed to point to a new dPrice
; there's not just a watchpoint for pObject->dPrice
, but also one for pObject
itself. This may be more than what's available.
A more comprehensive example:
// 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;
}
In theory, this is a useful feature; you can watch a complex expression, breaking as soon as it's false, somewhat like a constantly-tested assertion. For example, you can watch a==b
in the above program.
In practice, it's unexpected, often triggers this issue, and usually isn't what you want.
To watch only the target address, use watch -location pObject->dPrice
. (This is available as of GDB 7.3, released in July 2011; if you're using anything older, use print &pObject->dPrice
and watch *(double*)0x12345678
, or whichever address it prints.)
I'm not 100% sure, but my understanding is that when you watch pObject->dPrice
, GDB tries to watch anything that can change the watched value.
Using software watchpoints, after each step GDB checks if the expression has changed. Using hardware watchpoints, GDB has to set a watchpoint for dprice
, as you expect, but also for pObject
.
Now, you tagged the question 'x86'. On x86 you can set breakpoints for up to four bytes. A double is eight bytes. If you want to watch a double, I would guess that GDB would need two hardware watchpoints. You need an additional watchpoint for pObject
as well. I'm guessing that GDB tries to watch all of pObject
, which goes back to the problem in the question you linked in the question.
When I want to do something similar, if I'm certain that the pointer pObject
will not change, I usually do:
p &pObject->dprice
Let's say GDB says the address is (double *) 0xabcdef10
, now I do:
watch (double *) *0xabcdef10
and watch only what I want to.
Note: I don't have GDB open in front of me, so I may have the exact syntax for the watch
command wrong (regarding the placement of the *
), so check it out first.
精彩评论