From 2c3305f6b0432e37d26ce7761d0c4415ab5ca911 Mon Sep 17 00:00:00 2001 From: Pedro Franco de Carvalho Date: Tue, 22 May 2018 11:09:05 -0300 Subject: [PATCH] [PowerPC] Fix VSX registers in linux core files The functions used by the VSX regset to collect and supply registers from core files where incorrect. This patch changes the regset to use the standard regset collect/supply functions to fix this. The native target is also changed to use the same regset. gdb/ChangeLog: 2018-05-22 Pedro Franco de Carvalho * ppc-linux-tdep.c (ppc_linux_vsxregset): New function. (ppc32_linux_vsxregmap): New global. (ppc32_linux_vsxregset): Initialize with ppc32_linux_vsxregmap, regcache_supply_regset, and regcache_collect_regset. * ppc-linux-tdep.h (ppc_linux_vsxregset): Declare. * ppc-linux-nat.c (supply_vsxregset, fill_vsxregset): Remove. (fetch_vsx_register, store_vsx_register): Remove. (fetch_vsx_registers): Add regno parameter. Get regset using ppc_linux_vsxregset. Use regset to supply registers. (store_vsx_registers): Add regno parameter. Get regset using ppc_linux_vsxregset. Use regset to collect registers. (fetch_register): Call fetch_vsx_registers instead of fetch_vsx_register. (store_register): Call store_vsx_registers instead of store_vsx_register. (fetch_ppc_registers): Call fetch_vsx_registers with -1 for the new regno parameter. (store_ppc_registers): Call store_vsx_registers with -1 for the new regno parameter. * rs6000-tdep.c (ppc_vsx_support_p, ppc_supply_vsxreget) (ppc_collect_vsxregset): Remove. gdb/testsuite/ChangeLog: 2018-05-22 Pedro Franco de Carvalho * gdb.arch/powerpc-vsx-gcore.exp: New file. --- gdb/ChangeLog | 24 +++++ gdb/ppc-linux-nat.c | 106 +++---------------- gdb/ppc-linux-tdep.c | 18 +++- gdb/ppc-linux-tdep.h | 1 + gdb/rs6000-tdep.c | 74 ------------- gdb/testsuite/ChangeLog | 4 + gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp | 90 ++++++++++++++++ 7 files changed, 149 insertions(+), 168 deletions(-) create mode 100644 gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b234da8ceb1..9e74395b46f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,27 @@ +2018-05-22 Pedro Franco de Carvalho + + * ppc-linux-tdep.c (ppc_linux_vsxregset): New function. + (ppc32_linux_vsxregmap): New global. + (ppc32_linux_vsxregset): Initialize with ppc32_linux_vsxregmap, + regcache_supply_regset, and regcache_collect_regset. + * ppc-linux-tdep.h (ppc_linux_vsxregset): Declare. + * ppc-linux-nat.c (supply_vsxregset, fill_vsxregset): Remove. + (fetch_vsx_register, store_vsx_register): Remove. + (fetch_vsx_registers): Add regno parameter. Get regset using + ppc_linux_vsxregset. Use regset to supply registers. + (store_vsx_registers): Add regno parameter. Get regset using + ppc_linux_vsxregset. Use regset to collect registers. + (fetch_register): Call fetch_vsx_registers instead of + fetch_vsx_register. + (store_register): Call store_vsx_registers instead of + store_vsx_register. + (fetch_ppc_registers): Call fetch_vsx_registers with -1 for the + new regno parameter. + (store_ppc_registers): Call store_vsx_registers with -1 for the + new regno parameter. + * rs6000-tdep.c (ppc_vsx_support_p, ppc_supply_vsxreget) + (ppc_collect_vsxregset): Remove. + 2018-05-22 Pedro Franco de Carvalho * ppc-tdep.h (struct ppc_reg_offsets): Remove vector register diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index e00831a2483..0f7dd4c8e26 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -409,13 +409,11 @@ ppc_register_u_addr (struct gdbarch *gdbarch, int regno) 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) +fetch_vsx_registers (struct regcache *regcache, int tid, int regno) { int ret; gdb_vsxregset_t regs; - struct gdbarch *gdbarch = regcache->arch (); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum); + const struct regset *vsxregset = ppc_linux_vsxregset (); ret = ptrace (PTRACE_GETVSXREGS, tid, 0, ®s); if (ret < 0) @@ -425,12 +423,11 @@ fetch_vsx_register (struct regcache *regcache, int tid, int regno) have_ptrace_getsetvsxregs = 0; return; } - perror_with_name (_("Unable to fetch VSX register")); + perror_with_name (_("Unable to fetch VSX registers")); } - regcache_raw_supply (regcache, regno, - regs + (regno - tdep->ppc_vsr0_upper_regnum) - * vsxregsize); + vsxregset->supply_regset (vsxregset, regcache, regno, ®s, + PPC_LINUX_SIZEOF_VSXREGSET); } /* The Linux kernel ptrace interface for AltiVec registers uses the @@ -563,7 +560,7 @@ fetch_register (struct regcache *regcache, int tid, int regno) { if (have_ptrace_getsetvsxregs) { - fetch_vsx_register (regcache, tid, regno); + fetch_vsx_registers (regcache, tid, regno); return; } } @@ -624,40 +621,6 @@ fetch_register (struct regcache *regcache, int tid, int regno) gdbarch_byte_order (gdbarch)); } -static void -supply_vsxregset (struct regcache *regcache, gdb_vsxregset_t *vsxregsetp) -{ - int i; - struct gdbarch *gdbarch = regcache->arch (); - 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 -fetch_vsx_registers (struct regcache *regcache, int tid) -{ - int ret; - gdb_vsxregset_t regs; - - ret = ptrace (PTRACE_GETVSXREGS, tid, 0, ®s); - if (ret < 0) - { - if (errno == EIO) - { - have_ptrace_getsetvsxregs = 0; - return; - } - perror_with_name (_("Unable to fetch VSX registers")); - } - supply_vsxregset (regcache, ®s); -} - /* This function actually issues the request to ptrace, telling it to get all general-purpose registers and put them into the specified regset. @@ -799,7 +762,7 @@ fetch_ppc_registers (struct regcache *regcache, int tid) fetch_altivec_registers (regcache, tid, -1); if (have_ptrace_getsetvsxregs) if (tdep->ppc_vsr0_upper_regnum != -1) - fetch_vsx_registers (regcache, tid); + fetch_vsx_registers (regcache, tid, -1); if (tdep->ppc_ev0_upper_regnum >= 0) fetch_spe_register (regcache, tid, -1); } @@ -818,15 +781,12 @@ ppc_linux_nat_target::fetch_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) +store_vsx_registers (const struct regcache *regcache, int tid, int regno) { int ret; gdb_vsxregset_t regs; - struct gdbarch *gdbarch = regcache->arch (); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum); + const struct regset *vsxregset = ppc_linux_vsxregset (); ret = ptrace (PTRACE_GETVSXREGS, tid, 0, ®s); if (ret < 0) @@ -836,15 +796,15 @@ store_vsx_register (const struct regcache *regcache, int tid, int regno) have_ptrace_getsetvsxregs = 0; return; } - perror_with_name (_("Unable to fetch VSX register")); + perror_with_name (_("Unable to fetch VSX registers")); } - regcache_raw_collect (regcache, regno, regs + - (regno - tdep->ppc_vsr0_upper_regnum) * vsxregsize); + vsxregset->collect_regset (vsxregset, regcache, regno, ®s, + PPC_LINUX_SIZEOF_VSXREGSET); ret = ptrace (PTRACE_SETVSXREGS, tid, 0, ®s); if (ret < 0) - perror_with_name (_("Unable to store VSX register")); + perror_with_name (_("Unable to store VSX registers")); } static void @@ -980,7 +940,7 @@ store_register (const struct regcache *regcache, int tid, int regno) } if (vsx_register_p (gdbarch, regno)) { - store_vsx_register (regcache, tid, regno); + store_vsx_registers (regcache, tid, regno); return; } else if (spe_register_p (gdbarch, regno)) @@ -1038,42 +998,6 @@ 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 = regcache->arch (); - 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 -store_vsx_registers (const struct regcache *regcache, int tid) -{ - int ret; - gdb_vsxregset_t regs; - - ret = ptrace (PTRACE_GETVSXREGS, tid, 0, ®s); - if (ret < 0) - { - if (errno == EIO) - { - have_ptrace_getsetvsxregs = 0; - return; - } - perror_with_name (_("Couldn't get VSX registers")); - } - - fill_vsxregset (regcache, ®s); - - if (ptrace (PTRACE_SETVSXREGS, tid, 0, ®s) < 0) - perror_with_name (_("Couldn't write VSX registers")); -} - /* This function actually issues the request to ptrace, telling it to store all general-purpose registers present in the specified regset. @@ -1235,7 +1159,7 @@ store_ppc_registers (const struct regcache *regcache, int tid) store_altivec_registers (regcache, tid, -1); if (have_ptrace_getsetvsxregs) if (tdep->ppc_vsr0_upper_regnum != -1) - store_vsx_registers (regcache, tid); + store_vsx_registers (regcache, tid, -1); if (tdep->ppc_ev0_upper_regnum >= 0) store_spe_register (regcache, tid, -1); } diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 7362c4bbe19..293353a878c 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -553,10 +553,16 @@ static const struct regset ppc32_be_linux_vrregset = { ppc_linux_collect_vrregset }; +static const struct regcache_map_entry ppc32_linux_vsxregmap[] = + { + { 32, PPC_VSR0_UPPER_REGNUM, 8 }, + { 0 } + }; + static const struct regset ppc32_linux_vsxregset = { - &ppc32_linux_reg_offsets, - ppc_supply_vsxregset, - ppc_collect_vsxregset + ppc32_linux_vsxregmap, + regcache_supply_regset, + regcache_collect_regset }; const struct regset * @@ -580,6 +586,12 @@ ppc_linux_vrregset (struct gdbarch *gdbarch) return &ppc32_le_linux_vrregset; } +const struct regset * +ppc_linux_vsxregset (void) +{ + return &ppc32_linux_vsxregset; +} + /* Iterate over supported core file register note sections. */ static void diff --git a/gdb/ppc-linux-tdep.h b/gdb/ppc-linux-tdep.h index a8715bd4184..51f4b506a1a 100644 --- a/gdb/ppc-linux-tdep.h +++ b/gdb/ppc-linux-tdep.h @@ -30,6 +30,7 @@ const struct regset *ppc_linux_fpregset (void); /* Get the vector regset that matches the target byte order. */ const struct regset *ppc_linux_vrregset (struct gdbarch *gdbarch); +const struct regset *ppc_linux_vsxregset (void); /* Extra register number constants. The Linux kernel stores a "trap" code and the original value of r3 into special "registers"; diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index 4ef6f9e9805..0a56c7890ad 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -223,16 +223,6 @@ ppc_floating_point_unit_p (struct gdbarch *gdbarch) && tdep->ppc_fpscr_regnum >= 0); } -/* Return non-zero if the architecture described by GDBARCH has - VSX registers (vsr0 --- vsr63). */ -static int -ppc_vsx_support_p (struct gdbarch *gdbarch) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - return tdep->ppc_vsr0_regnum >= 0; -} - /* Return non-zero if the architecture described by GDBARCH has Altivec registers (vr0 --- vr31, vrsave and vscr). */ int @@ -573,37 +563,6 @@ ppc_supply_fpregset (const struct regset *regset, struct regcache *regcache, regnum == tdep->ppc_fpscr_regnum ? offsets->fpscr_size : 8); } -/* Supply register REGNUM in the VSX register set REGSET - from the buffer specified by VSXREGS and LEN to register cache - REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ - -void -ppc_supply_vsxregset (const struct regset *regset, struct regcache *regcache, - int regnum, const void *vsxregs, size_t len) -{ - struct gdbarch *gdbarch = regcache->arch (); - struct gdbarch_tdep *tdep; - - if (!ppc_vsx_support_p (gdbarch)) - return; - - tdep = gdbarch_tdep (gdbarch); - - if (regnum == -1) - { - int i; - - for (i = tdep->ppc_vsr0_upper_regnum; - i < tdep->ppc_vsr0_upper_regnum + 32; - i++) - ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, 0, 8); - - return; - } - else - ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8); -} - /* Collect register REGNUM in the general-purpose register set REGSET from register cache REGCACHE into the buffer specified by GREGS and LEN. If REGNUM is -1, do this for all registers in @@ -695,39 +654,6 @@ ppc_collect_fpregset (const struct regset *regset, regnum == tdep->ppc_fpscr_regnum ? offsets->fpscr_size : 8); } -/* Collect register REGNUM in the VSX register set - REGSET from register cache REGCACHE into the buffer specified by - VSXREGS and LEN. If REGNUM is -1, do this for all registers in - REGSET. */ - -void -ppc_collect_vsxregset (const struct regset *regset, - const struct regcache *regcache, - int regnum, void *vsxregs, size_t len) -{ - struct gdbarch *gdbarch = regcache->arch (); - struct gdbarch_tdep *tdep; - - if (!ppc_vsx_support_p (gdbarch)) - return; - - tdep = gdbarch_tdep (gdbarch); - - if (regnum == -1) - { - int i; - - for (i = tdep->ppc_vsr0_upper_regnum; - i < tdep->ppc_vsr0_upper_regnum + 32; - i++) - ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, 0, 8); - - return; - } - else - ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8); -} - static int insn_changes_sp_or_jumps (unsigned long insn) { diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index cdd4ba9fa90..82ab864fa19 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2018-05-22 Pedro Franco de Carvalho + + * gdb.arch/powerpc-vsx-gcore.exp: New file. + 2018-05-18 Tom Tromey * gdb.base/ptype-offsets.exp: Update. diff --git a/gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp b/gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp new file mode 100644 index 00000000000..e9bdfcdd445 --- /dev/null +++ b/gdb/testsuite/gdb.arch/powerpc-vsx-gcore.exp @@ -0,0 +1,90 @@ +# Copyright (C) 2018 Free Software Foundation, Inc. +# +# 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 . + +# This file is part of the gdb testsuite. + +# This test checks that generating and loading a core file preserves +# the correct VSX register state. + +if {![istarget "powerpc*-*-linux*"] || [skip_vsx_tests]} then { + verbose "Skipping PowerPC test for corefiles with VSX registers." + return +} + +standard_testfile .c + +set gen_src [standard_output_file $srcfile] + +gdb_produce_source $gen_src { + int main() { + return 0; + } +} + +if {[build_executable "compile" $binfile $gen_src] == -1} { + return -1 +} + +clean_restart $binfile + +if ![runto_main] then { + fail "could not run to main" + return -1 +} + +# Check if VSX register access through gdb is supported +proc check_vsx_access {} { + global gdb_prompt + + set test "vsx register access" + gdb_test_multiple "info reg vs0" "$test" { + -re "Invalid register.*\r\n$gdb_prompt $" { + unsupported "$test" + return 0 + } + -re "\r\nvs0.*\r\n$gdb_prompt $" { + pass "$test" + return 1 + } + } + return 0 +} + +if { ![check_vsx_access] } { + return -1 +} + +for {set i 0} {$i < 64} {incr i 1} { + gdb_test_no_output "set \$vs$i.uint128 = $i" +} + +set core_filename [standard_output_file "$testfile.core"] +set core_generated [gdb_gcore_cmd "$core_filename" "generate core file"] + +if { !$core_generated } { + return -1 +} + +clean_restart + +set core_loaded [gdb_core_cmd "$core_filename" "load core file"] + +if { $core_loaded != 1 } { + return -1 +} + +for {set i 0} {$i < 64} {incr i 1} { + gdb_test "print \$vs$i.uint128" ".* = $i" "print vs$i" +} -- 2.30.2