This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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,


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]