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 v2] Fix interrupt.exp fails with m32 in x86_64


According to your comments in the discussion thread about Linux kernel
patch.  I make a new patch for GDB that let %eax sign-extend if %orig_eax >= 0.

Thanks,
Hui

2014-05-06  Hui Zhu  <hui@codesourcery.com>

	* amd64-linux-nat.c (fill_gregset): Make %eax
	sign-extended if need.
	(amd64_linux_store_inferior_registers): Change
	amd64_collect_native_gregset to fill_gregset.
	* amd64-nat.c (amd64_native_gregset_reg_offset): Remove static.
	* amd64-nat.h (amd64_native_gregset_reg_offset): Add extern.

--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -128,7 +128,52 @@ void
 fill_gregset (const struct regcache *regcache,
 	      elf_gregset_t *gregsetp, int regnum)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
   amd64_collect_native_gregset (regcache, gregsetp, regnum);
+
+  /* If target arch is 32 bits and GDB interrupt a system call of
+     inferior (%orig_rax >= 0), %rax is the errno of this system call.
+     amd64_collect_native_gregset let %eax zero-extend put %rax from
+     negative to positive.
+     If Linux cannot convert value of %rax back, the system call of
+     inferior will got errno -ERESTARTNOHAND, -ERESTARTSYS, -ERESTARTNOINTR
+     or -ERESTART_RESTARTBLOCK.
+     So if this is a 32 bits system call and fill value to %orig_eax
+     (not %eax to make sure REGCACHE has the right value of %orig_rax)
+     or all registers, let %eax sign-extend.  */
+  if (regcache_register_status (regcache, I386_LINUX_ORIG_EAX_REGNUM)
+	  == REG_VALID
+      && regcache_register_status (regcache, I386_EAX_REGNUM) == REG_VALID
+      && gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32
+      && (regnum == I386_LINUX_ORIG_EAX_REGNUM || regnum == -1))
+    {
+      LONGEST val;
+      gdb_byte buf[MAX_REGISTER_SIZE];
+      int orig_eax_size;
+
+      /* Get value of orig_eax and put it to val.  */
+      regcache_raw_collect (regcache, I386_LINUX_ORIG_EAX_REGNUM,
+			    buf);
+      orig_eax_size = register_size (gdbarch,
+				     I386_LINUX_ORIG_EAX_REGNUM);
+      val = extract_signed_integer (buf, orig_eax_size,
+				    gdbarch_byte_order (gdbarch));
+      if (val >= 0)
+	{
+	  /* Make %eax get sign-extended to 64 bits.  */
+	  char *regs = (char *) gregsetp;
+	  int offset = amd64_native_gregset_reg_offset (gdbarch,
+							I386_EAX_REGNUM);
+
+	  regcache_raw_collect (regcache, I386_EAX_REGNUM,
+				regs + offset);
+	  val = extract_signed_integer ((gdb_byte *)(regs + offset), 4,
+					gdbarch_byte_order (gdbarch));
+	  store_signed_integer ((gdb_byte *)(regs + offset), 8,
+				gdbarch_byte_order (gdbarch), val);
+	}
+    }
 }
 
 /* Transfering floating-point registers between GDB, inferiors and cores.  */
@@ -234,7 +279,7 @@ amd64_linux_store_inferior_registers (st
       if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
 	perror_with_name (_("Couldn't get registers"));
 
-      amd64_collect_native_gregset (regcache, &regs, regnum);
+      fill_gregset (regcache, &regs, regnum);
 
       if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
 	perror_with_name (_("Couldn't write registers"));
--- a/gdb/amd64-nat.c
+++ b/gdb/amd64-nat.c
@@ -51,7 +51,7 @@ int amd64_native_gregset64_num_regs = AM
 /* Return the offset of REGNUM within the appropriate native
    general-purpose register set.  */
 
-static int
+int
 amd64_native_gregset_reg_offset (struct gdbarch *gdbarch, int regnum)
 {
   int *reg_offset = amd64_native_gregset64_reg_offset;
--- a/gdb/amd64-nat.h
+++ b/gdb/amd64-nat.h
@@ -30,6 +30,12 @@ extern int amd64_native_gregset32_num_re
 extern int *amd64_native_gregset64_reg_offset;
 extern int amd64_native_gregset64_num_regs;
 
+/* Return the offset of REGNUM within the appropriate native
+   general-purpose register set.  */
+
+extern int amd64_native_gregset_reg_offset (struct gdbarch *gdbarch,
+					    int regnum);
+
 /* Return whether the native general-purpose register set supplies
    register REGNUM.  */
 


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