This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch] i386-tdep.c: Handle kernels that run one past a syscall insn.
- From: dje at google dot com (Doug Evans)
- To: gdb-patches at sourceware dot org
- Date: Thu, 17 Jun 2010 13:25:07 -0700 (PDT)
- Subject: [patch] i386-tdep.c: Handle kernels that run one past a syscall insn.
Hi.
On one ubuntu kernel I use, it runs one past a syscall insn.
amd64-tdep.c has to handle the same thing so I copied
what was done there.
I will check this in in a few days if there are no objections.
[I changed to type of the lengthp arg to i386_syscall_p to match
amd64-tdep.c.]
2010-06-17 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.
Index: i386-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-linux-tdep.c,v
retrieving revision 1.78
diff -u -p -r1.78 i386-linux-tdep.c
--- i386-linux-tdep.c 22 Apr 2010 20:35:28 -0000 1.78
+++ i386-linux-tdep.c 17 Jun 2010 20:19:33 -0000
@@ -888,7 +888,7 @@ i386_linux_init_abi (struct gdbarch_info
/* 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);
Index: i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.314
diff -u -p -r1.314 i386-tdep.c
--- i386-tdep.c 26 May 2010 18:19:27 -0000 1.314
+++ i386-tdep.c 17 Jun 2010 20:19:33 -0000
@@ -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, UL
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 gdbarc
&& ! 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,11 @@ i386_displaced_step_fixup (struct gdbarc
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.
+ Fixup 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,
Index: i386-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.h,v
retrieving revision 1.70
diff -u -p -r1.70 i386-tdep.h
--- i386-tdep.h 7 Apr 2010 18:43:45 -0000 1.70
+++ i386-tdep.h 17 Jun 2010 20:19:33 -0000
@@ -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,