summaryrefslogtreecommitdiff
path: root/gdb/s390-nat.c
diff options
context:
space:
mode:
authorUlrich Weigand <uweigand@de.ibm.com>2011-12-06 14:14:44 +0000
committerUlrich Weigand <uweigand@de.ibm.com>2011-12-06 14:14:44 +0000
commit6e1eabf7ecbad686583f7ef1e5ba854799f36ded (patch)
tree27e4de6b4b9e3cd573f859cb49a5cd15af982247 /gdb/s390-nat.c
parent1d3fc11c5305b0ac63664c8774698b9b75f674f6 (diff)
downloadgdb-6e1eabf7ecbad686583f7ef1e5ba854799f36ded.tar.gz
ChangeLog:
* s390-tdep.h (S390_ORIG_R2_REGNUM): Define. (S390_LAST_BREAK_REGNUM): Likewise. (S390_SYSTEM_CALL_REGNUM): Likewise. (S390_NUM_REGS): Update. (s390_regmap_last_break): Add declaration. (s390x_regmap_last_break): Likewise. (s390_regmap_system_call): Likewise. (tdesc_s390_linux32v1): Add declaration. (tdesc_s390_linux32v2): Likewise. (tdesc_s390_linux64v1): Likewise. (tdesc_s390_linux64v2): Likewise. (tdesc_s390x_linux64v1): Likewise. (tdesc_s390x_linux64v2): Likewise. * s390-tdep.c: Include new target description files "features/s390-linux32v1.c", "features/s390-linux32v2.c", "features/s390-linux64v1.c", "features/s390-linux64v2.c", "features/s390x-linux64v1.c", and "features/s390x-linux64v2.c". (s390_cannot_store_register): New function. (s390_write_pc): Likewise. (s390_dwarf_regmap): Add fields for new registers. (s390_regmap_gregset): Likewise. (s390x_regmap_gregset): Likewise. (s390_regmap_fpregset): Likewise. (s390_regmap_upper): Likewise. (s390_regmap_last_break): New variable. (s390x_regmap_last_break): Likewise. (s390_regmap_system_call): Likewise. (s390_last_break_regset): Likewise. (s390x_last_break_regset): Likewise. (s390_system_call_regset): Likewise. (s390_upper_regset_sections): Rename to ... (s390_linux64_regset_sections): ... this. (s390_linux32_regset_sections): New variable. (s390x_linux64_regset_sections): Likewise. (s390_linux32v1_regset_sections): Likewise. (s390_linux32v2_regset_sections): Likewise. (s390_linux64v1_regset_sections): Likewise. (s390_linux64v2_regset_sections): Likewise. (s390x_linux64v1_regset_sections): Likewise. (s390x_linux64v2_regset_sections): Likewise. (s390_regset_from_core_section): Handle .reg-s390-last-break and .reg-s390-system-call core file sections. (s390_core_read_description): Check for presence of .reg-s390-last-break and .reg-s390-system-call core file sections and return appropriate target description. (s390_gdbarch_init): Detect Linux-specific registers "orig_r2", "last_break" and "system_call" in target description. Install appropriate gdbarch_core_regset_sections array. Call set_gdbarch_cannot_store_register and set_gdbarch_write_pc. (_initialize_s390_tdep): Initialize additional target descriptions. * s390-nat.c: Include "elf/common.h". (PTRACE_GETREGSET, PTRACE_SETREGSET): Define if undefined. (have_regset_last_break): New static variable. (have_regset_system_call): Likewise. (s390_native_supply): Handle S390_ORIG_R2_REGNUM. (s390_native_collect): Likewise. (fetch_regset, store_regset, check_regset): New functions. (s390_linux_fetch_inferior_registers): Handle S390_LAST_BREAK_REGNUM and S390_SYSTEM_CALL_REGNUM. (s390_linux_store_inferior_registers): Likewise. (s390_read_description): Check for presence of NT_S390_LAST_BREAK and NT_S390_SYSTEM_CALL regsets and use appropriate description. * features/Makefile (WHICH): Add s390-linux32v1, s390-linux64v1, s390x-linux64v1, s390-linux32v2, s390-linux64v2, and s390x-linux64v2. (s390-linux32v1-expedite): Define. (s390-linux32v2-expedite): Likewise. (s390-linux64v1-expedite): Likewise. (s390-linux64v2-expedite): Likewise. (s390x-linux64v1-expedite): Likewise. (s390x-linux64v2-expedite): Likewise. * features/s390-linux32.xml: Add orig_r2 register. * features/s390-linux64.xml: Likewise. * features/s390x-linux64.xml: Likewise. * features/s390-linux32v1.xml: New file. * features/s390-linux32v2.xml: Likewise. * features/s390-linux64v1.xml: Likewise. * features/s390-linux64v2.xml: Likewise. * features/s390x-linux64v1.xml: Likewise. * features/s390x-linux64v2.xml: Likewise. * features/s390-linux32.c: Regenerate. * features/s390-linux64.c: Likewise. * features/s390x-linux64.c: Likewise. * features/s390-linux32v1.c: New generated file. * features/s390-linux32v2.c: Likewise. * features/s390-linux64v1.c: Likewise. * features/s390-linux64v2.c: Likewise. * features/s390x-linux64v1.c: Likewise. * features/s390x-linux64v2.c: Likewise. * regformats/s390-linux32.dat: Regenerate. * regformats/s390-linux64.dat: Regenerate. * regformats/s390x-linux64.dat: Regenerate. * regformats/s390-linux32v1.dat: New generated file. * regformats/s390-linux32v2.dat: Likewise. * regformats/s390-linux64v1.dat: Likewise. * regformats/s390-linux64v2.dat: Likewise. * regformats/s390x-linux64v1.dat: Likewise. * regformats/s390x-linux64v2.dat: Likewise. gdbserver/ChangeLog: * Makefile.in (s390-linux32v1.o, s390-linux32v1.c): New rules. (s390-linux32v2.o, s390-linux32v2.c): Likewise. (s390-linux64v1.o, s390-linux64v1.c): Likewise. (s390-linux64v2.o, s390-linux64v2.c): Likewise. (s390x-linux64v1.o, s390x-linux64v1.c): Likewise. (s390x-linux64v2.o, s390x-linux64v2.c): Likewise. * configure.srv [s390*-*-linux*] (srv_regobj): Add new objects. (srv_xmlfiles): Add new XML files. * linux-s390-low.c: Include "elf/common.h", <sys/ptrace.h>, and <sys/uio.h>. (PTRACE_GETREGSET, PTRACE_SETREGSET): Define if undefined. (init_registers_s390_linux32v1): Add prototype. (init_registers_s390_linux32v2): Likewise. (init_registers_s390_linux64v1): Likewise. (init_registers_s390_linux64v2): Likewise. (init_registers_s390x_linux64v1): Likewise. (init_registers_s390x_linux64v2): Likewise. (s390_num_regs): Increment to 52. (s390_regmap): Add orig_r2 register. (s390_num_regs_3264): Increment to 68. (s390_regmap_3264): Add orig_r2 register. (s390_collect_ptrace_register): Handle orig_r2 register. (s390_supply_ptrace_register): Likewise. (s390_fill_last_break): New function. (s390_store_last_break): Likewise. (s390_fill_system_call): New function. (s390_store_system_call): Likewise. (target_regsets): Handle NT_S390_LAST_BREAK and NT_S390_SYSTEM_CALL register sets. (s390_check_regset): New function. (s390_arch_setup): Check for presence of NT_S390_LAST_BREAK and NT_S390_SYSTEM_CALL regsets and use appropriate description. Update target_regsets for available register sets. testsuite/ChangeLog: * gdb.base/callfuncs.exp (fetch_all_registers): Filter out read-only last_break register on s390*-*-* targets.
Diffstat (limited to 'gdb/s390-nat.c')
-rw-r--r--gdb/s390-nat.c118
1 files changed, 113 insertions, 5 deletions
diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c
index c1eec1cc1dc..ae3c868a47e 100644
--- a/gdb/s390-nat.c
+++ b/gdb/s390-nat.c
@@ -28,6 +28,7 @@
#include "auxv.h"
#include "s390-tdep.h"
+#include "elf/common.h"
#include <asm/ptrace.h>
#include <sys/ptrace.h>
@@ -40,6 +41,16 @@
#define HWCAP_S390_HIGH_GPRS 512
#endif
+#ifndef PTRACE_GETREGSET
+#define PTRACE_GETREGSET 0x4204
+#endif
+
+#ifndef PTRACE_SETREGSET
+#define PTRACE_SETREGSET 0x4205
+#endif
+
+static int have_regset_last_break = 0;
+static int have_regset_system_call = 0;
/* Map registers to gregset/ptrace offsets.
These arrays are defined in s390-tdep.c. */
@@ -97,7 +108,8 @@ s390_native_supply (struct regcache *regcache, int regno,
return;
}
- if (regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+ if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+ || regno == S390_ORIG_R2_REGNUM)
offset += 4;
}
#endif
@@ -151,7 +163,8 @@ s390_native_collect (const struct regcache *regcache, int regno,
return;
}
- if (regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+ if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+ || regno == S390_ORIG_R2_REGNUM)
{
memset (regp + offset, 0, 4);
offset += 4;
@@ -293,6 +306,70 @@ store_fpregs (const struct regcache *regcache, int tid, int regnum)
perror_with_name (_("Couldn't write floating point status"));
}
+/* Fetch all registers in the kernel's register set whose number is REGSET,
+ whose size is REGSIZE, and whose layout is described by REGMAP, from
+ process/thread TID and store their values in GDB's register cache. */
+static void
+fetch_regset (struct regcache *regcache, int tid,
+ int regset, int regsize, int *regmap)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ gdb_byte *buf = alloca (regsize);
+ struct iovec iov;
+ int i;
+
+ iov.iov_base = buf;
+ iov.iov_len = regsize;
+
+ if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0)
+ perror_with_name (_("Couldn't get register set"));
+
+ for (i = 0; i < S390_NUM_REGS; i++)
+ s390_native_supply (regcache, i, buf, regmap);
+}
+
+/* Store all registers in the kernel's register set whose number is REGSET,
+ whose size is REGSIZE, and whose layout is described by REGMAP, from
+ GDB's register cache back to process/thread TID. */
+static void
+store_regset (struct regcache *regcache, int tid,
+ int regset, int regsize, int *regmap)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ gdb_byte *buf = alloca (regsize);
+ struct iovec iov;
+ int i;
+
+ iov.iov_base = buf;
+ iov.iov_len = regsize;
+
+ if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0)
+ perror_with_name (_("Couldn't get register set"));
+
+ for (i = 0; i < S390_NUM_REGS; i++)
+ s390_native_collect (regcache, i, buf, regmap);
+
+ if (ptrace (PTRACE_SETREGSET, tid, (long) regset, (long) &iov) < 0)
+ perror_with_name (_("Couldn't set register set"));
+}
+
+/* Check whether the kernel provides a register set with number REGSET
+ of size REGSIZE for process/thread TID. */
+static int
+check_regset (int tid, int regset, int regsize)
+{
+ gdb_byte *buf = alloca (regsize);
+ struct iovec iov;
+
+ iov.iov_base = buf;
+ iov.iov_len = regsize;
+
+ if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0)
+ return 0;
+ else
+ return 1;
+}
+
/* Fetch register REGNUM from the child process. If REGNUM is -1, do
this for all registers. */
static void
@@ -308,6 +385,17 @@ s390_linux_fetch_inferior_registers (struct target_ops *ops,
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
fetch_fpregs (regcache, tid);
+
+ if (have_regset_last_break)
+ if (regnum == -1 || regnum == S390_LAST_BREAK_REGNUM)
+ fetch_regset (regcache, tid, NT_S390_LAST_BREAK, 8,
+ (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 32
+ ? s390_regmap_last_break : s390x_regmap_last_break));
+
+ if (have_regset_system_call)
+ if (regnum == -1 || regnum == S390_SYSTEM_CALL_REGNUM)
+ fetch_regset (regcache, tid, NT_S390_SYSTEM_CALL, 4,
+ s390_regmap_system_call);
}
/* Store register REGNUM back into the child process. If REGNUM is
@@ -325,6 +413,13 @@ s390_linux_store_inferior_registers (struct target_ops *ops,
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
store_fpregs (regcache, tid, regnum);
+
+ /* S390_LAST_BREAK_REGNUM is read-only. */
+
+ if (have_regset_system_call)
+ if (regnum == -1 || regnum == S390_SYSTEM_CALL_REGNUM)
+ store_regset (regcache, tid, NT_S390_SYSTEM_CALL, 4,
+ s390_regmap_system_call);
}
@@ -539,6 +634,13 @@ s390_get_hwcap (void)
static const struct target_desc *
s390_read_description (struct target_ops *ops)
{
+ int tid = s390_inferior_tid ();
+
+ have_regset_last_break
+ = check_regset (tid, NT_S390_LAST_BREAK, 8);
+ have_regset_system_call
+ = check_regset (tid, NT_S390_SYSTEM_CALL, 4);
+
#ifdef __s390x__
/* If GDB itself is compiled as 64-bit, we are running on a machine in
z/Architecture mode. If the target is running in 64-bit addressing
@@ -547,16 +649,22 @@ s390_read_description (struct target_ops *ops)
that mode, report s390 architecture with 64-bit GPRs. */
if (s390_target_wordsize () == 8)
- return tdesc_s390x_linux64;
+ return (have_regset_system_call? tdesc_s390x_linux64v2 :
+ have_regset_last_break? tdesc_s390x_linux64v1 :
+ tdesc_s390x_linux64);
if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS)
- return tdesc_s390_linux64;
+ return (have_regset_system_call? tdesc_s390_linux64v2 :
+ have_regset_last_break? tdesc_s390_linux64v1 :
+ tdesc_s390_linux64);
#endif
/* If GDB itself is compiled as 31-bit, or if we're running a 31-bit inferior
on a 64-bit kernel that does not support using 64-bit registers in 31-bit
mode, report s390 architecture with 32-bit GPRs. */
- return tdesc_s390_linux32;
+ return (have_regset_system_call? tdesc_s390_linux32v2 :
+ have_regset_last_break? tdesc_s390_linux32v1 :
+ tdesc_s390_linux32);
}
void _initialize_s390_nat (void);