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