Problem after hitting breakpoint on Windows (with GDBserver)

When debugging on Windows with GDBserver, the debugger starts
failing after hitting a breakpoint.  For instance:

    (gdb) b foo
    Breakpoint 1 at 0x40177e: file foo.adb, line 5.
    (gdb) cont
    Continuing.

    Breakpoint 1, foo () at foo.adb:5
    5          Put_Line ("Hello World.");  -- STOP
    (gdb) n

    Program received signal SIGSEGV, Segmentation fault.
    0x00401782 in foo () at foo.adb:5
    5          Put_Line ("Hello World.");  -- STOP

There are two issues:

  1. While trying to re-insert a breakpoint that is still inserted
     in memory, insert_bp_location wipes out the breakpoint location's
     shadow_contents.  As a consequence, we cannot restore the proper
     instruction when removing the breakpoint anymore.  That's why
     the inferior's behavior changes when trying to resume after
     the breakpoint was hit.

  2. mem-break.c:default_memory_insert_breakpoint passes a breakpoint
     location's shadow_contents as the buffer for a memory read.
     This reveals a limitation of the various memory-read target
     functions.  This patch documents this limitation and adjust
     the two calls that seem to hit that limitation.

gdb/ChangeLog:

        * breakpoint.c (breakpoint_xfer_memory): Add assertion.
        Update function description.
        (insert_bp_location): Do not wipe bl->target_info out.
        * mem-break.c: #include "gdb_string.h".
        (default_memory_insert_breakpoint): Do not call target_read_memory
        with a pointer to the breakpoint's shadow_contents buffer.  Use
        a local buffer instead.
        * m32r-tdep.c (m32r_memory_insert_breakpoint): Ditto.
This commit is contained in:
Joel Brobecker 2012-03-15 18:33:45 +00:00
parent 7b8957f8c3
commit 35c63cd8ce
4 changed files with 43 additions and 9 deletions

View File

@ -1,3 +1,14 @@
2012-03-15 Joel Brobecker <brobecker@adacore.com>
* breakpoint.c (breakpoint_xfer_memory): Add assertion.
Update function description.
(insert_bp_location): Do not wipe bl->target_info out.
* mem-break.c: #include "gdb_string.h".
(default_memory_insert_breakpoint): Do not call target_read_memory
with a pointer to the breakpoint's shadow_contents buffer. Use
a local buffer instead.
* m32r-tdep.c (m32r_memory_insert_breakpoint): Ditto.
2012-03-15 Tom Tromey <tromey@redhat.com>
* NEWS: Mention "info vtbl", not "info vtable".

View File

@ -1318,6 +1318,10 @@ bp_location_has_shadow (struct bp_location *bl)
/* Update BUF, which is LEN bytes read from the target address MEMADDR,
by replacing any memory breakpoints with their shadowed contents.
If READBUF is not NULL, this buffer must not overlap with any of
the breakpoint location's shadow_contents buffers. Otherwise,
a failed assertion internal error will be raised.
The range of shadowed area by each bp_location is:
bl->address - bp_location_placed_address_before_address_max
up to bl->address + bp_location_shadow_len_after_address_max
@ -1446,6 +1450,12 @@ breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
if (readbuf != NULL)
{
/* Verify that the readbuf buffer does not overlap with
the shadow_contents buffer. */
gdb_assert (bl->target_info.shadow_contents >= readbuf + len
|| readbuf >= (bl->target_info.shadow_contents
+ bl->target_info.shadow_len));
/* Update the read buffer with this inserted breakpoint's
shadow. */
memcpy (readbuf + bp_addr - memaddr,
@ -2082,8 +2092,15 @@ insert_bp_location (struct bp_location *bl,
if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
return 0;
/* Initialize the target-specific information. */
memset (&bl->target_info, 0, sizeof (bl->target_info));
/* Note we don't initialize bl->target_info, as that wipes out
the breakpoint location's shadow_contents if the breakpoint
is still inserted at that location. This in turn breaks
target_read_memory which depends on these buffers when
a memory read is requested at the breakpoint location:
Once the target_info has been wiped, we fail to see that
we have a breakpoint inserted at that address and thus
read the breakpoint instead of returning the data saved in
the breakpoint location's shadow contents. */
bl->target_info.placed_address = bl->address;
bl->target_info.placed_address_space = bl->pspace->aspace;
bl->target_info.length = bl->length;

View File

@ -85,7 +85,7 @@ m32r_memory_insert_breakpoint (struct gdbarch *gdbarch,
CORE_ADDR addr = bp_tgt->placed_address;
int val;
gdb_byte buf[4];
gdb_byte *contents_cache = bp_tgt->shadow_contents;
gdb_byte contents_cache[4];
gdb_byte bp_entry[] = { 0x10, 0xf1 }; /* dpt */
/* Save the memory contents. */
@ -93,6 +93,7 @@ m32r_memory_insert_breakpoint (struct gdbarch *gdbarch,
if (val != 0)
return val; /* return error */
memcpy (bp_tgt->shadow_contents, contents_cache, 4);
bp_tgt->placed_size = bp_tgt->shadow_len = 4;
/* Determine appropriate breakpoint contents and size for this address. */

View File

@ -29,6 +29,7 @@
#include "breakpoint.h"
#include "inferior.h"
#include "target.h"
#include "gdb_string.h"
/* Insert a breakpoint on targets that don't have any better
@ -46,6 +47,7 @@ default_memory_insert_breakpoint (struct gdbarch *gdbarch,
{
int val;
const unsigned char *bp;
gdb_byte *readbuf;
/* Determine appropriate breakpoint contents and size for this address. */
bp = gdbarch_breakpoint_from_pc
@ -53,15 +55,18 @@ default_memory_insert_breakpoint (struct gdbarch *gdbarch,
if (bp == NULL)
error (_("Software breakpoints not implemented for this target."));
/* Save the memory contents. */
/* Save the memory contents in the shadow_contents buffer and then
write the breakpoint instruction. */
bp_tgt->shadow_len = bp_tgt->placed_size;
val = target_read_memory (bp_tgt->placed_address, bp_tgt->shadow_contents,
readbuf = alloca (bp_tgt->placed_size);
val = target_read_memory (bp_tgt->placed_address, readbuf,
bp_tgt->placed_size);
/* Write the breakpoint. */
if (val == 0)
val = target_write_raw_memory (bp_tgt->placed_address, bp,
bp_tgt->placed_size);
{
memcpy (bp_tgt->shadow_contents, readbuf, bp_tgt->placed_size);
val = target_write_raw_memory (bp_tgt->placed_address, bp,
bp_tgt->placed_size);
}
return val;
}