* i386-tdep.h (i386_displaced_step_copy_insn): Declare.

* i386-tdep.c (i386_displaced_step_copy_insn): New function.
	(i386_syscall_p): Change type of lengthp to int.
	(i386_displaced_step_fixup): Handle kernels that run one past a
	syscall insn.
	* i386-linux-tdep.c (i386_linux_init_abi): Use
	i386_displaced_step_copy_insn instead of
	simple_displaced_step_copy_insn.
This commit is contained in:
Doug Evans 2010-06-22 00:09:10 +00:00
parent d5bc977ffb
commit b55078be0a
4 changed files with 60 additions and 4 deletions

View File

@ -1,3 +1,14 @@
2010-06-21 Doug Evans <dje@google.com>
* i386-tdep.h (i386_displaced_step_copy_insn): Declare.
* i386-tdep.c (i386_displaced_step_copy_insn): New function.
(i386_syscall_p): Change type of lengthp to int.
(i386_displaced_step_fixup): Handle kernels that run one past a
syscall insn.
* i386-linux-tdep.c (i386_linux_init_abi): Use
i386_displaced_step_copy_insn instead of
simple_displaced_step_copy_insn.
2010-06-21 Tom Tromey <tromey@redhat.com>
* dwarf2read.c (read_base_type): Handle DW_ATE_UTF.

View File

@ -888,7 +888,7 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
/* Displaced stepping. */
set_gdbarch_displaced_step_copy_insn (gdbarch,
simple_displaced_step_copy_insn);
i386_displaced_step_copy_insn);
set_gdbarch_displaced_step_fixup (gdbarch, i386_displaced_step_fixup);
set_gdbarch_displaced_step_free_closure (gdbarch,
simple_displaced_step_free_closure);

View File

@ -518,7 +518,7 @@ i386_call_p (const gdb_byte *insn)
length in bytes. Otherwise, return zero. */
static int
i386_syscall_p (const gdb_byte *insn, ULONGEST *lengthp)
i386_syscall_p (const gdb_byte *insn, int *lengthp)
{
if (insn[0] == 0xcd)
{
@ -529,6 +529,43 @@ i386_syscall_p (const gdb_byte *insn, ULONGEST *lengthp)
return 0;
}
/* Some kernels may run one past a syscall insn, so we have to cope.
Otherwise this is just simple_displaced_step_copy_insn. */
struct displaced_step_closure *
i386_displaced_step_copy_insn (struct gdbarch *gdbarch,
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs)
{
size_t len = gdbarch_max_insn_length (gdbarch);
gdb_byte *buf = xmalloc (len);
read_memory (from, buf, len);
/* GDB may get control back after the insn after the syscall.
Presumably this is a kernel bug.
If this is a syscall, make sure there's a nop afterwards. */
{
int syscall_length;
gdb_byte *insn;
insn = i386_skip_prefixes (buf, len);
if (insn != NULL && i386_syscall_p (insn, &syscall_length))
insn[syscall_length] = NOP_OPCODE;
}
write_memory (to, buf, len);
if (debug_displaced)
{
fprintf_unfiltered (gdb_stdlog, "displaced: copy %s->%s: ",
paddress (gdbarch, from), paddress (gdbarch, to));
displaced_step_dump_bytes (gdb_stdlog, buf, len);
}
return (struct displaced_step_closure *) buf;
}
/* Fix up the state of registers and memory after having single-stepped
a displaced instruction. */
@ -587,7 +624,7 @@ i386_displaced_step_fixup (struct gdbarch *gdbarch,
&& ! i386_ret_p (insn))
{
ULONGEST orig_eip;
ULONGEST insn_len;
int insn_len;
regcache_cooked_read_unsigned (regs, I386_EIP_REGNUM, &orig_eip);
@ -606,7 +643,12 @@ i386_displaced_step_fixup (struct gdbarch *gdbarch,
it unrelocated. Goodness help us if there are PC-relative
system calls. */
if (i386_syscall_p (insn, &insn_len)
&& orig_eip != to + (insn - insn_start) + insn_len)
&& orig_eip != to + (insn - insn_start) + insn_len
/* GDB can get control back after the insn after the syscall.
Presumably this is a kernel bug.
i386_displaced_step_copy_insn ensures its a nop,
we add one to the length for it. */
&& orig_eip != to + (insn - insn_start) + insn_len + 1)
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,

View File

@ -362,6 +362,9 @@ extern const struct regset *
const char *sect_name, size_t sect_size);
extern struct displaced_step_closure *i386_displaced_step_copy_insn
(struct gdbarch *gdbarch, CORE_ADDR from, CORE_ADDR to,
struct regcache *regs);
extern void i386_displaced_step_fixup (struct gdbarch *gdbarch,
struct displaced_step_closure *closure,
CORE_ADDR from, CORE_ADDR to,