diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 354a6361b7..8f7810b0bc 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -679,6 +679,7 @@ ALL_TARGET_OBS = \
arch/arm-get-next-pcs.o \
arch/arm-linux.o \
arch/i386.o \
+ arch/ppc-fbsd-common.o \
arch/ppc-linux-common.o \
arm-bsd-tdep.o \
arm-fbsd-tdep.o \
@@ -1414,6 +1415,7 @@ HFILES_NO_SRCDIR = \
arch/aarch64-insn.h \
arch/arm.h \
arch/i386.h \
+ arch/ppc-fbsd-common.h \
arch/ppc-linux-common.h \
arch/ppc-linux-tdesc.h \
cli/cli-cmds.h \
diff --git a/gdb/arch/ppc-fbsd-common.c b/gdb/arch/ppc-fbsd-common.c
new file mode 100644
index 0000000000..2d4fea631b
--- /dev/null
+++ b/gdb/arch/ppc-fbsd-common.c
@@ -0,0 +1,59 @@
+/* Common target dependent code for FreeBSD on PPC systems.
+
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+#include "common-defs.h"
+#include "arch/ppc-fbsd-common.h"
+
+extern struct target_desc *tdesc_powerpc_32;
+extern struct target_desc *tdesc_powerpc_altivec32;
+extern struct target_desc *tdesc_powerpc_vsx32;
+extern struct target_desc *tdesc_powerpc_64;
+extern struct target_desc *tdesc_powerpc_altivec64;
+extern struct target_desc *tdesc_powerpc_vsx64;
+
+const struct target_desc *
+ppc_fbsd_match_description (struct ppc_fbsd_features features)
+{
+ struct target_desc *tdesc = NULL;
+
+ if (features.wordsize == 8)
+ {
+ if (features.vsx)
+ tdesc = tdesc_powerpc_vsx64;
+ else if (features.altivec)
+ tdesc = tdesc_powerpc_altivec64;
+ else
+ tdesc = tdesc_powerpc_64;
+ }
+ else
+ {
+ gdb_assert (features.wordsize == 4);
+
+ if (features.vsx)
+ tdesc = tdesc_powerpc_vsx32;
+ else if (features.altivec)
+ tdesc = tdesc_powerpc_altivec32;
+ else
+ tdesc = tdesc_powerpc_32;
+ }
+
+ gdb_assert (tdesc != NULL);
+
+ return tdesc;
+}
diff --git a/gdb/arch/ppc-fbsd-common.h b/gdb/arch/ppc-fbsd-common.h
new file mode 100644
index 0000000000..0a1b199307
--- /dev/null
+++ b/gdb/arch/ppc-fbsd-common.h
@@ -0,0 +1,86 @@
+/* Common target dependent code for FreeBSD on PPC systems.
+
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+#ifndef ARCH_PPC_FBSD_COMMON_H
+#define ARCH_PPC_FBSD_COMMON_H
+
+struct target_desc;
+
+#define PPC_FBSD_SIZEOF_GREGSET_32 148
+#define PPC_FBSD_SIZEOF_GREGSET_64 296
+#define PPC_FBSD_SIZEOF_FPREGSET 264
+
+/* PT_GETVRREGS returns data as defined in machine/pcb.h:
+ 32 128-bit registers + 8 spare bytes + VRSAVE (4 bytes) + VSCR (4 bytes). */
+#define PPC_FBSD_SIZEOF_VRREGSET (32*16 + 8 + 4 + 4)
+
+/* 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 PPC_FBSD_SIZEOF_VSXREGSET (32*8)
+
+/* Features used to determine the target description. */
+struct ppc_fbsd_features
+{
+ unsigned int wordsize;
+ bool altivec;
+ bool vsx;
+};
+
+/* Base value for ppc_fbsd_features variables. */
+const struct ppc_fbsd_features ppc_fbsd_no_features = {
+ 0,
+ false,
+ false
+};
+
+/* Return a target description that matches FEATURES. */
+const struct target_desc *
+ppc_fbsd_match_description (struct ppc_fbsd_features features);
+
+#endif /* ARCH_PPC_FBSD_COMMON_H */
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index f197160896..dc617a1ab4 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -465,7 +465,8 @@ powerpc*-*-freebsd*)
# Target: FreeBSD/powerpc
gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppc64-tdep.o \
ppc-fbsd-tdep.o \
- ravenscar-thread.o ppc-ravenscar-thread.o"
+ ravenscar-thread.o ppc-ravenscar-thread.o \
+ arch/ppc-fbsd-common.o"
;;
powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu)
diff --git a/gdb/ppc-fbsd-nat.c b/gdb/ppc-fbsd-nat.c
index 44661e9a24..d81b62139a 100644
--- a/gdb/ppc-fbsd-nat.c
+++ b/gdb/ppc-fbsd-nat.c
@@ -21,6 +21,7 @@
#include "gdbcore.h"
#include "inferior.h"
#include "regcache.h"
+#include "regset.h"
#include
#include
@@ -37,10 +38,37 @@
#include "inf-ptrace.h"
#include "bsd-kvm.h"
+#include "arch/ppc-fbsd-common.h"
+
+/* These definitions should really come from machine/ptrace.h,
+ but we provide them in case gdb is built on an machine whose
+ FreeBSD version still doesn't have them. */
+
+#ifndef PT_FIRSTMACH
+#define PT_FIRSTMACH 64
+#endif
+
+/* PTRACE requests for Altivec registers. */
+#ifndef PT_GETVRREGS
+#define PT_GETVRREGS (PT_FIRSTMACH + 0)
+#define PT_SETVRREGS (PT_FIRSTMACH + 1)
+#endif
+
+/* PTRACE requests for POWER7 VSX registers. */
+#ifndef PT_GETVSRREGS
+#define PT_GETVSRREGS (PT_FIRSTMACH + 2)
+#define PT_SETVSRREGS (PT_FIRSTMACH + 3)
+#endif
+
+typedef char gdb_vrregset_t[PPC_FBSD_SIZEOF_VRREGSET];
+typedef char gdb_vsxregset_t[PPC_FBSD_SIZEOF_VSXREGSET];
+
struct ppc_fbsd_nat_target final : public fbsd_nat_target
{
void fetch_registers (struct regcache *, int) override;
void store_registers (struct regcache *, int) override;
+
+ const struct target_desc *read_description () override;
};
static ppc_fbsd_nat_target the_ppc_fbsd_nat_target;
@@ -120,6 +148,109 @@ getfpregs_supplies (struct gdbarch *gdbarch, int regno)
|| regno == tdep->ppc_fpscr_regnum);
}
+/* The 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. */
+static void
+fetch_altivec_registers (struct regcache *regcache, int tid,
+ int regno)
+{
+ int ret;
+ gdb_vrregset_t regs;
+ const struct regset *vrregset = ppc_fbsd_vrregset ();
+
+ ret = ptrace (PT_GETVRREGS, tid, (PTRACE_TYPE_ARG3) ®s, 0);
+ if (ret < 0)
+ perror_with_name (_("Unable to fetch AltiVec registers"));
+
+ vrregset->supply_regset (vrregset, regcache, regno, ®s,
+ PPC_FBSD_SIZEOF_VRREGSET);
+}
+
+/* The 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_registers (struct regcache *regcache, int tid, int regno)
+{
+ int ret;
+ gdb_vsxregset_t regs;
+ const struct regset *vsxregset = ppc_fbsd_vsxregset ();
+
+ ret = ptrace (PT_GETVSRREGS, tid, (PTRACE_TYPE_ARG3) ®s, 0);
+ if (ret < 0)
+ perror_with_name (_("Unable to fetch VSX registers"));
+
+ vsxregset->supply_regset (vsxregset, regcache, regno, ®s,
+ PPC_FBSD_SIZEOF_VSXREGSET);
+}
+
+static void
+store_altivec_registers (const struct regcache *regcache, int tid,
+ int regno)
+{
+ int ret;
+ gdb_vrregset_t regs;
+ const struct regset *vrregset = ppc_fbsd_vrregset ();
+
+ ret = ptrace (PT_GETVRREGS, tid, (PTRACE_TYPE_ARG3) ®s, 0);
+ if (ret < 0)
+ perror_with_name (_("Unable to fetch AltiVec registers"));
+
+ vrregset->collect_regset (vrregset, regcache, regno, ®s,
+ PPC_FBSD_SIZEOF_VRREGSET);
+
+ ret = ptrace (PT_SETVRREGS, tid, (PTRACE_TYPE_ARG3) ®s, 0);
+ if (ret < 0)
+ perror_with_name (_("Unable to store AltiVec registers"));
+}
+
+static void
+store_vsx_registers (const struct regcache *regcache, int tid, int regno)
+{
+ int ret;
+ gdb_vsxregset_t regs;
+ const struct regset *vsxregset = ppc_fbsd_vsxregset ();
+
+ ret = ptrace (PT_GETVSRREGS, tid, (PTRACE_TYPE_ARG3) ®s, 0);
+ if (ret < 0)
+ perror_with_name (_("Unable to fetch VSX registers"));
+
+ vsxregset->collect_regset (vsxregset, regcache, regno, ®s,
+ PPC_FBSD_SIZEOF_VSXREGSET);
+
+ ret = ptrace (PT_SETVSRREGS, tid, (PTRACE_TYPE_ARG3) ®s, 0);
+ if (ret < 0)
+ perror_with_name (_("Unable to store VSX registers"));
+}
+
+static int
+ppc_fbsd_target_wordsize (int tid)
+{
+ int wordsize = 4;
+
+#ifdef __powerpc64__
+ /* Check for 64-bit inferior process. This is the case when the host is
+ 64-bit, and PT_GETREGS returns less data than the length of gdb_gregset_t. */
+
+ gdb_gregset_t regs0;
+ gdb_gregset_t regs1;
+
+ /* Initialize regs0 with 00's and regs1 with ff's. If, after ptrace fills
+ them, they have the same contents, it means ptrace returned data for a
+ 64-bit inferior. */
+ memset (®s0, 0, sizeof (regs0));
+ memset (®s1, 0xff, sizeof (regs1));
+
+ if (ptrace (PT_GETREGS, tid, (PTRACE_TYPE_ARG3) ®s0, 0) >= 0
+ && ptrace (PT_GETREGS, tid, (PTRACE_TYPE_ARG3) ®s1, 0) >= 0)
+ if (memcmp (®s0, ®s1, sizeof (regs0)) == 0)
+ wordsize = 8;
+#endif
+
+ return wordsize;
+}
+
/* Fetch register REGNO from the child process. If REGNO is -1, do it
for all registers. */
@@ -128,13 +259,15 @@ ppc_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regno)
{
gdb_gregset_t regs;
pid_t pid = ptid_get_lwp (regcache->ptid ());
+ struct gdbarch *gdbarch = regcache->arch ();
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) ®s, 0) == -1)
perror_with_name (_("Couldn't get registers"));
supply_gregset (regcache, ®s);
- if (regno == -1 || getfpregs_supplies (regcache->arch (), regno))
+ if (regno == -1 || getfpregs_supplies (gdbarch, regno))
{
const struct regset *fpregset = ppc_fbsd_fpregset ();
gdb_fpregset_t fpregs;
@@ -142,8 +275,16 @@ ppc_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regno)
if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
perror_with_name (_("Couldn't get FP registers"));
- ppc_supply_fpregset (fpregset, regcache, regno, &fpregs, sizeof fpregs);
+ ppc_supply_fpregset (fpregset, regcache, regno, &fpregs, sizeof (fpregs));
}
+
+ if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
+ if (regno == -1 || altivec_register_p (gdbarch, regno))
+ fetch_altivec_registers (regcache, pid, regno);
+
+ if (tdep->ppc_vsr0_upper_regnum != -1)
+ if (regno == -1 || vsx_register_p (gdbarch, regno))
+ fetch_vsx_registers (regcache, pid, regno);
}
/* Store register REGNO back into the child process. If REGNO is -1,
@@ -154,6 +295,8 @@ ppc_fbsd_nat_target::store_registers (struct regcache *regcache, int regno)
{
gdb_gregset_t regs;
pid_t pid = ptid_get_lwp (regcache->ptid ());
+ struct gdbarch *gdbarch = regcache->arch ();
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) ®s, 0) == -1)
perror_with_name (_("Couldn't get registers"));
@@ -163,7 +306,7 @@ ppc_fbsd_nat_target::store_registers (struct regcache *regcache, int regno)
if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) ®s, 0) == -1)
perror_with_name (_("Couldn't write registers"));
- if (regno == -1 || getfpregs_supplies (regcache->arch (), regno))
+ if (regno == -1 || getfpregs_supplies (gdbarch, regno))
{
gdb_fpregset_t fpregs;
@@ -175,6 +318,46 @@ ppc_fbsd_nat_target::store_registers (struct regcache *regcache, int regno)
if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
perror_with_name (_("Couldn't set FP registers"));
}
+
+ if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
+ if (regno == -1 || altivec_register_p (gdbarch, regno))
+ store_altivec_registers (regcache, pid, regno);
+
+ if (tdep->ppc_vsr0_upper_regnum != -1)
+ if (regno == -1 || vsx_register_p (gdbarch, regno))
+ store_vsx_registers (regcache, pid, regno);
+}
+
+const struct target_desc *
+ppc_fbsd_nat_target::read_description ()
+{
+ int tid = ptid_get_lwp (inferior_ptid);
+
+ struct ppc_fbsd_features features = ppc_fbsd_no_features;
+
+ features.wordsize = ppc_fbsd_target_wordsize (tid);
+
+ gdb_vsxregset_t vsxregset;
+
+ if (ptrace (PT_GETVSRREGS, tid, (PTRACE_TYPE_ARG3) &vsxregset, 0) >= 0)
+ features.vsx = true;
+
+ /* EINVAL means that the PT_GETVSRREGS request isn't supported.
+ Anything else needs to be reported. */
+ else if (errno != EINVAL)
+ perror_with_name (_("Unable to fetch VSX registers"));
+
+ gdb_vrregset_t vrregset;
+
+ if (ptrace (PT_GETVRREGS, tid, (PTRACE_TYPE_ARG3) &vrregset, 0) >= 0)
+ features.altivec = true;
+
+ /* EINVAL means that the PT_GETVRREGS request isn't supported.
+ Anything else needs to be reported. */
+ else if (errno != EINVAL)
+ perror_with_name (_("Unable to fetch AltiVec registers"));
+
+ return ppc_fbsd_match_description (features);
}
/* Architecture specific function that reconstructs the
diff --git a/gdb/ppc-fbsd-tdep.c b/gdb/ppc-fbsd-tdep.c
index 495ccca8f1..a1fa7b8aaa 100644
--- a/gdb/ppc-fbsd-tdep.c
+++ b/gdb/ppc-fbsd-tdep.c
@@ -36,6 +36,21 @@
#include "fbsd-tdep.h"
#include "solib-svr4.h"
+#include "arch/ppc-fbsd-common.h"
+
+static void
+ppc_fbsd_collect_vrregset (const struct regset *regset,
+ const struct regcache *regcache,
+ int regnum, void *buf, size_t len)
+{
+ gdb_byte *vrregs = (gdb_byte *) buf;
+
+ /* Zero out the unused bytes in ppc32_fbsd_vrregmap
+ in case they get displayed somewhere (e.g. in core files). */
+ memset (&vrregs[32 * 16], 0, 8);
+
+ regcache_collect_regset (regset, regcache, regnum, buf, len);
+}
/* 32-bit regset descriptions. */
@@ -105,6 +120,31 @@ static const struct regset ppc32_fbsd_fpregset = {
ppc_collect_fpregset
};
+static const struct regcache_map_entry ppc32_fbsd_vrregmap[] = {
+ { 32, PPC_VR0_REGNUM, 16 },
+ { 1, REGCACHE_MAP_SKIP, 8},
+ { 1, PPC_VRSAVE_REGNUM, 4 },
+ { 1, PPC_VSCR_REGNUM, 4 },
+ { 0 }
+};
+
+static const struct regset ppc32_fbsd_vrregset = {
+ ppc32_fbsd_vrregmap,
+ regcache_supply_regset,
+ ppc_fbsd_collect_vrregset
+};
+
+static const struct regcache_map_entry ppc32_fbsd_vsxregmap[] = {
+ { 32, PPC_VSR0_UPPER_REGNUM, 8 },
+ { 0 }
+};
+
+static const struct regset ppc32_fbsd_vsxregset = {
+ ppc32_fbsd_vsxregmap,
+ regcache_supply_regset,
+ regcache_collect_regset
+};
+
const struct regset *
ppc_fbsd_gregset (int wordsize)
{
@@ -117,6 +157,18 @@ ppc_fbsd_fpregset (void)
return &ppc32_fbsd_fpregset;
}
+const struct regset *
+ppc_fbsd_vrregset (void)
+{
+ return &ppc32_fbsd_vrregset;
+}
+
+const struct regset *
+ppc_fbsd_vsxregset (void)
+{
+ return &ppc32_fbsd_vsxregset;
+}
+
/* Iterate over core file register note sections. */
static void
@@ -126,12 +178,56 @@ ppcfbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
const struct regcache *regcache)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int have_altivec = tdep->ppc_vr0_regnum != -1;
+ int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
if (tdep->wordsize == 4)
- cb (".reg", 148, &ppc32_fbsd_gregset, NULL, cb_data);
+ cb (".reg", PPC_FBSD_SIZEOF_GREGSET_32, &ppc32_fbsd_gregset, NULL, cb_data);
else
- cb (".reg", 296, &ppc64_fbsd_gregset, NULL, cb_data);
- cb (".reg2", 264, &ppc32_fbsd_fpregset, NULL, cb_data);
+ cb (".reg", PPC_FBSD_SIZEOF_GREGSET_64, &ppc64_fbsd_gregset, NULL, cb_data);
+ cb (".reg2", PPC_FBSD_SIZEOF_FPREGSET, &ppc32_fbsd_fpregset, NULL, cb_data);
+
+ if (have_altivec)
+ cb (".reg-ppc-vmx", PPC_FBSD_SIZEOF_VRREGSET, ppc_fbsd_vrregset (),
+ "ppc Altivec", cb_data);
+
+ if (have_vsx)
+ cb (".reg-ppc-vsx", PPC_FBSD_SIZEOF_VSXREGSET, ppc_fbsd_vsxregset (),
+ "POWER7 VSX", cb_data);
+}
+
+static const struct target_desc *
+ppc_fbsd_core_read_description (struct gdbarch *gdbarch,
+ struct target_ops *target,
+ bfd *abfd)
+{
+ struct ppc_fbsd_features features = ppc_fbsd_no_features;
+ asection *altivec = bfd_get_section_by_name (abfd, ".reg-ppc-vmx");
+ asection *vsx = bfd_get_section_by_name (abfd, ".reg-ppc-vsx");
+ asection *section = bfd_get_section_by_name (abfd, ".reg");
+
+ if (! section)
+ return NULL;
+
+ switch (bfd_section_size (abfd, section))
+ {
+ case PPC_FBSD_SIZEOF_GREGSET_32:
+ features.wordsize = 4;
+ break;
+ case PPC_FBSD_SIZEOF_GREGSET_64:
+ features.wordsize = 8;
+ break;
+ default:
+ return NULL;
+ }
+
+ if (altivec)
+ features.altivec = true;
+
+ if (vsx)
+ features.vsx = true;
+
+ return ppc_fbsd_match_description (features);
}
/* Default page size. */
@@ -317,6 +413,8 @@ ppcfbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
}
+ set_gdbarch_core_read_description (gdbarch, ppc_fbsd_core_read_description);
+
set_gdbarch_iterate_over_regset_sections
(gdbarch, ppcfbsd_iterate_over_regset_sections);
diff --git a/gdb/ppc-fbsd-tdep.h b/gdb/ppc-fbsd-tdep.h
index 356b5941ba..7b28bab73c 100644
--- a/gdb/ppc-fbsd-tdep.h
+++ b/gdb/ppc-fbsd-tdep.h
@@ -25,5 +25,7 @@ struct regset;
/* From ppc-fbsd-tdep.c ... */
const struct regset *ppc_fbsd_gregset (int);
const struct regset *ppc_fbsd_fpregset (void);
+const struct regset *ppc_fbsd_vrregset (void);
+const struct regset *ppc_fbsd_vsxregset (void);
#endif /* PPC_FBSD_TDEP_H */