* mem-break.c (struct raw_breakpoint): New field shlib_disabled.

(set_gdb_breakpoint_at): If GDB is inserting a breakpoint on top
	of another, then delete the previous, and validate all
	breakpoints.
	(validate_inserted_breakpoint): New.
	(delete_disabled_breakpoints): New.
	(validate_breakpoints): New.
	(check_mem_read): Validate breakpoints before trusting their
	shadow.  Delete disabled breakpoints.
	(check_mem_write): Validate breakpoints before trusting they
	should be inserted.  Delete disabled breakpoints.
	* mem-break.h (validate_breakpoints):
	* server.c (handle_query): Validate breakpoints when we see a
	qSymbol query.
This commit is contained in:
Pedro Alves 2010-04-01 14:26:53 +00:00
parent 8b07ae33f0
commit d3bbe7a0c8
4 changed files with 132 additions and 2 deletions

View File

@ -1,3 +1,20 @@
2010-04-01 Pedro Alves <pedro@codesourcery.com>
* mem-break.c (struct raw_breakpoint): New field shlib_disabled.
(set_gdb_breakpoint_at): If GDB is inserting a breakpoint on top
of another, then delete the previous, and validate all
breakpoints.
(validate_inserted_breakpoint): New.
(delete_disabled_breakpoints): New.
(validate_breakpoints): New.
(check_mem_read): Validate breakpoints before trusting their
shadow. Delete disabled breakpoints.
(check_mem_write): Validate breakpoints before trusting they
should be inserted. Delete disabled breakpoints.
* mem-break.h (validate_breakpoints):
* server.c (handle_query): Validate breakpoints when we see a
qSymbol query.
2010-04-01 Pedro Alves <pedro@codesourcery.com>
* linux-low.c (linux_wait_1): Avoid setting need_step_over is

View File

@ -65,6 +65,10 @@ struct raw_breakpoint
/* Non-zero if this breakpoint is currently inserted in the
inferior. */
int inserted;
/* Non-zero if this breakpoint is currently disabled because we no
longer detect it as inserted. */
int shlib_disabled;
};
/* The type of a breakpoint. */
@ -326,6 +330,24 @@ set_gdb_breakpoint_at (CORE_ADDR where)
if (breakpoint_data == NULL)
return 1;
/* If we see GDB inserting a second breakpoint at the same address,
then the first breakpoint must have disappeared due to a shared
library unload. On targets where the shared libraries are
handled by userspace, like SVR4, for example, GDBserver can't
tell if a library was loaded or unloaded. Since we refcount
breakpoints, if we didn't do this, we'd just increase the
refcount of the previous breakpoint at this address, but the trap
was not planted in the inferior anymore, thus the breakpoint
would never be hit. */
bp = find_gdb_breakpoint_at (where);
if (bp != NULL)
{
delete_gdb_breakpoint_at (where);
/* Might as well validate all other breakpoints. */
validate_breakpoints ();
}
bp = set_breakpoint_at (where, NULL);
if (bp == NULL)
return -1;
@ -537,12 +559,70 @@ breakpoint_inserted_here (CORE_ADDR addr)
return (bp != NULL && bp->inserted);
}
static int
validate_inserted_breakpoint (struct raw_breakpoint *bp)
{
unsigned char *buf;
int err;
gdb_assert (bp->inserted);
buf = alloca (breakpoint_len);
err = (*the_target->read_memory) (bp->pc, buf, breakpoint_len);
if (err || memcmp (buf, breakpoint_data, breakpoint_len) != 0)
{
/* Tag it as gone. */
bp->inserted = 0;
bp->shlib_disabled = 1;
return 0;
}
return 1;
}
static void
delete_disabled_breakpoints (void)
{
struct process_info *proc = current_process ();
struct breakpoint *bp, *next;
for (bp = proc->breakpoints; bp != NULL; bp = next)
{
next = bp->next;
if (bp->raw->shlib_disabled)
delete_breakpoint_1 (proc, bp);
}
}
/* Check if breakpoints we inserted still appear to be inserted. They
may disappear due to a shared library unload, and worse, a new
shared library may be reloaded at the same address as the
previously unloaded one. If that happens, we should make sure that
the shadow memory of the old breakpoints isn't used when reading or
writing memory. */
void
validate_breakpoints (void)
{
struct process_info *proc = current_process ();
struct breakpoint *bp;
for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
{
if (bp->raw->inserted)
validate_inserted_breakpoint (bp->raw);
}
delete_disabled_breakpoints ();
}
void
check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
{
struct process_info *proc = current_process ();
struct raw_breakpoint *bp = proc->raw_breakpoints;
CORE_ADDR mem_end = mem_addr + mem_len;
int disabled_one = 0;
for (; bp != NULL; bp = bp->next)
{
@ -568,8 +648,16 @@ check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
buf_offset = start - mem_addr;
if (bp->inserted)
memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
{
if (validate_inserted_breakpoint (bp))
memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
else
disabled_one = 1;
}
}
if (disabled_one)
delete_disabled_breakpoints ();
}
void
@ -578,6 +666,7 @@ check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
struct process_info *proc = current_process ();
struct raw_breakpoint *bp = proc->raw_breakpoints;
CORE_ADDR mem_end = mem_addr + mem_len;
int disabled_one = 0;
for (; bp != NULL; bp = bp->next)
{
@ -604,8 +693,16 @@ check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
if (bp->inserted)
memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
{
if (validate_inserted_breakpoint (bp))
memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
else
disabled_one = 1;
}
}
if (disabled_one)
delete_disabled_breakpoints ();
}
/* Delete all breakpoints, and un-insert them from the inferior. */

View File

@ -104,4 +104,8 @@ void delete_all_breakpoints (void);
void free_all_breakpoints (struct process_info *proc);
/* Check if breakpoints still seem to be inserted in the inferior. */
void validate_breakpoints (void);
#endif /* MEM_BREAK_H */

View File

@ -858,6 +858,18 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (strcmp ("qSymbol::", own_buf) == 0)
{
/* GDB is suggesting new symbols have been loaded. This may
mean a new shared library has been detected as loaded, so
take the opportunity to check if breakpoints we think are
inserted, still are. Note that it isn't guaranteed that
we'll see this when a shared library is loaded, and nor will
we see this for unloads (although breakpoints in unloaded
libraries shouldn't trigger), as GDB may not find symbols for
the library at all. We also re-validate breakpoints when we
see a second GDB breakpoint for the same address, and or when
we access breakpoint shadows. */
validate_breakpoints ();
if (target_running () && the_target->look_up_symbols != NULL)
(*the_target->look_up_symbols) ();