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

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