summaryrefslogtreecommitdiff
path: root/gdb/ppc-linux-nat.c
diff options
context:
space:
mode:
authorLuis Machado <luisgpm@br.ibm.com>2008-08-15 15:18:30 +0000
committerLuis Machado <luisgpm@br.ibm.com>2008-08-15 15:18:30 +0000
commit68cb0f9580ae6cbf82b7cadc91f13ca345d5c48a (patch)
treebb6623b9d0dbfb2e2ce8d3aa0e4afc415034ed0d /gdb/ppc-linux-nat.c
parenta586fc5e6c8717a5adecea5f25f5883afd997382 (diff)
downloadgdb-68cb0f9580ae6cbf82b7cadc91f13ca345d5c48a.tar.gz
* rs6000-tdep: Include "features/rs6000/powerpc-vsx32.c".
Include "features/rs6000/powerpc-vsx64.c". (ppc_supply_vsxregset): New function. (ppc_collect_vsxregset): New function. (IS_VSX_PSEUDOREG): New macro. (IS_EFP_PSEUDOREG): New macro. (vsx_register_p): New function. (ppc_vsx_support_p): New function. (rs6000_builtin_type_vec128): New function. (rs6000_register_name): Hide upper halves of vs0~vs31. Return correct names for VSX registers and EFPR registers. (rs6000_pseudo_register_type): Return correct types for VSX and EFPR registers. (rs6000_pseudo_register_reggroup_p): Return correct group for VSX and EFPR registers. (ppc_pseudo_register_read): Rename to dfp_pseudo_register_read. (ppc_pseudo_register_write): Rename to dfp_pseudo_register_write. (vsx_pseudo_register_read): New function. (vsx_pseudo_register_write): New function. (efpr_pseudo_register_read): New function. (efpr_pseudo_register_write): New function. (rs6000_pseudo_register_read): Call new VSX and EFPR read functions. (rs6000_pseudo_register_write): Call new VSX and EFPR write functions. (rs6000_gdbarch_init): Declare have_vsx. Initialize new upper half VSX registers. Initialize VSX-related and EFPR-related pseudo-registers variables. Adjust the number of pseudo registers accordingly. * ppc-linux-nat.c: Define PTRACE_GETVSXREGS, PTRACE_SETVSXREGS and SIZEOF_VSRREGS. (gdb_vsxregset_t): New type. (have_ptrace_getsetvsxregs): New variable. (fetch_vsx_register): New function. (fetch_register): Handle VSX registers. (fetch_vsx_registers): New function. (fetch_ppc_registers): Handle VSX registers. (store_ppc_registers): Handle VSX registers. (store_vsx_register): New function. (store_register): Handle VSX registers. (store_vsx_registers): New function. (ppc_linux_read_description): Handle VSX-enabled inferiors. (gdb_vsxregset_t): New type. (supply_vsxregset): New function. (fill_vsxregset): New function. * ppc-tdep.h (vsx_register_p): New prototype. (vsx_support_p): New prototype. (ppc_vsr0_regnum): New variable. (ppc_vsr0_upper_regnum): Likewise. (ppc_efpr0_regnum): Likewise. (ppc_builtin_type_vec128): New type. (ppc_num_vsrs): New constant. (ppc_num_vshrs): New constant. (ppc_num_efprs): Likewise. Define POWERPC_VEC_VSX PPC_VSR0_UPPER_REGNUM and PPC_VSR31_UPPER_REGNUM. (ppc_supply_vsxregset): New prototype. (ppc_collect_vsxregset): New prototype. * ppc-linux-tdep.c: Include "features/rs6000/powerpc-vsx32l.c" Include "features/rs6000/powerpc-vsx64l.c". (_initialize_ppc_linux_tdep): Initialize VSX-enabled targets. (ppc_linux_regset_sections): Add new ".reg-ppc-vsx" field. (ppc32_linux_vsxregset): New 32-bit VSX-enabled regset. (ppc_linux_regset_from_core_section): Handle VSX core section. (ppc_linux_core_read_description): Support VSX-enabled core files. * ppc-linux-tdep.h: Declare *tdesc_powerpc_vsx32l Declare tdesc_powerpc_vsx64l * corelow.c (get_core_register_section): Support VSX-enabled core files. * features/rs6000/power-vsx.xml: New VSX descriptions. * features/rs6000/powerpc-vsx32.xml: New file. * features/rs6000/powerpc-vsx32l.xml: New file. * features/rs6000/powerpc-vsx64.xml: New file. * features/rs6000/powerpc-vsx64l.xml: New file. * features/rs6000/powerpc-vsx32.c: New file (generated). * features/rs6000/powerpc-vsx32l.c: New file (generated). * features/rs6000/powerpc-vsx64.c: New file (generated). * features/rs6000/powerpc-vsx64l.c: New file (generated). * features/Makefile: Updated with new descriptions. * regformats/rs6000/powerpc-vsx32l.dat: New file (generated). * regformats/rs6000/powerpc-vsx64l.dat: New file (generated). * testsuite/gdb.arch/vsx-regs.c: New source file. * testsuite/gdb.arch/vsx-regs.exp: New testcase. * testsuite/lib/gdb.exp (skip_vsx_tests): New function.
Diffstat (limited to 'gdb/ppc-linux-nat.c')
-rw-r--r--gdb/ppc-linux-nat.c222
1 files changed, 220 insertions, 2 deletions
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index db070b9a7fe..ed197f1163f 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -76,6 +76,11 @@
#define PTRACE_SETVRREGS 19
#endif
+/* PTRACE requests for POWER7 VSX registers. */
+#ifndef PTRACE_GETVSXREGS
+#define PTRACE_GETVSXREGS 27
+#define PTRACE_SETVSXREGS 28
+#endif
/* Similarly for the ptrace requests for getting / setting the SPE
registers (ev0 -- ev31, acc, and spefscr). See the description of
@@ -127,6 +132,41 @@
typedef char gdb_vrregset_t[SIZEOF_VRREGS];
+/* This is the layout of the POWER7 VSX registers and the way they overlap
+ with the existing FPR and VMX registers.
+
+ VSR doubleword 0 VSR doubleword 1
+ ----------------------------------------------------------------
+ VSR[0] | FPR[0] | |
+ ----------------------------------------------------------------
+ VSR[1] | FPR[1] | |
+ ----------------------------------------------------------------
+ | ... | |
+ | ... | |
+ ----------------------------------------------------------------
+ VSR[30] | FPR[30] | |
+ ----------------------------------------------------------------
+ VSR[31] | FPR[31] | |
+ ----------------------------------------------------------------
+ VSR[32] | VR[0] |
+ ----------------------------------------------------------------
+ VSR[33] | VR[1] |
+ ----------------------------------------------------------------
+ | ... |
+ | ... |
+ ----------------------------------------------------------------
+ VSR[62] | VR[30] |
+ ----------------------------------------------------------------
+ VSR[63] | VR[31] |
+ ----------------------------------------------------------------
+
+ VSX has 64 128bit registers. The first 32 registers overlap with
+ the FP registers (doubleword 0) and hence extend them with additional
+ 64 bits (doubleword 1). The other 32 regs overlap with the VMX
+ registers. */
+#define SIZEOF_VSXREGS 32*8
+
+typedef char gdb_vsxregset_t[SIZEOF_VSXREGS];
/* On PPC processors that support the the Signal Processing Extension
(SPE) APU, the general-purpose registers are 64 bits long.
@@ -152,6 +192,12 @@ struct gdb_evrregset_t
unsigned long spefscr;
};
+/* Non-zero if our kernel may support the PTRACE_GETVSXREGS and
+ PTRACE_SETVSXREGS requests, for reading and writing the VSX
+ POWER7 registers 0 through 31. Zero if we've tried one of them and
+ gotten an error. Note that VSX registers 32 through 63 overlap
+ with VR registers 0 through 31. */
+int have_ptrace_getsetvsxregs = 1;
/* Non-zero if our kernel may support the PTRACE_GETVRREGS and
PTRACE_SETVRREGS requests, for reading and writing the Altivec
@@ -239,6 +285,34 @@ ppc_register_u_addr (struct gdbarch *gdbarch, int regno)
return u_addr;
}
+/* The Linux kernel ptrace interface for POWER7 VSX registers uses the
+ registers set mechanism, as opposed to the interface for all the
+ other registers, that stores/fetches each register individually. */
+static void
+fetch_vsx_register (struct regcache *regcache, int tid, int regno)
+{
+ int ret;
+ gdb_vsxregset_t regs;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
+
+ ret = ptrace (PTRACE_GETVSXREGS, tid, 0, &regs);
+ if (ret < 0)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_getsetvsxregs = 0;
+ return;
+ }
+ perror_with_name (_("Unable to fetch VSX register"));
+ }
+
+ regcache_raw_supply (regcache, regno,
+ regs + (regno - tdep->ppc_vsr0_upper_regnum)
+ * vsxregsize);
+}
+
/* The Linux kernel ptrace interface for AltiVec registers uses the
registers set mechanism, as opposed to the interface for all the
other registers, that stores/fetches each register individually. */
@@ -373,6 +447,14 @@ fetch_register (struct regcache *regcache, int tid, int regno)
AltiVec registers, fall through and return zeroes, because
regaddr will be -1 in this case. */
}
+ if (vsx_register_p (gdbarch, regno))
+ {
+ if (have_ptrace_getsetvsxregs)
+ {
+ fetch_vsx_register (regcache, tid, regno);
+ return;
+ }
+ }
else if (spe_register_p (gdbarch, regno))
{
fetch_spe_register (regcache, tid, regno);
@@ -429,6 +511,21 @@ fetch_register (struct regcache *regcache, int tid, int regno)
}
static void
+supply_vsxregset (struct regcache *regcache, gdb_vsxregset_t *vsxregsetp)
+{
+ int i;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
+
+ for (i = 0; i < ppc_num_vshrs; i++)
+ {
+ regcache_raw_supply (regcache, tdep->ppc_vsr0_upper_regnum + i,
+ *vsxregsetp + i * vsxregsize);
+ }
+}
+
+static void
supply_vrregset (struct regcache *regcache, gdb_vrregset_t *vrregsetp)
{
int i;
@@ -454,6 +551,25 @@ supply_vrregset (struct regcache *regcache, gdb_vrregset_t *vrregsetp)
}
static void
+fetch_vsx_registers (struct regcache *regcache, int tid)
+{
+ int ret;
+ gdb_vsxregset_t regs;
+
+ ret = ptrace (PTRACE_GETVSXREGS, tid, 0, &regs);
+ if (ret < 0)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_getsetvsxregs = 0;
+ return;
+ }
+ perror_with_name (_("Unable to fetch VSX registers"));
+ }
+ supply_vsxregset (regcache, &regs);
+}
+
+static void
fetch_altivec_registers (struct regcache *regcache, int tid)
{
int ret;
@@ -507,6 +623,9 @@ fetch_ppc_registers (struct regcache *regcache, int tid)
if (have_ptrace_getvrregs)
if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
fetch_altivec_registers (regcache, tid);
+ if (have_ptrace_getsetvsxregs)
+ if (tdep->ppc_vsr0_upper_regnum != -1)
+ fetch_vsx_registers (regcache, tid);
if (tdep->ppc_ev0_upper_regnum >= 0)
fetch_spe_register (regcache, tid, -1);
}
@@ -530,6 +649,35 @@ ppc_linux_fetch_inferior_registers (struct regcache *regcache, int regno)
fetch_register (regcache, tid, regno);
}
+/* Store one VSX register. */
+static void
+store_vsx_register (const struct regcache *regcache, int tid, int regno)
+{
+ int ret;
+ gdb_vsxregset_t regs;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
+
+ ret = ptrace (PTRACE_SETVSXREGS, tid, 0, &regs);
+ if (ret < 0)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_getsetvsxregs = 0;
+ return;
+ }
+ perror_with_name (_("Unable to fetch VSX register"));
+ }
+
+ regcache_raw_collect (regcache, regno, regs +
+ (regno - tdep->ppc_vsr0_upper_regnum) * vsxregsize);
+
+ ret = ptrace (PTRACE_SETVSXREGS, tid, 0, &regs);
+ if (ret < 0)
+ perror_with_name (_("Unable to store VSX register"));
+}
+
/* Store one register. */
static void
store_altivec_register (const struct regcache *regcache, int tid, int regno)
@@ -668,6 +816,11 @@ store_register (const struct regcache *regcache, int tid, int regno)
store_altivec_register (regcache, tid, regno);
return;
}
+ if (vsx_register_p (gdbarch, regno))
+ {
+ store_vsx_register (regcache, tid, regno);
+ return;
+ }
else if (spe_register_p (gdbarch, regno))
{
store_spe_register (regcache, tid, regno);
@@ -722,6 +875,19 @@ store_register (const struct regcache *regcache, int tid, int regno)
}
static void
+fill_vsxregset (const struct regcache *regcache, gdb_vsxregset_t *vsxregsetp)
+{
+ int i;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
+
+ for (i = 0; i < ppc_num_vshrs; i++)
+ regcache_raw_collect (regcache, tdep->ppc_vsr0_upper_regnum + i,
+ *vsxregsetp + i * vsxregsize);
+}
+
+static void
fill_vrregset (const struct regcache *regcache, gdb_vrregset_t *vrregsetp)
{
int i;
@@ -745,6 +911,29 @@ fill_vrregset (const struct regcache *regcache, gdb_vrregset_t *vrregsetp)
}
static void
+store_vsx_registers (const struct regcache *regcache, int tid)
+{
+ int ret;
+ gdb_vsxregset_t regs;
+
+ ret = ptrace (PTRACE_GETVSXREGS, tid, 0, &regs);
+ if (ret < 0)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_getsetvsxregs = 0;
+ return;
+ }
+ perror_with_name (_("Couldn't get VSX registers"));
+ }
+
+ fill_vsxregset (regcache, &regs);
+
+ if (ptrace (PTRACE_SETVSXREGS, tid, 0, &regs) < 0)
+ perror_with_name (_("Couldn't write VSX registers"));
+}
+
+static void
store_altivec_registers (const struct regcache *regcache, int tid)
{
int ret;
@@ -802,6 +991,9 @@ store_ppc_registers (const struct regcache *regcache, int tid)
if (have_ptrace_getvrregs)
if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
store_altivec_registers (regcache, tid);
+ if (have_ptrace_getsetvsxregs)
+ if (tdep->ppc_vsr0_upper_regnum != -1)
+ store_vsx_registers (regcache, tid);
if (tdep->ppc_ev0_upper_regnum >= 0)
store_spe_register (regcache, tid, -1);
}
@@ -1037,6 +1229,7 @@ static const struct target_desc *
ppc_linux_read_description (struct target_ops *ops)
{
int altivec = 0;
+ int vsx = 0;
int tid = TIDGET (inferior_ptid);
if (tid == 0)
@@ -1055,6 +1248,19 @@ ppc_linux_read_description (struct target_ops *ops)
perror_with_name (_("Unable to fetch SPE registers"));
}
+ if (have_ptrace_getsetvsxregs)
+ {
+ gdb_vsxregset_t vsxregset;
+
+ if (ptrace (PTRACE_GETVSXREGS, tid, 0, &vsxregset) >= 0)
+ vsx = 1;
+
+ /* EIO means that the PTRACE_GETVSXREGS request isn't supported.
+ Anything else needs to be reported. */
+ else if (errno != EIO)
+ perror_with_name (_("Unable to fetch VSX registers"));
+ }
+
if (have_ptrace_getvrregs)
{
gdb_vrregset_t vrregset;
@@ -1076,11 +1282,23 @@ ppc_linux_read_description (struct target_ops *ops)
errno = 0;
msr = (long) ptrace (PTRACE_PEEKUSER, tid, PT_MSR * 8, 0);
if (errno == 0 && msr < 0)
- return altivec? tdesc_powerpc_altivec64l : tdesc_powerpc_64l;
+ {
+ if (vsx)
+ return tdesc_powerpc_vsx64l;
+ else if (altivec)
+ return tdesc_powerpc_altivec64l;
+
+ return tdesc_powerpc_64l;
+ }
}
#endif
- return altivec? tdesc_powerpc_altivec32l : tdesc_powerpc_32l;
+ if (vsx)
+ return tdesc_powerpc_vsx32l;
+ else if (altivec)
+ return tdesc_powerpc_altivec32l;
+
+ return tdesc_powerpc_32l;
}
void _initialize_ppc_linux_nat (void);