This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH v2] Fix interrupt.exp fails with m32 in x86_64
- From: Hui Zhu <hui at codesourcery dot com>
- To: Mark Kettenis <mark dot kettenis at xs4all dot nl>, Pedro Alves <palves at redhat dot com>
- Cc: Hui Zhu <teawater at gmail dot com>, H.Peter Anvin <hpa at zytor dot com>, gdb-patches ml <gdb-patches at sourceware dot org>
- Date: Tue, 6 May 2014 01:21:12 -0700
- Subject: [PATCH v2] Fix interrupt.exp fails with m32 in x86_64
- Authentication-results: sourceware.org; auth=none
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) ®s) < 0)
perror_with_name (_("Couldn't get registers"));
- amd64_collect_native_gregset (regcache, ®s, regnum);
+ fill_gregset (regcache, ®s, regnum);
if (ptrace (PTRACE_SETREGS, tid, 0, (long) ®s) < 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. */