From patchwork Thu May 10 19:58:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: pedromfc X-Patchwork-Id: 27215 Received: (qmail 88921 invoked by alias); 10 May 2018 21:18:06 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 88457 invoked by uid 89); 10 May 2018 21:18:05 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, NO_DNS_FOR_FROM, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=collector X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0a-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.156.1) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 10 May 2018 21:18:03 +0000 Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w4AJwxXd100821 for ; Thu, 10 May 2018 15:59:15 -0400 Received: from e33.co.us.ibm.com (e33.co.us.ibm.com [32.97.110.151]) by mx0a-001b2d01.pphosted.com with ESMTP id 2hvuyp1ra8-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 10 May 2018 15:59:14 -0400 Received: from localhost by e33.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 10 May 2018 13:59:14 -0600 Received: from b03cxnp08028.gho.boulder.ibm.com (9.17.130.20) by e33.co.us.ibm.com (192.168.1.133) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 10 May 2018 13:59:12 -0600 Received: from b03ledav005.gho.boulder.ibm.com (b03ledav005.gho.boulder.ibm.com [9.17.130.236]) by b03cxnp08028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w4AJxCCY11796990 for ; Thu, 10 May 2018 12:59:12 -0700 Received: from b03ledav005.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 51262BE051 for ; Thu, 10 May 2018 13:59:12 -0600 (MDT) Received: from pedro.localdomain (unknown [9.18.235.221]) by b03ledav005.gho.boulder.ibm.com (Postfix) with ESMTP id 187CFBE03B for ; Thu, 10 May 2018 13:59:12 -0600 (MDT) Received: by pedro.localdomain (Postfix, from userid 1000) id 75FAD3C03E2; Thu, 10 May 2018 16:59:07 -0300 (-03) From: Pedro Franco de Carvalho To: gdb-patches@sourceware.org Subject: [PATCH 5/8] [PowerPC] Fix access to VSCR in linux targets Date: Thu, 10 May 2018 16:58:37 -0300 In-Reply-To: <20180510195840.17734-1-pedromfc@linux.vnet.ibm.com> References: <20180510195840.17734-1-pedromfc@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18051019-0008-0000-0000-000009C1227A X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00009001; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000259; SDB=6.01030392; UDB=6.00526595; IPR=6.00809523; MB=3.00021034; MTD=3.00000008; XFM=3.00000015; UTC=2018-05-10 19:59:13 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18051019-0009-0000-0000-000047347901 Message-Id: <20180510195840.17734-6-pedromfc@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-05-10_06:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1805100185 X-IsSubscribed: yes The 4-byte VSCR register is found inside a 16-byte field in the regset returned by ptrace and in core files. The position of VSCR depends on the endianess of the target, which was previously assumed to be big-endian for the purpose of getting VSCR. This patch removes this assumption to fix access to VSCR in little-endian mode. gdb/ChangeLog: yyyy-mm-dd Pedro Franco de Carvalho * ppc-linux-tdep.c (ppc_linux_collect_vrregset): New function. (ppc_linux_vrregset) : New function. (ppc32_le_linux_vrregmap, ppc32_be_linux_vrregmap) (ppc32_le_linux_vrregset, ppc32_be_linux_vrregset): New globals. (ppc32_linux_vrregset): Remove. (ppc_linux_iterate_over_regset_sections): Call ppc_linux_vrregset and use result instead of ppc32_linux_vrregset. * ppc-linux-tdep.h (ppc_linux_vrregset): New declaration. * ppc-linux-nat.c: Include regset.h. (gdb_vrregset_t): Adjust comment to account for little-endian mode. (supply_vrregset, fill_vrregset): Remove. (fetch_altivec_register, store_altivec_register): Remove. (fetch_altivec_registers): Add regno parameter. Get regset using ppc_linux_vrregset. Use regset to supply registers. (store_altivec_registers): Add regno parameter. Get regset using ppc_linux_vrregset. Use regset to collect registers. (fetch_register): Call fetch_altivec_registers instead of fetch_altivec_register. (store_register): Call store_altivec_registers instead of store_altivec_register. (fetch_ppc_registers): Call fetch_altivec_registers with -1 for the new regno parameter. (store_ppc_registers): Call store_altivec_registers with -1 for the new regno parameter. gdb/gdbserver/ChangeLog: yyyy-mm-dd Pedro Franco de Carvalho * linux-ppc-low.c (ppc_fill_vrregset): Add vscr_offset variable. Set vscr_offset to 0 in little-endian mode and 12 in big-endian mode. Call collect_register_by_name with vscr using vscr_offset. Zero-pad vscr and vrsave fields in collector buffer. (ppc_store_vrregset): Add and set vscr_offset variable as in ppc_fill_vrregset. Call supply_register_by_name with vscr using vscr_offset. --- gdb/gdbserver/linux-ppc-low.c | 19 +++++- gdb/ppc-linux-nat.c | 153 +++++++----------------------------------- gdb/ppc-linux-tdep.c | 65 ++++++++++++++++-- gdb/ppc-linux-tdep.h | 3 + 4 files changed, 103 insertions(+), 137 deletions(-) diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c index ed48fa7850..91e6625121 100644 --- a/gdb/gdbserver/linux-ppc-low.c +++ b/gdb/gdbserver/linux-ppc-low.c @@ -486,12 +486,22 @@ ppc_fill_vrregset (struct regcache *regcache, void *buf) { int i, base; char *regset = (char *) buf; + int vscr_offset = 0; base = find_regno (regcache->tdesc, "vr0"); for (i = 0; i < 32; i++) collect_register (regcache, base + i, ®set[i * 16]); - collect_register_by_name (regcache, "vscr", ®set[32 * 16 + 12]); + if (__BYTE_ORDER == __BIG_ENDIAN) + vscr_offset = 12; + + /* Zero-pad the unused bytes in the fields for vscr and vrsave in + case they get displayed somewhere. */ + memset (®set[32 * 16], 0, 16); + collect_register_by_name (regcache, "vscr", + ®set[32 * 16 + vscr_offset]); + + memset (®set[33 * 16], 0, 16); collect_register_by_name (regcache, "vrsave", ®set[33 * 16]); } @@ -500,12 +510,17 @@ ppc_store_vrregset (struct regcache *regcache, const void *buf) { int i, base; const char *regset = (const char *) buf; + int vscr_offset = 0; base = find_regno (regcache->tdesc, "vr0"); for (i = 0; i < 32; i++) supply_register (regcache, base + i, ®set[i * 16]); - supply_register_by_name (regcache, "vscr", ®set[32 * 16 + 12]); + if (__BYTE_ORDER == __BIG_ENDIAN) + vscr_offset = 12; + + supply_register_by_name (regcache, "vscr", + ®set[32 * 16 + vscr_offset]); supply_register_by_name (regcache, "vrsave", ®set[33 * 16]); } diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index 554aba662e..85cd08cd8e 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -24,6 +24,7 @@ #include "gdbthread.h" #include "gdbcore.h" #include "regcache.h" +#include "regset.h" #include "target.h" #include "linux-nat.h" #include @@ -160,17 +161,18 @@ struct ppc_hw_breakpoint Even though this vrsave register is not included in the regset typedef, it is handled by the ptrace requests. - Note that GNU/Linux doesn't support little endian PPC hardware, - therefore the offset at which the real value of the VSCR register - is located will be always 12 bytes. - The layout is like this (where x is the actual value of the vscr reg): */ /* *INDENT-OFF* */ /* +Big-Endian: |.|.|.|.|.....|.|.|.|.||.|.|.|x||.| <-------> <-------><-------><-> VR0 VR31 VSCR VRSAVE +Little-Endian: + |.|.|.|.|.....|.|.|.|.||X|.|.|.||.| + <-------> <-------><-------><-> + VR0 VR31 VSCR VRSAVE */ /* *INDENT-ON* */ @@ -435,14 +437,13 @@ fetch_vsx_register (struct regcache *regcache, int tid, int regno) registers set mechanism, as opposed to the interface for all the other registers, that stores/fetches each register individually. */ static void -fetch_altivec_register (struct regcache *regcache, int tid, int regno) +fetch_altivec_registers (struct regcache *regcache, int tid, + int regno) { int ret; - int offset = 0; gdb_vrregset_t regs; struct gdbarch *gdbarch = regcache->arch (); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum); + const struct regset *vrregset = ppc_linux_vrregset (gdbarch); ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s); if (ret < 0) @@ -452,19 +453,11 @@ fetch_altivec_register (struct regcache *regcache, int tid, int regno) have_ptrace_getvrregs = 0; return; } - perror_with_name (_("Unable to fetch AltiVec register")); + perror_with_name (_("Unable to fetch AltiVec registers")); } - - /* VSCR is fetched as a 16 bytes quantity, but it is really 4 bytes - long on the hardware. We deal only with the lower 4 bytes of the - vector. VRSAVE is at the end of the array in a 4 bytes slot, so - there is no need to define an offset for it. */ - if (regno == (tdep->ppc_vrsave_regnum - 1)) - offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum); - - regcache_raw_supply (regcache, regno, - regs + (regno - - tdep->ppc_vr0_regnum) * vrregsize + offset); + + vrregset->supply_regset(vrregset, regcache, regno, ®s, + PPC_LINUX_SIZEOF_VRREGSET); } /* Fetch the top 32 bits of TID's general-purpose registers and the @@ -559,7 +552,7 @@ fetch_register (struct regcache *regcache, int tid, int regno) register. */ if (have_ptrace_getvrregs) { - fetch_altivec_register (regcache, tid, regno); + fetch_altivec_registers (regcache, tid, regno); return; } /* If we have discovered that there is no ptrace support for @@ -647,31 +640,6 @@ supply_vsxregset (struct regcache *regcache, gdb_vsxregset_t *vsxregsetp) } static void -supply_vrregset (struct regcache *regcache, gdb_vrregset_t *vrregsetp) -{ - int i; - struct gdbarch *gdbarch = regcache->arch (); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1; - int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum); - int offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum); - - for (i = 0; i < num_of_vrregs; i++) - { - /* The last 2 registers of this set are only 32 bit long, not - 128. However an offset is necessary only for VSCR because it - occupies a whole vector, while VRSAVE occupies a full 4 bytes - slot. */ - if (i == (num_of_vrregs - 2)) - regcache_raw_supply (regcache, tdep->ppc_vr0_regnum + i, - *vrregsetp + i * vrregsize + offset); - else - regcache_raw_supply (regcache, tdep->ppc_vr0_regnum + i, - *vrregsetp + i * vrregsize); - } -} - -static void fetch_vsx_registers (struct regcache *regcache, int tid) { int ret; @@ -690,25 +658,6 @@ fetch_vsx_registers (struct regcache *regcache, int tid) supply_vsxregset (regcache, ®s); } -static void -fetch_altivec_registers (struct regcache *regcache, int tid) -{ - int ret; - gdb_vrregset_t regs; - - ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s); - if (ret < 0) - { - if (errno == EIO) - { - have_ptrace_getvrregs = 0; - return; - } - perror_with_name (_("Unable to fetch AltiVec registers")); - } - supply_vrregset (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. @@ -847,7 +796,7 @@ fetch_ppc_registers (struct regcache *regcache, int tid) fetch_register (regcache, tid, tdep->ppc_fpscr_regnum); if (have_ptrace_getvrregs) if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) - fetch_altivec_registers (regcache, tid); + fetch_altivec_registers (regcache, tid, -1); if (have_ptrace_getsetvsxregs) if (tdep->ppc_vsr0_upper_regnum != -1) fetch_vsx_registers (regcache, tid); @@ -898,16 +847,14 @@ store_vsx_register (const struct regcache *regcache, int tid, int regno) perror_with_name (_("Unable to store VSX register")); } -/* Store one register. */ static void -store_altivec_register (const struct regcache *regcache, int tid, int regno) +store_altivec_registers (const struct regcache *regcache, int tid, + int regno) { int ret; - int offset = 0; gdb_vrregset_t regs; struct gdbarch *gdbarch = regcache->arch (); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum); + const struct regset *vrregset = ppc_linux_vrregset (gdbarch); ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s); if (ret < 0) @@ -917,21 +864,15 @@ store_altivec_register (const struct regcache *regcache, int tid, int regno) have_ptrace_getvrregs = 0; return; } - perror_with_name (_("Unable to fetch AltiVec register")); + perror_with_name (_("Unable to fetch AltiVec registers")); } - /* VSCR is fetched as a 16 bytes quantity, but it is really 4 bytes - long on the hardware. */ - if (regno == (tdep->ppc_vrsave_regnum - 1)) - offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum); - - regcache_raw_collect (regcache, regno, - regs + (regno - - tdep->ppc_vr0_regnum) * vrregsize + offset); + vrregset->collect_regset (vrregset, regcache, regno, ®s, + PPC_LINUX_SIZEOF_VRREGSET); ret = ptrace (PTRACE_SETVRREGS, tid, 0, ®s); if (ret < 0) - perror_with_name (_("Unable to store AltiVec register")); + perror_with_name (_("Unable to store AltiVec registers")); } /* Assuming TID referrs to an SPE process, set the top halves of TID's @@ -1034,7 +975,7 @@ store_register (const struct regcache *regcache, int tid, int regno) if (altivec_register_p (gdbarch, regno)) { - store_altivec_register (regcache, tid, regno); + store_altivec_registers (regcache, tid, regno); return; } if (vsx_register_p (gdbarch, regno)) @@ -1111,29 +1052,6 @@ fill_vsxregset (const struct regcache *regcache, gdb_vsxregset_t *vsxregsetp) } static void -fill_vrregset (const struct regcache *regcache, gdb_vrregset_t *vrregsetp) -{ - int i; - struct gdbarch *gdbarch = regcache->arch (); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1; - int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum); - int offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum); - - for (i = 0; i < num_of_vrregs; i++) - { - /* The last 2 registers of this set are only 32 bit long, not - 128, but only VSCR is fetched as a 16 bytes quantity. */ - if (i == (num_of_vrregs - 2)) - regcache_raw_collect (regcache, tdep->ppc_vr0_regnum + i, - *vrregsetp + i * vrregsize + offset); - else - regcache_raw_collect (regcache, tdep->ppc_vr0_regnum + i, - *vrregsetp + i * vrregsize); - } -} - -static void store_vsx_registers (const struct regcache *regcache, int tid) { int ret; @@ -1156,29 +1074,6 @@ store_vsx_registers (const struct regcache *regcache, int tid) perror_with_name (_("Couldn't write VSX registers")); } -static void -store_altivec_registers (const struct regcache *regcache, int tid) -{ - int ret; - gdb_vrregset_t regs; - - ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s); - if (ret < 0) - { - if (errno == EIO) - { - have_ptrace_getvrregs = 0; - return; - } - perror_with_name (_("Couldn't get AltiVec registers")); - } - - fill_vrregset (regcache, ®s); - - if (ptrace (PTRACE_SETVRREGS, tid, 0, ®s) < 0) - perror_with_name (_("Couldn't write AltiVec registers")); -} - /* This function actually issues the request to ptrace, telling it to store all general-purpose registers present in the specified regset. @@ -1337,7 +1232,7 @@ 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); + store_altivec_registers (regcache, tid, -1); if (have_ptrace_getsetvsxregs) if (tdep->ppc_vsr0_upper_regnum != -1) store_vsx_registers (regcache, tid); diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 344069d752..3c8ba26f8e 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -444,6 +444,24 @@ ppc_linux_collect_gregset (const struct regset *regset, } } +static void +ppc_linux_collect_vrregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *buf, size_t len) +{ + gdb_byte *vrregs = (gdb_byte *) buf; + + /* Zero-pad the unused bytes in the fields for vscr and vrsave + in case they get displayed somewhere (e.g. in core files). */ + if (regnum == PPC_VSCR_REGNUM || regnum == -1) + memset (&vrregs[32 * 16], 0, 16); + + if (regnum == PPC_VRSAVE_REGNUM || regnum == -1) + memset (&vrregs[33 * 16], 0, 16); + + regcache_collect_regset (regset, regcache, regnum, buf, len); +} + /* Regset descriptions. */ static const struct ppc_reg_offsets ppc32_linux_reg_offsets = { @@ -513,10 +531,33 @@ static const struct regset ppc32_linux_fpregset = { ppc_collect_fpregset }; -static const struct regset ppc32_linux_vrregset = { - &ppc32_linux_reg_offsets, - ppc_supply_vrregset, - ppc_collect_vrregset +static const struct regcache_map_entry ppc32_le_linux_vrregmap[] = + { + { 32, PPC_VR0_REGNUM, 16 }, + { 1, PPC_VSCR_REGNUM, 16 }, + { 1, PPC_VRSAVE_REGNUM, 16 }, + { 0 } + }; + +static const struct regcache_map_entry ppc32_be_linux_vrregmap[] = + { + { 32, PPC_VR0_REGNUM, 16 }, + { 1, REGCACHE_MAP_SKIP, 12}, + { 1, PPC_VSCR_REGNUM, 4 }, + { 1, PPC_VRSAVE_REGNUM, 16 }, + { 0 } + }; + +static const struct regset ppc32_le_linux_vrregset = { + ppc32_le_linux_vrregmap, + regcache_supply_regset, + ppc_linux_collect_vrregset +}; + +static const struct regset ppc32_be_linux_vrregset = { + ppc32_be_linux_vrregmap, + regcache_supply_regset, + ppc_linux_collect_vrregset }; static const struct regset ppc32_linux_vsxregset = { @@ -537,6 +578,15 @@ ppc_linux_fpregset (void) return &ppc32_linux_fpregset; } +const struct regset * +ppc_linux_vrregset (struct gdbarch *gdbarch) +{ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + return &ppc32_be_linux_vrregset; + else + return &ppc32_le_linux_vrregset; +} + /* Iterate over supported core file register note sections. */ static void @@ -557,8 +607,11 @@ ppc_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, cb (".reg2", 264, &ppc32_linux_fpregset, NULL, cb_data); if (have_altivec) - cb (".reg-ppc-vmx", PPC_LINUX_SIZEOF_VRREGSET, &ppc32_linux_vrregset, - "ppc Altivec", cb_data); + { + const struct regset *vrregset = ppc_linux_vrregset(gdbarch); + cb (".reg-ppc-vmx", PPC_LINUX_SIZEOF_VRREGSET, vrregset, + "ppc Altivec", cb_data); + } if (have_vsx) cb (".reg-ppc-vsx", PPC_LINUX_SIZEOF_VSXREGSET, diff --git a/gdb/ppc-linux-tdep.h b/gdb/ppc-linux-tdep.h index 5e7c4be16b..a8715bd418 100644 --- a/gdb/ppc-linux-tdep.h +++ b/gdb/ppc-linux-tdep.h @@ -28,6 +28,9 @@ struct regset; const struct regset *ppc_linux_gregset (int); 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); + /* Extra register number constants. The Linux kernel stores a "trap" code and the original value of r3 into special "registers"; these need to be saved and restored when performing an inferior