This is the mail archive of the
gdb@sourceware.org
mailing list for the GDB project.
Re: Dynamic watchpoints in dynamic memory
- From: Simon Marchi <simon dot marchi at polymtl dot ca>
- To: Giles Atkinson <gatk at btinternet dot com>
- Cc: gdb at sourceware dot org
- Date: Fri, 05 Feb 2016 22:43:58 -0500
- Subject: Re: Dynamic watchpoints in dynamic memory
- Authentication-results: sourceware.org; auth=none
- References: <1C590CEA-031F-40C0-A814-99829DD80E4D at btinternet dot com>
Hi Giles,
On 2016-02-05 18:21, Giles Atkinson wrote:
Greetings,
I have a suspicion that these may be somewhat stupid questions, but I
feel I have done enough searching of documentation, FAQs etc.,
without result, to be ready to ask. I think this could be a FAQ-level
query, but found no reference to the topic.
I have a C program that crashes on a modify access via a
dynamically-allocated structure member with an illegal address, not
NULL.
The core file, circumstances, and code review suggest that an unusual
event has previously corrupted a pointer
in the structure, which the failing instruction dereferences.
You might have done that already, but my first thought would be to try
Valgrind. It might not help here, since the rogue write spills into
allocated code, but we never know. That program does some amazing
things.
Just to be sure, is it the pointer to the structure that becomes
corrupted, or a pointer inside the structure, that points to something
else? Some times, it can appear to the the later, while it's the former
(and you were just "lucky" that the first dereference did not produce a
segfault, because it happened to be in mapped memory).
My approach was to set a breakpoint on structure initialisation, with
a command list to set a watchpoint on the
pointer member. The watchpoint command list is backtrace and
continue, output to file. By setting the breakpoint on the
right instruction, the breakpoint command list can pick the structure
address from a register, adding an offset.
Silly question: since you are debugging C, don't you have access to a
variable that holds the address of the structure? It would be simpler
to use that than to figure out which register to use.
That works: so far, so good.
The target structures are created and destroyed fairly frequently,
responding to user input.
To avoid noise in the output, and limit the number of watchpoints,
there is a breakpoint before deallocation
that attempts to remove the watchpoint on the structure, again using a
register value.
Questions:
Does this make sense, or have I missed a better way?
I have done that in the past (using Python though), I think it makes
sense. It's good to keep in mind that if you track more than a few
bytes, GDB will have to resort to use software watchpoints, which will
slow down execution of the program by a few orders of magnitude. It can
be useful nonetheless.
How to remove the watchpoint? I can not identify the right syntax.
The watchpoint is set like this: watch -location *(void **)($esi +
$offset)
Again, using C (if possible) would be much easier. Something like
(gdb) watch -location structure->field
might do the trick (untested, may require some more & or *).
I have tried to remove it with 'clear', but that seems to match
watchpoints
using the 'watch' expression, and what I have is a different
expression that should yield the same address.
The register is different on deallocation and the original command is
not unique.
There might be a super clever way to do this using only base gdb
commands, but for these things I go straight to Python:
https://sourceware.org/gdb/onlinedocs/gdb/Breakpoints-In-Python.html
Create three breakpoint classes: two for the allocation and
de-allocation functions and one of type watchpoint, that will watch the
actual structures. In the allocation breakpoint's stop handler, you:
1. get the address of the structure (e.g.: gdb.parse_and_eval('ptr'),
where ptr is a pointer to the structure)
2. create an instance of the watchpoint class based on the structure
address
3. put that in a global dict, that maps structure addresses to
watchpoint object instances
In the de-allocation's stop handler, you:
1. get the address of the structure
2. find and remove the watchpoint instance from the global dict
3. call .delete() on the watchpoint.
This way, you should have watchpoints that follow the lifetime of your
objects (which is what I understood you wanted). I hope it makes sense
and is actually helpful.
More puzzlement: my printf commands in (nested) command lists do
nothing.
Hmm I am not sure I understand, could you give a reproducible example?
Simon