/* PPC GNU/Linux native support.
- Copyright (C) 1988-2018 Free Software Foundation, Inc.
+ Copyright (C) 1988-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include <signal.h>
#include <sys/user.h>
#include <sys/ioctl.h>
-#include "gdb_wait.h"
+#include <sys/uio.h>
+#include "gdbsupport/gdb_wait.h"
#include <fcntl.h>
#include <sys/procfs.h>
#include "nat/gdb_ptrace.h"
+#include "nat/linux-ptrace.h"
#include "inf-ptrace.h"
/* Prototypes for supply_gregset etc. */
#include "arch/ppc-linux-common.h"
#include "arch/ppc-linux-tdesc.h"
#include "nat/ppc-linux.h"
+#include "linux-tdep.h"
/* Similarly for the hardware watchpoint support. These requests are used
when the PowerPC HWDEBUG ptrace interface is not available. */
int i;
for (i = 0; i < ppc_num_gprs; i++)
- regcache_raw_supply (regcache, tdep->ppc_ev0_upper_regnum + i,
- &evrregs.evr[i]);
+ regcache->raw_supply (tdep->ppc_ev0_upper_regnum + i, &evrregs.evr[i]);
}
else if (tdep->ppc_ev0_upper_regnum <= regno
&& regno < tdep->ppc_ev0_upper_regnum + ppc_num_gprs)
- regcache_raw_supply (regcache, regno,
- &evrregs.evr[regno - tdep->ppc_ev0_upper_regnum]);
+ regcache->raw_supply (regno,
+ &evrregs.evr[regno - tdep->ppc_ev0_upper_regnum]);
if (regno == -1
|| regno == tdep->ppc_acc_regnum)
- regcache_raw_supply (regcache, tdep->ppc_acc_regnum, &evrregs.acc);
+ regcache->raw_supply (tdep->ppc_acc_regnum, &evrregs.acc);
if (regno == -1
|| regno == tdep->ppc_spefscr_regnum)
- regcache_raw_supply (regcache, tdep->ppc_spefscr_regnum,
- &evrregs.spefscr);
+ regcache->raw_supply (tdep->ppc_spefscr_regnum, &evrregs.spefscr);
+}
+
+/* Use ptrace to fetch all registers from the register set with note
+ type REGSET_ID, size REGSIZE, and layout described by REGSET, from
+ process/thread TID and supply their values to REGCACHE. If ptrace
+ returns ENODATA to indicate the regset is unavailable, mark the
+ registers as unavailable in REGCACHE. */
+
+static void
+fetch_regset (struct regcache *regcache, int tid,
+ int regset_id, int regsetsize, const struct regset *regset)
+{
+ void *buf = alloca (regsetsize);
+ struct iovec iov;
+
+ iov.iov_base = buf;
+ iov.iov_len = regsetsize;
+
+ if (ptrace (PTRACE_GETREGSET, tid, regset_id, &iov) < 0)
+ {
+ if (errno == ENODATA)
+ regset->supply_regset (regset, regcache, -1, NULL, regsetsize);
+ else
+ perror_with_name (_("Couldn't get register set"));
+ }
+ else
+ regset->supply_regset (regset, regcache, -1, buf, regsetsize);
+}
+
+/* Use ptrace to store register REGNUM of the regset with note type
+ REGSET_ID, size REGSETSIZE, and layout described by REGSET, from
+ REGCACHE back to process/thread TID. If REGNUM is -1 all registers
+ in the set are collected and stored. */
+
+static void
+store_regset (const struct regcache *regcache, int tid, int regnum,
+ int regset_id, int regsetsize, const struct regset *regset)
+{
+ void *buf = alloca (regsetsize);
+ struct iovec iov;
+
+ iov.iov_base = buf;
+ iov.iov_len = regsetsize;
+
+ /* Make sure that the buffer that will be stored has up to date values
+ for the registers that won't be collected. */
+ if (ptrace (PTRACE_GETREGSET, tid, regset_id, &iov) < 0)
+ perror_with_name (_("Couldn't get register set"));
+
+ regset->collect_regset (regset, regcache, regnum, buf, regsetsize);
+
+ if (ptrace (PTRACE_SETREGSET, tid, regset_id, &iov) < 0)
+ perror_with_name (_("Couldn't set register set"));
+}
+
+/* Check whether the kernel provides a register set with number
+ REGSET_ID of size REGSETSIZE for process/thread TID. */
+
+static bool
+check_regset (int tid, int regset_id, int regsetsize)
+{
+ void *buf = alloca (regsetsize);
+ struct iovec iov;
+
+ iov.iov_base = buf;
+ iov.iov_len = regsetsize;
+
+ if (ptrace (PTRACE_GETREGSET, tid, regset_id, &iov) >= 0
+ || errno == ENODATA)
+ return true;
+ else
+ return false;
}
static void
/* This isn't really an address. But ptrace thinks of it as one. */
CORE_ADDR regaddr = ppc_register_u_addr (gdbarch, regno);
int bytes_transferred;
- unsigned int offset; /* Offset of registers within the u area. */
gdb_byte buf[PPC_MAX_REGISTER_SIZE];
if (altivec_register_p (gdbarch, regno))
{
/* If this is the first time through, or if it is not the first
- time through, and we have comfirmed that there is kernel
+ time through, and we have confirmed that there is kernel
support for such a ptrace request, then go and fetch the
register. */
if (have_ptrace_getvrregs)
AltiVec registers, fall through and return zeroes, because
regaddr will be -1 in this case. */
}
- if (vsx_register_p (gdbarch, regno))
+ else if (vsx_register_p (gdbarch, regno))
{
if (have_ptrace_getsetvsxregs)
{
fetch_spe_register (regcache, tid, regno);
return;
}
+ else if (regno == PPC_DSCR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_dscr_regnum != -1);
+
+ fetch_regset (regcache, tid, NT_PPC_DSCR,
+ PPC_LINUX_SIZEOF_DSCRREGSET,
+ &ppc32_linux_dscrregset);
+ return;
+ }
+ else if (regno == PPC_PPR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_ppr_regnum != -1);
+
+ fetch_regset (regcache, tid, NT_PPC_PPR,
+ PPC_LINUX_SIZEOF_PPRREGSET,
+ &ppc32_linux_pprregset);
+ return;
+ }
+ else if (regno == PPC_TAR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_tar_regnum != -1);
+
+ fetch_regset (regcache, tid, NT_PPC_TAR,
+ PPC_LINUX_SIZEOF_TARREGSET,
+ &ppc32_linux_tarregset);
+ return;
+ }
+ else if (PPC_IS_EBB_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_ebb);
+
+ fetch_regset (regcache, tid, NT_PPC_EBB,
+ PPC_LINUX_SIZEOF_EBBREGSET,
+ &ppc32_linux_ebbregset);
+ return;
+ }
+ else if (PPC_IS_PMU_REGNUM (regno))
+ {
+ gdb_assert (tdep->ppc_mmcr0_regnum != -1);
+
+ fetch_regset (regcache, tid, NT_PPC_PMU,
+ PPC_LINUX_SIZEOF_PMUREGSET,
+ &ppc32_linux_pmuregset);
+ return;
+ }
+ else if (PPC_IS_TMSPR_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_spr);
+
+ fetch_regset (regcache, tid, NT_PPC_TM_SPR,
+ PPC_LINUX_SIZEOF_TM_SPRREGSET,
+ &ppc32_linux_tm_sprregset);
+ return;
+ }
+ else if (PPC_IS_CKPTGP_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_core);
+
+ const struct regset *cgprregset = ppc_linux_cgprregset (gdbarch);
+ fetch_regset (regcache, tid, NT_PPC_TM_CGPR,
+ (tdep->wordsize == 4?
+ PPC32_LINUX_SIZEOF_CGPRREGSET
+ : PPC64_LINUX_SIZEOF_CGPRREGSET),
+ cgprregset);
+ return;
+ }
+ else if (PPC_IS_CKPTFP_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_fpu);
+
+ fetch_regset (regcache, tid, NT_PPC_TM_CFPR,
+ PPC_LINUX_SIZEOF_CFPRREGSET,
+ &ppc32_linux_cfprregset);
+ return;
+ }
+ else if (PPC_IS_CKPTVMX_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_altivec);
+
+ const struct regset *cvmxregset = ppc_linux_cvmxregset (gdbarch);
+ fetch_regset (regcache, tid, NT_PPC_TM_CVMX,
+ PPC_LINUX_SIZEOF_CVMXREGSET,
+ cvmxregset);
+ return;
+ }
+ else if (PPC_IS_CKPTVSX_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_vsx);
+
+ fetch_regset (regcache, tid, NT_PPC_TM_CVSX,
+ PPC_LINUX_SIZEOF_CVSXREGSET,
+ &ppc32_linux_cvsxregset);
+ return;
+ }
+ else if (regno == PPC_CPPR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_cppr_regnum != -1);
+
+ fetch_regset (regcache, tid, NT_PPC_TM_CPPR,
+ PPC_LINUX_SIZEOF_CPPRREGSET,
+ &ppc32_linux_cpprregset);
+ return;
+ }
+ else if (regno == PPC_CDSCR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_cdscr_regnum != -1);
+
+ fetch_regset (regcache, tid, NT_PPC_TM_CDSCR,
+ PPC_LINUX_SIZEOF_CDSCRREGSET,
+ &ppc32_linux_cdscrregset);
+ return;
+ }
+ else if (regno == PPC_CTAR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_ctar_regnum != -1);
+
+ fetch_regset (regcache, tid, NT_PPC_TM_CTAR,
+ PPC_LINUX_SIZEOF_CTARREGSET,
+ &ppc32_linux_ctarregset);
+ return;
+ }
if (regaddr == -1)
{
memset (buf, '\0', register_size (gdbarch, regno)); /* Supply zeroes */
- regcache_raw_supply (regcache, regno, buf);
+ regcache->raw_supply (regno, buf);
return;
}
{
/* Little-endian values are always found at the left end of the
bytes transferred. */
- regcache_raw_supply (regcache, regno, buf);
+ regcache->raw_supply (regno, buf);
}
else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
{
/* Big-endian values are found at the right end of the bytes
transferred. */
size_t padding = (bytes_transferred - register_size (gdbarch, regno));
- regcache_raw_supply (regcache, regno, buf + padding);
+ regcache->raw_supply (regno, buf + padding);
}
else
internal_error (__FILE__, __LINE__,
static int
fetch_all_gp_regs (struct regcache *regcache, int tid)
{
- struct gdbarch *gdbarch = regcache->arch ();
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_gregset_t gregset;
if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
static void
fetch_ppc_registers (struct regcache *regcache, int tid)
{
- int i;
struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
fetch_vsx_registers (regcache, tid, -1);
if (tdep->ppc_ev0_upper_regnum >= 0)
fetch_spe_register (regcache, tid, -1);
+ if (tdep->ppc_ppr_regnum != -1)
+ fetch_regset (regcache, tid, NT_PPC_PPR,
+ PPC_LINUX_SIZEOF_PPRREGSET,
+ &ppc32_linux_pprregset);
+ if (tdep->ppc_dscr_regnum != -1)
+ fetch_regset (regcache, tid, NT_PPC_DSCR,
+ PPC_LINUX_SIZEOF_DSCRREGSET,
+ &ppc32_linux_dscrregset);
+ if (tdep->ppc_tar_regnum != -1)
+ fetch_regset (regcache, tid, NT_PPC_TAR,
+ PPC_LINUX_SIZEOF_TARREGSET,
+ &ppc32_linux_tarregset);
+ if (tdep->have_ebb)
+ fetch_regset (regcache, tid, NT_PPC_EBB,
+ PPC_LINUX_SIZEOF_EBBREGSET,
+ &ppc32_linux_ebbregset);
+ if (tdep->ppc_mmcr0_regnum != -1)
+ fetch_regset (regcache, tid, NT_PPC_PMU,
+ PPC_LINUX_SIZEOF_PMUREGSET,
+ &ppc32_linux_pmuregset);
+ if (tdep->have_htm_spr)
+ fetch_regset (regcache, tid, NT_PPC_TM_SPR,
+ PPC_LINUX_SIZEOF_TM_SPRREGSET,
+ &ppc32_linux_tm_sprregset);
+ if (tdep->have_htm_core)
+ {
+ const struct regset *cgprregset = ppc_linux_cgprregset (gdbarch);
+ fetch_regset (regcache, tid, NT_PPC_TM_CGPR,
+ (tdep->wordsize == 4?
+ PPC32_LINUX_SIZEOF_CGPRREGSET
+ : PPC64_LINUX_SIZEOF_CGPRREGSET),
+ cgprregset);
+ }
+ if (tdep->have_htm_fpu)
+ fetch_regset (regcache, tid, NT_PPC_TM_CFPR,
+ PPC_LINUX_SIZEOF_CFPRREGSET,
+ &ppc32_linux_cfprregset);
+ if (tdep->have_htm_altivec)
+ {
+ const struct regset *cvmxregset = ppc_linux_cvmxregset (gdbarch);
+ fetch_regset (regcache, tid, NT_PPC_TM_CVMX,
+ PPC_LINUX_SIZEOF_CVMXREGSET,
+ cvmxregset);
+ }
+ if (tdep->have_htm_vsx)
+ fetch_regset (regcache, tid, NT_PPC_TM_CVSX,
+ PPC_LINUX_SIZEOF_CVSXREGSET,
+ &ppc32_linux_cvsxregset);
+ if (tdep->ppc_cppr_regnum != -1)
+ fetch_regset (regcache, tid, NT_PPC_TM_CPPR,
+ PPC_LINUX_SIZEOF_CPPRREGSET,
+ &ppc32_linux_cpprregset);
+ if (tdep->ppc_cdscr_regnum != -1)
+ fetch_regset (regcache, tid, NT_PPC_TM_CDSCR,
+ PPC_LINUX_SIZEOF_CDSCRREGSET,
+ &ppc32_linux_cdscrregset);
+ if (tdep->ppc_ctar_regnum != -1)
+ fetch_regset (regcache, tid, NT_PPC_TM_CTAR,
+ PPC_LINUX_SIZEOF_CTARREGSET,
+ &ppc32_linux_ctarregset);
}
/* Fetch registers from the child process. Fetch all registers if
perror_with_name (_("Unable to store AltiVec registers"));
}
-/* Assuming TID referrs to an SPE process, set the top halves of TID's
+/* Assuming TID refers to an SPE process, set the top halves of TID's
general-purpose registers and its SPE-specific registers to the
values in EVRREGSET. If we don't support PTRACE_SETEVRREGS, do
nothing.
int i;
for (i = 0; i < ppc_num_gprs; i++)
- regcache_raw_collect (regcache,
- tdep->ppc_ev0_upper_regnum + i,
- &evrregs.evr[i]);
+ regcache->raw_collect (tdep->ppc_ev0_upper_regnum + i,
+ &evrregs.evr[i]);
}
else if (tdep->ppc_ev0_upper_regnum <= regno
&& regno < tdep->ppc_ev0_upper_regnum + ppc_num_gprs)
- regcache_raw_collect (regcache, regno,
- &evrregs.evr[regno - tdep->ppc_ev0_upper_regnum]);
+ regcache->raw_collect (regno,
+ &evrregs.evr[regno - tdep->ppc_ev0_upper_regnum]);
if (regno == -1
|| regno == tdep->ppc_acc_regnum)
- regcache_raw_collect (regcache,
- tdep->ppc_acc_regnum,
- &evrregs.acc);
+ regcache->raw_collect (tdep->ppc_acc_regnum,
+ &evrregs.acc);
if (regno == -1
|| regno == tdep->ppc_spefscr_regnum)
- regcache_raw_collect (regcache,
- tdep->ppc_spefscr_regnum,
- &evrregs.spefscr);
+ regcache->raw_collect (tdep->ppc_spefscr_regnum,
+ &evrregs.spefscr);
/* Write back the modified register set. */
set_spe_registers (tid, &evrregs);
store_altivec_registers (regcache, tid, regno);
return;
}
- if (vsx_register_p (gdbarch, regno))
+ else if (vsx_register_p (gdbarch, regno))
{
store_vsx_registers (regcache, tid, regno);
return;
store_spe_register (regcache, tid, regno);
return;
}
+ else if (regno == PPC_DSCR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_dscr_regnum != -1);
+
+ store_regset (regcache, tid, regno, NT_PPC_DSCR,
+ PPC_LINUX_SIZEOF_DSCRREGSET,
+ &ppc32_linux_dscrregset);
+ return;
+ }
+ else if (regno == PPC_PPR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_ppr_regnum != -1);
+
+ store_regset (regcache, tid, regno, NT_PPC_PPR,
+ PPC_LINUX_SIZEOF_PPRREGSET,
+ &ppc32_linux_pprregset);
+ return;
+ }
+ else if (regno == PPC_TAR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_tar_regnum != -1);
+
+ store_regset (regcache, tid, regno, NT_PPC_TAR,
+ PPC_LINUX_SIZEOF_TARREGSET,
+ &ppc32_linux_tarregset);
+ return;
+ }
+ else if (PPC_IS_EBB_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_ebb);
+
+ store_regset (regcache, tid, regno, NT_PPC_EBB,
+ PPC_LINUX_SIZEOF_EBBREGSET,
+ &ppc32_linux_ebbregset);
+ return;
+ }
+ else if (PPC_IS_PMU_REGNUM (regno))
+ {
+ gdb_assert (tdep->ppc_mmcr0_regnum != -1);
+
+ store_regset (regcache, tid, regno, NT_PPC_PMU,
+ PPC_LINUX_SIZEOF_PMUREGSET,
+ &ppc32_linux_pmuregset);
+ return;
+ }
+ else if (PPC_IS_TMSPR_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_spr);
+
+ store_regset (regcache, tid, regno, NT_PPC_TM_SPR,
+ PPC_LINUX_SIZEOF_TM_SPRREGSET,
+ &ppc32_linux_tm_sprregset);
+ return;
+ }
+ else if (PPC_IS_CKPTGP_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_core);
+
+ const struct regset *cgprregset = ppc_linux_cgprregset (gdbarch);
+ store_regset (regcache, tid, regno, NT_PPC_TM_CGPR,
+ (tdep->wordsize == 4?
+ PPC32_LINUX_SIZEOF_CGPRREGSET
+ : PPC64_LINUX_SIZEOF_CGPRREGSET),
+ cgprregset);
+ return;
+ }
+ else if (PPC_IS_CKPTFP_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_fpu);
+
+ store_regset (regcache, tid, regno, NT_PPC_TM_CFPR,
+ PPC_LINUX_SIZEOF_CFPRREGSET,
+ &ppc32_linux_cfprregset);
+ return;
+ }
+ else if (PPC_IS_CKPTVMX_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_altivec);
+
+ const struct regset *cvmxregset = ppc_linux_cvmxregset (gdbarch);
+ store_regset (regcache, tid, regno, NT_PPC_TM_CVMX,
+ PPC_LINUX_SIZEOF_CVMXREGSET,
+ cvmxregset);
+ return;
+ }
+ else if (PPC_IS_CKPTVSX_REGNUM (regno))
+ {
+ gdb_assert (tdep->have_htm_vsx);
+
+ store_regset (regcache, tid, regno, NT_PPC_TM_CVSX,
+ PPC_LINUX_SIZEOF_CVSXREGSET,
+ &ppc32_linux_cvsxregset);
+ return;
+ }
+ else if (regno == PPC_CPPR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_cppr_regnum != -1);
+
+ store_regset (regcache, tid, regno, NT_PPC_TM_CPPR,
+ PPC_LINUX_SIZEOF_CPPRREGSET,
+ &ppc32_linux_cpprregset);
+ return;
+ }
+ else if (regno == PPC_CDSCR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_cdscr_regnum != -1);
+
+ store_regset (regcache, tid, regno, NT_PPC_TM_CDSCR,
+ PPC_LINUX_SIZEOF_CDSCRREGSET,
+ &ppc32_linux_cdscrregset);
+ return;
+ }
+ else if (regno == PPC_CTAR_REGNUM)
+ {
+ gdb_assert (tdep->ppc_ctar_regnum != -1);
+
+ store_regset (regcache, tid, regno, NT_PPC_TM_CTAR,
+ PPC_LINUX_SIZEOF_CTARREGSET,
+ &ppc32_linux_ctarregset);
+ return;
+ }
if (regaddr == -1)
return;
if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
{
/* Little-endian values always sit at the left end of the buffer. */
- regcache_raw_collect (regcache, regno, buf);
+ regcache->raw_collect (regno, buf);
}
else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
{
/* Big-endian values sit at the right end of the buffer. */
size_t padding = (bytes_to_transfer - register_size (gdbarch, regno));
- regcache_raw_collect (regcache, regno, buf + padding);
+ regcache->raw_collect (regno, buf + padding);
}
for (i = 0; i < bytes_to_transfer; i += sizeof (long))
static int
store_all_gp_regs (const struct regcache *regcache, int tid, int regno)
{
- struct gdbarch *gdbarch = regcache->arch ();
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_gregset_t gregset;
if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
static void
store_ppc_registers (const struct regcache *regcache, int tid)
{
- int i;
struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
store_vsx_registers (regcache, tid, -1);
if (tdep->ppc_ev0_upper_regnum >= 0)
store_spe_register (regcache, tid, -1);
-}
-
-/* Fetch the AT_HWCAP entry from the aux vector. */
-static CORE_ADDR
-ppc_linux_get_hwcap (void)
-{
- CORE_ADDR field;
-
- if (target_auxv_search (target_stack, AT_HWCAP, &field) != 1)
- return 0;
-
- return field;
+ if (tdep->ppc_ppr_regnum != -1)
+ store_regset (regcache, tid, -1, NT_PPC_PPR,
+ PPC_LINUX_SIZEOF_PPRREGSET,
+ &ppc32_linux_pprregset);
+ if (tdep->ppc_dscr_regnum != -1)
+ store_regset (regcache, tid, -1, NT_PPC_DSCR,
+ PPC_LINUX_SIZEOF_DSCRREGSET,
+ &ppc32_linux_dscrregset);
+ if (tdep->ppc_tar_regnum != -1)
+ store_regset (regcache, tid, -1, NT_PPC_TAR,
+ PPC_LINUX_SIZEOF_TARREGSET,
+ &ppc32_linux_tarregset);
+
+ if (tdep->ppc_mmcr0_regnum != -1)
+ store_regset (regcache, tid, -1, NT_PPC_PMU,
+ PPC_LINUX_SIZEOF_PMUREGSET,
+ &ppc32_linux_pmuregset);
+
+ if (tdep->have_htm_spr)
+ store_regset (regcache, tid, -1, NT_PPC_TM_SPR,
+ PPC_LINUX_SIZEOF_TM_SPRREGSET,
+ &ppc32_linux_tm_sprregset);
+
+ /* Because the EBB and checkpointed HTM registers can be
+ unavailable, attempts to store them here would cause this
+ function to fail most of the time, so we ignore them. */
}
/* The cached DABR value, to install in new threads.
struct ppc_hw_breakpoint *hw_break;
};
-/* This is an internal VEC created to store information about *points inserted
- for each thread. This is used when PowerPC HWDEBUG ptrace interface is
- available. */
-typedef struct thread_points
+/* This is an internal vector created to store information about *points
+ inserted for each thread. This is used when PowerPC HWDEBUG ptrace
+ interface is available. */
+struct thread_points
{
/* The TID to which this *point relates. */
int tid;
size of these vector is MAX_SLOTS_NUMBER. If the hw_break element of
the tuple is NULL, then the position in the vector is free. */
struct hw_break_tuple *hw_breaks;
- } *thread_points_p;
-DEF_VEC_P (thread_points_p);
+ };
-VEC(thread_points_p) *ppc_threads = NULL;
+static std::vector<thread_points *> ppc_threads;
/* The version of the PowerPC HWDEBUG kernel interface that we will use, if
available. */
{
int tid;
- tid = ptid_get_lwp (inferior_ptid);
+ tid = inferior_ptid.lwp ();
if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
+ tid = inferior_ptid.pid ();
/* Check for kernel support for PowerPC HWDEBUG ptrace interface. */
if (ptrace (PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info) >= 0)
/* We need to know whether ptrace supports PTRACE_SET_DEBUGREG
and whether the target has DABR. If either answer is no, the
ptrace call will return -1. Fail in that case. */
- tid = ptid_get_lwp (ptid);
+ tid = ptid.lwp ();
if (tid == 0)
- tid = ptid_get_pid (ptid);
+ tid = ptid.pid ();
if (ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0) == -1)
return 0;
takes two hardware watchpoints though. */
if (len > 1
&& hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE
- && ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+ && linux_get_hwcap (current_top_target ()) & PPC_FEATURE_BOOKE)
return 2;
/* Check if the processor provides DAWR interface. */
if (hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_DAWR)
ptrace interface, DAC-based processors (i.e., embedded processors) will
use addresses aligned to 4-bytes due to the way the read/write flags are
passed in the old ptrace interface. */
- else if (((ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+ else if (((linux_get_hwcap (current_top_target ()) & PPC_FEATURE_BOOKE)
&& (addr + len) > (addr & ~3) + 4)
|| (addr + len) > (addr & ~7) + 8)
return 0;
static struct thread_points *
hwdebug_find_thread_points_by_tid (int tid, int alloc_new)
{
- int i;
- struct thread_points *t;
-
- for (i = 0; VEC_iterate (thread_points_p, ppc_threads, i, t); i++)
- if (t->tid == tid)
- return t;
+ for (thread_points *t : ppc_threads)
+ {
+ if (t->tid == tid)
+ return t;
+ }
- t = NULL;
+ struct thread_points *t = NULL;
/* Do we need to allocate a new point_item
if the wanted one does not exist? */
t = XNEW (struct thread_points);
t->hw_breaks = XCNEWVEC (struct hw_break_tuple, max_slots_number);
t->tid = tid;
- VEC_safe_push (thread_points_p, ppc_threads, t);
+ ppc_threads.push_back (t);
}
return t;
gdb::unique_xmalloc_ptr<ppc_hw_breakpoint> p (XDUP (ppc_hw_breakpoint, b));
struct hw_break_tuple *hw_breaks;
struct thread_points *t;
- struct hw_break_tuple *tuple;
errno = 0;
slot = ptrace (PPC_PTRACE_SETHWDEBUG, tid, 0, p.get ());
/* Find a free element in the hw_breaks vector. */
for (i = 0; i < max_slots_number; i++)
- if (hw_breaks[i].hw_break == NULL)
- {
- hw_breaks[i].slot = slot;
- hw_breaks[i].hw_break = p.release ();
- break;
- }
+ {
+ if (hw_breaks[i].hw_break == NULL)
+ {
+ hw_breaks[i].slot = slot;
+ hw_breaks[i].hw_break = p.release ();
+ break;
+ }
+ }
gdb_assert (i != max_slots_number);
}
}
ALL_LWPS (lp)
- hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
+ hwdebug_insert_point (&p, lp->ptid.lwp ());
return 0;
}
}
ALL_LWPS (lp)
- hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
+ hwdebug_remove_point (&p, lp->ptid.lwp ());
return 0;
}
p.condition_value = 0;
ALL_LWPS (lp)
- hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
+ hwdebug_insert_point (&p, lp->ptid.lwp ());
return 0;
}
p.condition_value = 0;
ALL_LWPS (lp)
- hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
+ hwdebug_remove_point (&p, lp->ptid.lwp ());
return 0;
}
can_use_watchpoint_cond_accel (void)
{
struct thread_points *p;
- int tid = ptid_get_lwp (inferior_ptid);
+ int tid = inferior_ptid.lwp ();
int cnt = hwdebug_info.num_condition_regs, i;
- CORE_ADDR tmp_value;
if (!have_ptrace_hwdebug_interface () || cnt == 0)
return 0;
create_watchpoint_request (&p, addr, len, type, cond, 1);
ALL_LWPS (lp)
- hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
+ hwdebug_insert_point (&p, lp->ptid.lwp ());
ret = 0;
}
long dabr_value;
long read_mode, write_mode;
- if (ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+ if (linux_get_hwcap (current_top_target ()) & PPC_FEATURE_BOOKE)
{
/* PowerPC 440 requires only the read/write flags to be passed
to the kernel. */
saved_dabr_value = dabr_value;
ALL_LWPS (lp)
- if (ptrace (PTRACE_SET_DEBUGREG, ptid_get_lwp (lp->ptid), 0,
+ if (ptrace (PTRACE_SET_DEBUGREG, lp->ptid.lwp (), 0,
saved_dabr_value) < 0)
return -1;
create_watchpoint_request (&p, addr, len, type, cond, 0);
ALL_LWPS (lp)
- hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
+ hwdebug_remove_point (&p, lp->ptid.lwp ());
ret = 0;
}
{
saved_dabr_value = 0;
ALL_LWPS (lp)
- if (ptrace (PTRACE_SET_DEBUGREG, ptid_get_lwp (lp->ptid), 0,
+ if (ptrace (PTRACE_SET_DEBUGREG, lp->ptid.lwp (), 0,
saved_dabr_value) < 0)
return -1;
void
ppc_linux_nat_target::low_new_thread (struct lwp_info *lp)
{
- int tid = ptid_get_lwp (lp->ptid);
+ int tid = lp->ptid.lwp ();
if (have_ptrace_hwdebug_interface ())
{
struct thread_points *p;
struct hw_break_tuple *hw_breaks;
- if (VEC_empty (thread_points_p, ppc_threads))
+ if (ppc_threads.empty ())
return;
/* Get a list of breakpoints from any thread. */
- p = VEC_last (thread_points_p, ppc_threads);
+ p = ppc_threads.back ();
hw_breaks = p->hw_breaks;
/* Copy that thread's breakpoints and watchpoints to the new thread. */
ppc_linux_thread_exit (struct thread_info *tp, int silent)
{
int i;
- int tid = ptid_get_lwp (tp->ptid);
+ int tid = tp->ptid.lwp ();
struct hw_break_tuple *hw_breaks;
- struct thread_points *t = NULL, *p;
+ struct thread_points *t = NULL;
if (!have_ptrace_hwdebug_interface ())
return;
- for (i = 0; VEC_iterate (thread_points_p, ppc_threads, i, p); i++)
- if (p->tid == tid)
- {
- t = p;
- break;
- }
+ for (i = 0; i < ppc_threads.size (); i++)
+ {
+ if (ppc_threads[i]->tid == tid)
+ {
+ t = ppc_threads[i];
+ break;
+ }
+ }
if (t == NULL)
return;
- VEC_unordered_remove (thread_points_p, ppc_threads, i);
+ unordered_remove (ppc_threads, i);
hw_breaks = t->hw_breaks;
/* The index (or slot) of the *point is passed in the si_errno field. */
int slot = siginfo.si_errno;
- t = hwdebug_find_thread_points_by_tid (ptid_get_lwp (inferior_ptid), 0);
+ t = hwdebug_find_thread_points_by_tid (inferior_ptid.lwp (), 0);
/* Find out if this *point is a hardware breakpoint.
If so, we should return 0. */
int mask;
if (have_ptrace_hwdebug_interface ()
- && ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+ && linux_get_hwcap (current_top_target ()) & PPC_FEATURE_BOOKE)
return start <= addr && start + length >= addr;
- else if (ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+ else if (linux_get_hwcap (current_top_target ()) & PPC_FEATURE_BOOKE)
mask = 3;
else
mask = 7;
gdb_byte *endptr, CORE_ADDR *typep,
CORE_ADDR *valp)
{
- int tid = ptid_get_lwp (inferior_ptid);
+ int tid = inferior_ptid.lwp ();
if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
+ tid = inferior_ptid.pid ();
int sizeof_auxv_field = ppc_linux_target_wordsize (tid);
const struct target_desc *
ppc_linux_nat_target::read_description ()
{
- int tid = ptid_get_lwp (inferior_ptid);
+ int tid = inferior_ptid.lwp ();
if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
+ tid = inferior_ptid.pid ();
if (have_ptrace_getsetevrregs)
{
features.wordsize = ppc_linux_target_wordsize (tid);
- CORE_ADDR hwcap = ppc_linux_get_hwcap ();
+ CORE_ADDR hwcap = linux_get_hwcap (current_top_target ());
+ CORE_ADDR hwcap2 = linux_get_hwcap2 (current_top_target ());
if (have_ptrace_getsetvsxregs
&& (hwcap & PPC_FEATURE_HAS_VSX))
perror_with_name (_("Unable to fetch AltiVec registers"));
}
- if (hwcap & PPC_FEATURE_CELL)
- features.cell = true;
-
features.isa205 = ppc_linux_has_isa205 (hwcap);
+ if ((hwcap2 & PPC_FEATURE2_DSCR)
+ && check_regset (tid, NT_PPC_PPR, PPC_LINUX_SIZEOF_PPRREGSET)
+ && check_regset (tid, NT_PPC_DSCR, PPC_LINUX_SIZEOF_DSCRREGSET))
+ {
+ features.ppr_dscr = true;
+ if ((hwcap2 & PPC_FEATURE2_ARCH_2_07)
+ && (hwcap2 & PPC_FEATURE2_TAR)
+ && (hwcap2 & PPC_FEATURE2_EBB)
+ && check_regset (tid, NT_PPC_TAR, PPC_LINUX_SIZEOF_TARREGSET)
+ && check_regset (tid, NT_PPC_EBB, PPC_LINUX_SIZEOF_EBBREGSET)
+ && check_regset (tid, NT_PPC_PMU, PPC_LINUX_SIZEOF_PMUREGSET))
+ {
+ features.isa207 = true;
+ if ((hwcap2 & PPC_FEATURE2_HTM)
+ && check_regset (tid, NT_PPC_TM_SPR,
+ PPC_LINUX_SIZEOF_TM_SPRREGSET))
+ features.htm = true;
+ }
+ }
+
return ppc_linux_match_description (features);
}