[v2] Fix interrupt.exp fails with m32 in x86_64

Message ID 0a87ce80-983c-4a0e-a5be-f931581873e8@SVR-ORW-FEM-02.mgc.mentorg.com
State New, archived
Headers

Commit Message

Hui Zhu May 6, 2014, 8:21 a.m. UTC
  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.
  

Comments

Hui Zhu June 12, 2014, 8:39 a.m. UTC | #1
Ping.

Thanks,
Hui

On Tue, May 6, 2014 at 4:21 PM, Hui Zhu <hui@codesourcery.com> wrote:
> 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.  */
>
  

Patch

--- 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.  */