Blame SOURCES/gdb-x86_64-i386-syscall-restart.patch

e1d87d
http://sourceware.org/ml/gdb-patches/2009-11/msg00592.html
e1d87d
Subject: [patch] Fix syscall restarts for amd64->i386 biarch
e1d87d
e1d87d
Hi,
e1d87d
e1d87d
tested only on recent Linux kernels, it should apply also on vanilla ones.
e1d87d
There were various changes of the kernels behavior in the past.
e1d87d
e1d87d
FSF GDB HEAD state:
e1d87d
kernel debugger inferior state
e1d87d
x86_64 x86_64   x86_64   PASS
e1d87d
x86_64 x86_64   i386     FAIL without this patch, PASS with this patch
e1d87d
x86_64 i386     i386     PASS on recent kernels
e1d87d
                         (FAIL: kernel-2.6.31.5-127.fc12.x86_64 - Fedora 12)
e1d87d
                         (PASS: kernel-2.6.32-0.55.rc8.git1.fc13.x86_64)
e1d87d
i386   i386     i386     PASS
e1d87d
e1d87d
e1d87d
Currently gdb.base/interrupt.exp fails on amd64 host running under
e1d87d
--target_board unix/-m32 with:
e1d87d
	continue
e1d87d
	Continuing.
e1d87d
	Unknown error 512
e1d87d
e1d87d
<linux/errno.h>:
e1d87d
/*
e1d87d
 * These should never be seen by user programs.  To return one of ERESTART*
e1d87d
 * codes, signal_pending() MUST be set.  Note that ptrace can observe these
e1d87d
 * at syscall exit tracing, but they will never be left for the debugged user
e1d87d
 * process to see.
e1d87d
 */
e1d87d
#define ERESTARTSYS     512
e1d87d
e1d87d
"Unknown error 512" printed above is printed by the inferior itself, not by GDB.
e1d87d
e1d87d
It is because GDB reads it as 0xfffffffffffffe00 but writes it back as
e1d87d
0xfffffe00.
e1d87d
+      /* Sign-extend %eax as during return from a syscall it is being checked
e1d87d
+	 for -ERESTART* values -512 being above 0xfffffffffffffe00; tested by
e1d87d
+	 interrupt.exp.  */
e1d87d
e1d87d
e1d87d
Quote of Roland McGrath from IRC:
e1d87d
e1d87d
roland: in the user_regset model, there are 64-bit user_regset flavors and
e1d87d
32-bit user_regset flavors, so at the kabi level the (kernel) caller can say
e1d87d
what it means: calls on the 32-bit user_regset flavor will behave as if on
e1d87d
a 32-bit kernel/userland.  in ptrace, there is no way for x86_64 ptrace calls
e1d87d
to say "i think of the inferior as being 32 bits, so act accordingly" (tho ppc
e1d87d
and/or sparc have ptr
e1d87d
roland: ace requests that do that iirc)
e1d87d
roland: ergo 64-bit ptrace callers must either save/restore full 64-bits so
e1d87d
the kernel's sign-extension choices are preserved, or else grok magic ways to
e1d87d
expand stored 32-bit register contents to 64-bit values to stuff via 64-bit
e1d87d
ptrace
e1d87d
[...]
e1d87d
roland: there is a "32-bit-flavored task", but it's not really true that it
e1d87d
has 32-bit registers.  there is no 32-bit-only userland condition.  any task
e1d87d
can always ljmp to the 64-bit code segment and run 64-bit insns including
e1d87d
a 64-bit syscall
e1d87d
roland: so a 64-bit debugger should see and be able to fiddle the full
e1d87d
registers.  it can even change cs via ptrace to force the inferior into
e1d87d
running 32 or 64 bit code.
e1d87d
e1d87d
e1d87d
Saving whole 64bits for i386 targets on x86_64 hosts does not much match the
e1d87d
GDB architecture as `struct type' for these registers still should be 32bit
e1d87d
etc.   Therefore provided just this exception.
e1d87d
e1d87d
The problem is reproducible only if one does an inferior call during the
e1d87d
interruption to do full inferior save/restore from GDB regcache.
e1d87d
e1d87d
Regression tested on {x86_64,x86_64-m32,i686}-fedora12-linux-gnu.
e1d87d
e1d87d
e1d87d
Thanks,
e1d87d
Jan
e1d87d
e1d87d
e1d87d
gdb/
e1d87d
2009-11-29  Jan Kratochvil  <jan.kratochvil@redhat.com>
e1d87d
e1d87d
	* amd64-nat.c (amd64_collect_native_gregset): Do not pre-clear %eax.
e1d87d
	Sign extend it afterwards.
e1d87d
e1d87d
--- a/gdb/amd64-nat.c
e1d87d
+++ b/gdb/amd64-nat.c
e1d87d
@@ -131,9 +131,9 @@ amd64_collect_native_gregset (const struct regcache *regcache,
e1d87d
     {
e1d87d
       num_regs = amd64_native_gregset32_num_regs;
e1d87d
 
e1d87d
-      /* Make sure %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and
e1d87d
+      /* Make sure %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and
e1d87d
          %eip get zero-extended to 64 bits.  */
e1d87d
-      for (i = 0; i <= I386_EIP_REGNUM; i++)
e1d87d
+      for (i = I386_ECX_REGNUM; i <= I386_EIP_REGNUM; i++)
e1d87d
 	{
e1d87d
 	  if (regnum == -1 || regnum == i)
e1d87d
 	    memset (regs + amd64_native_gregset_reg_offset (gdbarch, i), 0, 8);
e1d87d
@@ -159,4 +159,20 @@ amd64_collect_native_gregset (const struct regcache *regcache,
e1d87d
 	    regcache_raw_collect (regcache, i, regs + offset);
e1d87d
 	}
e1d87d
     }
e1d87d
+
e1d87d
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
e1d87d
+    {
e1d87d
+      /* Sign-extend %eax as during return from a syscall it is being checked
e1d87d
+	 for -ERESTART* values -512 being above 0xfffffffffffffe00; tested by
e1d87d
+	 interrupt.exp.  */
e1d87d
+
e1d87d
+      int i = I386_EAX_REGNUM;
e1d87d
+
e1d87d
+      if (regnum == -1 || regnum == i)
e1d87d
+	{
e1d87d
+	  void *ptr = regs + amd64_native_gregset_reg_offset (gdbarch, i);
e1d87d
+
e1d87d
+	  *(int64_t *) ptr = *(int32_t *) ptr;
e1d87d
+	}
e1d87d
+    }
e1d87d
 }
e1d87d