diff options
author | Edjunior Barbosa Machado <emachado@linux.vnet.ibm.com> | 2018-10-26 09:37:54 -0300 |
---|---|---|
committer | Pedro Franco de Carvalho <pedromfc@linux.ibm.com> | 2018-10-26 10:03:46 -0300 |
commit | 7ca18ed6d22398dd3009ba72d3a1e7747e40753d (patch) | |
tree | c531258259984fbedc9196c14420ca56da323b75 /gdb/ppc-linux-nat.c | |
parent | 93b4691f0fe1f8249de3c3f9d2e271cb0ba3254e (diff) | |
download | gdb-7ca18ed6d22398dd3009ba72d3a1e7747e40753d.zip gdb-7ca18ed6d22398dd3009ba72d3a1e7747e40753d.tar.gz gdb-7ca18ed6d22398dd3009ba72d3a1e7747e40753d.tar.bz2 |
[PowerPC] Add support for PPR and DSCR
This patch adds gdb support for the Program Priorty Register and the
Data Stream Control Register, for the powerpc linux native and core
file targets, and for the powerpc linux server stub.
gdb/ChangeLog:
2018-10-26 Edjunior Barbosa Machado <emachado@linux.vnet.ibm.com>
Pedro Franco de Carvalho <pedromfc@linux.ibm.com>
* arch/ppc-linux-tdesc.h (tdesc_powerpc_isa205_ppr_dscr_vsx32l)
(tdesc_powerpc_isa205_ppr_dscr_vsx64l): Declare.
* arch/ppc-linux-common.h (PPC_LINUX_SIZEOF_PPRREGSET)
(PPC_LINUX_SIZEOF_DSCRREGSET): Define.
(struct ppc_linux_features) <ppr_dscr>: New field.
(ppc_linux_no_features): Add initializer for ppr_dscr field.
* arch/ppc-linux-common.c (ppc_linux_match_description): Return
new tdescs.
* nat/ppc-linux.h (PPC_FEATURE2_DSCR, NT_PPC_PPR, NT_PPC_DSCR):
Define if not already defined.
* features/Makefile (WHICH): Add
rs6000/powerpc-isa205-ppr-dscr-vsx32l and
rs6000/powerpc-isa205-ppr-dscr-vsx64l.
(XMLTOC): Add rs6000/powerpc-isa205-ppr-dscr-vsx32l.xml and
rs6000/powerpc-isa205-ppr-dscr-vsx64l.xml.
* features/rs6000/power-dscr.xml: New file.
* features/rs6000/power-ppr.xml: New file.
* features/rs6000/powerpc-isa205-ppr-dscr-vsx32l.xml: New file.
* features/rs6000/powerpc-isa205-ppr-dscr-vsx64l.xml: New file.
* features/rs6000/powerpc-isa205-ppr-dscr-vsx32l.c: Generate.
* features/rs6000/powerpc-isa205-ppr-dscr-vsx64l.c: Generate.
* regformats/rs6000/powerpc-isa205-ppr-dscr-vsx32l.dat: Generate.
* regformats/rs6000/powerpc-isa205-ppr-dscr-vsx64l.dat: Generate.
* ppc-linux-nat.c: Include <sys/uio.h>.
(fetch_regset, store_regset, check_regset): New functions.
(fetch_register, fetch_ppc_registers): Call fetch_regset with
DSCR and PPR regsets.
(store_register, store_ppc_registers): Call store_regset with
DSCR and PPR regsets.
(ppc_linux_get_hwcap2): New function.
(ppc_linux_nat_target::read_description): Call
ppc_linux_get_hwcap2 and check_regset, set ppr_dscr field in the
features struct if needed.
* ppc-linux-tdep.c: Include
features/rs6000/powerpc-isa205-ppr-dscr-vsx32l.c and
features/rs6000/powerpc-isa205-ppr-dscr-vsx64l.c.
(ppc32_regmap_ppr, ppc32_regmap_dscr, ppc32_linux_pprregset)
(ppc32_linux_dscrregset): New globals.
(ppc_linux_iterate_over_regset_sections): Call back with the ppr
and dscr regsets.
(ppc_linux_core_read_description): Check if the ppr and dscr
sections are present and set ppr_dscr in the features struct.
(_initialize_ppc_linux_tdep): Call
initialize_tdesc_powerpc_isa205_ppr_dscr_vsx32l and
initialize_tdesc_powerpc_isa205_ppr_dscr_vsx64l.
* ppc-linux-tdep.h (ppc32_linux_pprregset)
(ppc32_linux_dscrregset): Declare.
* ppc-tdep.h (struct gdbarch_tdep) <ppc_ppr_regnum>: New field.
<ppc_dscr_regnum>: New field.
(enum) <PPC_PPR_REGNUM, PPC_DSCR_REGNUM>: New enum values.
* rs6000-tdep.c (rs6000_gdbarch_init): Look for and validate ppr
and dscr features.
(ppc_process_record_op31): Record changes to PPR and DSCR.
gdb/gdbserver/ChangeLog:
2018-10-26 Edjunior Barbosa Machado <emachado@linux.vnet.ibm.com>
Pedro Franco de Carvalho <pedromfc@linux.ibm.com>
* configure.srv (ipa_ppc_linux_regobj): Add
powerpc-isa205-ppr-dscr-vsx32l-ipa.o and
powerpc-isa205-ppr-dscr-vsx64l-ipa.o.
(powerpc*-*-linux*): Add powerpc-isa205-ppr-dscr-vsx32l.o and
powerpc-isa205-ppr-dscr-vsx64l.o to srv_regobj, add
rs6000/power-dscr.xml, rs6000/power-ppr.xml,
rs6000/powerpc-isa205-ppr-dscr-vsx32l.xml and
rs6000/powerpc-isa205-ppr-dscr-vsx64l.xml to srv_xmlfiles.
* linux-ppc-tdesc-init.h (enum ppc_linux_tdesc)
<PPC_TDESC_ISA205_PPR_DSCR_VSX>: New enum value.
(init_registers_powerpc_isa205_ppr_dscr_vsx32l)
(init_registers_powerpc_isa205_ppr_dscr_vsx64l): Declare.
* linux-ppc-low.c: Include "elf/common.h" and <sys/uio.h>.
(ppc_hwcap): Add comment.
(ppc_hwcap2): New global.
(ppc_check_regset, ppc_fill_pprregset, ppc_store_pprregset)
(ppc_fill_dscrregset, ppc_store_dscrregset): New functions.
(ppc_regsets): Add entries for the DSCR and PPR regsets.
(ppc_arch_setup): Get AT_HWCAP2. Set ppr_dscr in features struct
when needed. Set sizes for the the DSCR and PPR regsets.
(ppc_get_ipa_tdesc_idx): Return PPC_TDESC_ISA205_PPR_DSCR_VSX.
(initialize_low_arch): Call
init_registers_powerpc_isa205_ppr_dscr_vsx32l and
init_registers_powerpc_isa205_ppr_dscr_vsx64l.
* linux-ppc-ipa.c (get_ipa_tdesc): Handle
PPC_TDESC_ISA205_PPR_DSCR_VSX.
(initialize_low_tracepoint): Call
init_registers_powerpc_isa205_ppr_dscr_vsx32l and
init_registers_powerpc_isa205_ppr_dscr_vsx64l.
gdb/testsuite/ChangeLog:
2018-10-26 Pedro Franco de Carvalho <pedromfc@linux.ibm.com>
* gdb.arch/powerpc-ppr-dscr.c: New file.
* gdb.arch/powerpc-ppr-dscr.exp: New file.
gdb/doc/ChangeLog:
2018-10-26 Pedro Franco de Carvalho <pedromfc@linux.ibm.com>
* gdb.texinfo (PowerPC Features): Describe new features
"org.gnu.gdb.power.ppr" and "org.gnu.gdb.power.dscr".
Diffstat (limited to 'gdb/ppc-linux-nat.c')
-rw-r--r-- | gdb/ppc-linux-nat.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index f96fba4..27c73c2 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -31,6 +31,7 @@ #include <signal.h> #include <sys/user.h> #include <sys/ioctl.h> +#include <sys/uio.h> #include "gdb_wait.h" #include <fcntl.h> #include <sys/procfs.h> @@ -528,10 +529,83 @@ fetch_spe_register (struct regcache *regcache, int tid, int regno) 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 fetch_register (struct regcache *regcache, int tid, int regno) { struct gdbarch *gdbarch = regcache->arch (); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); /* 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; @@ -565,6 +639,24 @@ fetch_register (struct regcache *regcache, int tid, int regno) 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; + } if (regaddr == -1) { @@ -758,6 +850,14 @@ fetch_ppc_registers (struct regcache *regcache, int tid) 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); } /* Fetch registers from the child process. Fetch all registers if @@ -938,6 +1038,24 @@ store_register (const struct regcache *regcache, int tid, int regno) 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; + } if (regaddr == -1) return; @@ -1149,6 +1267,14 @@ store_ppc_registers (const struct regcache *regcache, int tid) store_vsx_registers (regcache, tid, -1); if (tdep->ppc_ev0_upper_regnum >= 0) store_spe_register (regcache, tid, -1); + 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); } /* Fetch the AT_HWCAP entry from the aux vector. */ @@ -1163,6 +1289,19 @@ ppc_linux_get_hwcap (void) return field; } +/* Fetch the AT_HWCAP2 entry from the aux vector. */ + +static CORE_ADDR +ppc_linux_get_hwcap2 (void) +{ + CORE_ADDR field; + + if (target_auxv_search (current_top_target (), AT_HWCAP2, &field) != 1) + return 0; + + return field; +} + /* The cached DABR value, to install in new threads. This variable is used when the PowerPC HWDEBUG ptrace interface is not available. */ @@ -2222,6 +2361,7 @@ ppc_linux_nat_target::read_description () features.wordsize = ppc_linux_target_wordsize (tid); CORE_ADDR hwcap = ppc_linux_get_hwcap (); + CORE_ADDR hwcap2 = ppc_linux_get_hwcap2 (); if (have_ptrace_getsetvsxregs && (hwcap & PPC_FEATURE_HAS_VSX)) @@ -2256,6 +2396,11 @@ ppc_linux_nat_target::read_description () 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; + return ppc_linux_match_description (features); } |