public inbox for gdb@sourceware.org
 help / color / mirror / Atom feed
From: Simon Marchi <simon.marchi@polymtl.ca>
To: Giles Atkinson <gatk@btinternet.com>
Cc: gdb@sourceware.org
Subject: Re: Dynamic watchpoints in dynamic memory
Date: Sat, 06 Feb 2016 03:44:00 -0000	[thread overview]
Message-ID: <b34c7ea99980aec37791337ed7e08436@simark.ca> (raw)
In-Reply-To: <1C590CEA-031F-40C0-A814-99829DD80E4D@btinternet.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

  reply	other threads:[~2016-02-06  3:44 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-05 23:21 Giles Atkinson
2016-02-06  3:44 ` Simon Marchi [this message]
2016-02-06 21:43   ` Giles Atkinson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b34c7ea99980aec37791337ed7e08436@simark.ca \
    --to=simon.marchi@polymtl.ca \
    --cc=gatk@btinternet.com \
    --cc=gdb@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).