GDB 7.4 added a very useful "-l / -location" option to the "watch expr" command[1]:
"Ordinarily a watchpoint respects the scope of variables in expr. The -location argument tells gdb to instead watch the memory referred to by expr. In this case, gdb will evaluate expr, take the address of the result, and watch the memory at that address.".
i.e. If you do "watch p->field_that_gets_corrupted" the watch point will get deleted when local variable p goes out of scope while "watch -l" works the way you want.
For those stuck using GDB 7.2 (as shipped in Ubuntu 11.04) the following GDB Python script ( gdb-watch-location.py) might help:
import gdb def _watch_location(expr, watch_point_class): l = gdb.parse_and_eval(expr).address wp_str = '*(%(type)s)(%(address)s)' % dict(type=l.type, address=l) gdb.Breakpoint(wp_str, gdb.BP_WATCHPOINT, watch_point_class) class _WatchLocationCommand(gdb.Command): 'Like "watch -l" in gdb 7.4+' def __init__(self): gdb.Command.__init__(self, 'watch-l', gdb.COMMAND_BREAKPOINTS, gdb.COMPLETE_SYMBOL) def invoke(self, arg, from_tty): _watch_location(arg, gdb.WP_WRITE) class _RWatchLocationCommand(gdb.Command): 'Like "rwatch -l" in gdb 7.4+' ... class _AWatchLocationCommand(gdb.Command): 'Like "awatch -l" in gdb 7.4+' ... _WatchLocationCommand() _RWatchLocationCommand() _AWatchLocationCommand()
Suppose you're working with the following C code snippet:
struct bag { int a, b; }; static void bag_poke(struct bag *p) { p->a = 1; }
Here's how gdb-watch-locations.py works:
- In _watch_location(), we call gdb.parse_and_eval() to turn an expression into a gdb.Value:
In [1]: gdb.parse_and_eval('p->a') Out[1]: <gdb.Value at 0x294a070>
- A gdb.Value has a type and an address
In [2]: v = gdb.parse_and_eval('p->a') In [3]: print v.type, v.address int 0x7fffffffdc30
- We use that to create a GDB watchpoint expression which we later pass to gdb.Breakpoint:
In [4]: '*(%(type)s)(%(address)s)' % dict(type=v.address.type, address=v.address) u'*(int *)(0x7fffffffdc30)'
- The code then adds three new GDB commands: "watch-l", "rwatch-l" and "awatch-l". Tells GDB that they should be classified as breakpoint commands in the online help system and use symbols for TAB completion.
Sample session:
$ gdb -x gdb-watch-locations.py data-access (gdb) break bag_poke Breakpoint 1 at 0x40050c: file data-access.c, line 9. (gdb) run Starting program: /home/scottt/work/scottt-gdb/data-access Breakpoint 1, bag_poke (p=0x7fffffffdc40) at data-access.c:9 9 p->a = 1; (gdb) wa watch watch-l (gdb) watch-l p->a Hardware watchpoint 2: *(int *)(0x7fffffffdc40) (gdb) continue Continuing. Hardware watchpoint 2: *(int *)(0x7fffffffdc40) Old value = 0 New value = 1 bag_poke (p=0x7fffffffdc40) at data-access.c:10 10 }