From patchwork Mon Jun 27 14:49:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bhushan Attarde X-Patchwork-Id: 13385 Received: (qmail 8242 invoked by alias); 27 Jun 2016 14:50:18 -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 8144 invoked by uid 89); 27 Jun 2016 14:50:17 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=3.5 required=5.0 tests=AWL, BAYES_00, GARBLED_SUBJECT, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, SPF_PASS autolearn=no version=3.3.2 spammy=1209, 27, 6, odd, 120, 9 X-HELO: mailapp01.imgtec.com Received: from mailapp01.imgtec.com (HELO mailapp01.imgtec.com) (195.59.15.196) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 27 Jun 2016 14:50:14 +0000 Received: from hhmail02.hh.imgtec.org (unknown [10.100.10.20]) by Forcepoint Email with ESMTPS id 3D659638633F6 for ; Mon, 27 Jun 2016 15:50:07 +0100 (IST) Received: from pudesk170.pu.imgtec.org (192.168.93.65) by hhmail02.hh.imgtec.org (10.100.10.20) with Microsoft SMTP Server (TLS) id 14.3.294.0; Mon, 27 Jun 2016 15:50:10 +0100 From: Bhushan Attarde To: CC: , , , , , Bhushan Attarde Subject: [PATCH 04/24] Add MIPS Config5 register related support Date: Mon, 27 Jun 2016 20:19:31 +0530 Message-ID: <1467038991-6600-4-git-send-email-bhushan.attarde@imgtec.com> In-Reply-To: <1467038991-6600-1-git-send-email-bhushan.attarde@imgtec.com> References: <1467038991-6600-1-git-send-email-bhushan.attarde@imgtec.com> MIME-Version: 1.0 This patch has below changes: 1. Add a Config5 register binding in order to get access to the FRE floating point mode bit. The internal register number is allocated dynamically only when provided by the target description, and is tracked in struct mips_regnum. 2. MIPS native: Use FP regset to support Config5 Use the NT_FPREGSET register set in preference to PTRACE_GETFPREGS for getting the floating point registers. This register set also provides the Config5 register which PTRACE_GETFPREGS doesn't. 3. Define type for the MIPS CP0 Config5 register, allowing the important fields to be decoded. gdb/ChangeLog: * mips-tdep.c (mips_config5_type): New function. (mips_linux_reg_names): Add config5. (mips_gdbarch_init): Initialise config5 register number and bind to named config5 register in target description. (mips_value_to_register): Return config5_type for config5 register. * mips-tdep.h (struct mips_regnum): New config5 field. (gdbarch_tdep): New config5_type field. * mips-linux-nat.c: Include "elf/common.h". (PTRACE_GETREGSET, PTRACE_SETREGSET): New fallback definitions. (have_ptrace_getregset_gp, have_ptrace_getregset_fp): New variables. (mips64_linux_regsets_fetch_registers): Use PTRACE_GETREGSET with NT_FPREGSET in preferance to PTRACE_GETFPREGS to get FP and Config5 registers. (mips64_linux_regsets_store_registers): Use PTRACE_SETREGSET with NT_FPREGSET in preferance to PTRACE_SETFPREGS to get FP and Config5 registers --- gdb/mips-linux-nat.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++----- gdb/mips-tdep.c | 35 ++++++++ gdb/mips-tdep.h | 4 + 3 files changed, 239 insertions(+), 21 deletions(-) diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c index bfe9fcb..627c652 100644 --- a/gdb/mips-linux-nat.c +++ b/gdb/mips-linux-nat.c @@ -27,6 +27,7 @@ #include "linux-nat.h" #include "mips-linux-tdep.h" #include "target-descriptions.h" +#include "elf/common.h" #include "gdb_proc_service.h" #include "gregset.h" @@ -46,10 +47,22 @@ #define PTRACE_GET_THREAD_AREA 25 #endif +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif + +#ifndef PTRACE_SETREGSET +#define PTRACE_SETREGSET 0x4205 +#endif + /* Assume that we have PTRACE_GETREGS et al. support. If we do not, we'll clear this and use PTRACE_PEEKUSER instead. */ static int have_ptrace_regsets = 1; +/* Does the current host support PTRACE_GETREGSET? */ +static int have_ptrace_getregset_gp = 1; +static int have_ptrace_getregset_fp = 1; + /* Saved function pointers to fetch and store a single register using PTRACE_PEEKUSER and PTRACE_POKEUSER. */ @@ -217,18 +230,25 @@ mips64_linux_regsets_fetch_registers (struct target_ops *ops, struct regcache *regcache, int regno) { struct gdbarch *gdbarch = get_regcache_arch (regcache); + int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG); int is_fp, is_dsp; int have_dsp; int regi; int tid; - if (regno >= mips_regnum (gdbarch)->fp0 - && regno <= mips_regnum (gdbarch)->fp0 + 32) + /* FP registers can be obtained in several ways. + is_fp will be cleared once the registers have been obtained. */ + if (regno == -1) + is_fp = 1; + else if (regno >= mips_regnum (gdbarch)->fp0 + && regno <= mips_regnum (gdbarch)->fp0 + 32) is_fp = 1; else if (regno == mips_regnum (gdbarch)->fp_control_status) is_fp = 1; else if (regno == mips_regnum (gdbarch)->fp_implementation_revision) is_fp = 1; + else if (regno == mips_regnum (gdbarch)->config5) + is_fp = 1; else is_fp = 0; @@ -266,23 +286,93 @@ mips64_linux_regsets_fetch_registers (struct target_ops *ops, (const mips64_elf_gregset_t *) ®s); } - if (regno == -1 || is_fp) + if (is_fp) { - mips64_elf_fpregset_t fp_regs; + const struct mips_regnum *rn = mips_regnum (gdbarch); + int float_regnum = rn->fp0; - if (ptrace (PTRACE_GETFPREGS, tid, 0L, - (PTRACE_TYPE_ARG3) &fp_regs) == -1) + /* Try the FP regset next as it may contain Config5 */ + if (have_ptrace_getregset_gp && have_ptrace_getregset_fp) { - if (errno == EIO) + unsigned char fp_regs[34][8]; + struct iovec iovec; + int ret; + + iovec.iov_base = &fp_regs; + iovec.iov_len = sizeof (fp_regs); + + ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec); + if (ret < 0) { - have_ptrace_regsets = 0; - return; + if (errno == EIO) + have_ptrace_getregset_gp = 0; + else if (errno == EINVAL) + have_ptrace_getregset_fp = 0; + else + perror_with_name (_("Unable to fetch FP registers.")); + } + else + { + for (regi = 0; regi < 32; regi++) + { + if (register_size (gdbarch, float_regnum + regi) == 8) + { + /* FR = 1 + copy entire double */ + regcache_raw_supply (regcache, float_regnum + regi, + (char *) fp_regs[regi]); + } + else if (regi & 1) + { + /* FR = 0 + odd single from top of even double */ + regcache_raw_supply (regcache, float_regnum + regi, + (char *) fp_regs[regi - 1] + + 4 - 4*big_endian); + } + else + { + /* FR = 0 + even single from bottom of even double */ + regcache_raw_supply (regcache, float_regnum + regi, + (char *) fp_regs[regi] + 4 * big_endian); + } + } + + if (iovec.iov_len >= 32*8 + 4) + regcache_raw_supply (regcache, rn->fp_control_status, + (char *) (fp_regs + 32) + 0); + if (iovec.iov_len >= 32*8 + 8) + regcache_raw_supply (regcache, rn->fp_implementation_revision, + (char *) (fp_regs + 32) + 4); + if (iovec.iov_len >= 33*8 + 4 && rn->config5 >= 0) + regcache_raw_supply (regcache, rn->config5, + (char *) (fp_regs + 33) + 0); + + /* we've got fp registers now */ + is_fp = 0; } - perror_with_name (_("Couldn't get FP registers")); } - mips64_supply_fpregset (regcache, - (const mips64_elf_fpregset_t *) &fp_regs); + /* Fall back to GETFPREGS. */ + if (is_fp) + { + mips64_elf_fpregset_t fp_regs; + + if (ptrace (PTRACE_GETFPREGS, tid, 0L, + (PTRACE_TYPE_ARG3) &fp_regs) == -1) + { + if (errno == EIO) + { + have_ptrace_regsets = 0; + return; + } + perror_with_name (_("Couldn't get FP registers")); + } + + mips64_supply_fpregset (regcache, + (const mips64_elf_fpregset_t *) &fp_regs); + } } if (is_dsp) @@ -305,11 +395,16 @@ mips64_linux_regsets_store_registers (struct target_ops *ops, struct regcache *regcache, int regno) { struct gdbarch *gdbarch = get_regcache_arch (regcache); + int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG); int is_fp, is_dsp; int have_dsp; int regi; int tid; + /* FP registers can be written in several ways. + is_fp will be cleared once the registers have been written. */ + if (regno == -1) + is_fp = 1; if (regno >= mips_regnum (gdbarch)->fp0 && regno <= mips_regnum (gdbarch)->fp0 + 32) is_fp = 1; @@ -317,6 +412,8 @@ mips64_linux_regsets_store_registers (struct target_ops *ops, is_fp = 1; else if (regno == mips_regnum (gdbarch)->fp_implementation_revision) is_fp = 1; + else if (regno == mips_regnum (gdbarch)->config5) + is_fp = 1; else is_fp = 0; @@ -349,19 +446,101 @@ mips64_linux_regsets_store_registers (struct target_ops *ops, perror_with_name (_("Couldn't set registers")); } - if (regno == -1 || is_fp) + if (is_fp) { - mips64_elf_fpregset_t fp_regs; + const struct mips_regnum *rn = mips_regnum (gdbarch); + int float_regnum = rn->fp0; + + /* Try the FP regset next as it may contain Config5 */ + if (have_ptrace_getregset_gp && have_ptrace_getregset_fp) + { + unsigned char fp_regs[34][8]; + struct iovec iovec; + int ret; + + iovec.iov_base = &fp_regs; + iovec.iov_len = sizeof (fp_regs); - if (ptrace (PTRACE_GETFPREGS, tid, 0L, - (PTRACE_TYPE_ARG3) &fp_regs) == -1) - perror_with_name (_("Couldn't get FP registers")); + ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec); + if (ret < 0) + { + if (errno == EIO) + have_ptrace_getregset_gp = 0; + else if (errno == EINVAL) + have_ptrace_getregset_fp = 0; + else + perror_with_name (_("Unable to fetch FP registers.")); + } + else + { + for (regi = 0; regi < 32; regi++) + { + if (register_size (gdbarch, float_regnum + regi) == 8) + { + /* FR = 1 + copy entire double */ + regcache_raw_collect (regcache, float_regnum + regi, + (char *) fp_regs[regi]); + } + else if (regi & 1) + { + /* FR = 0 + odd single from top of even double */ + regcache_raw_collect (regcache, float_regnum + regi, + (char *) fp_regs[regi - 1] + + 4 - 4*big_endian); + } + else + { + /* FR = 0 + even single from bottom of even double */ + regcache_raw_collect (regcache, float_regnum + regi, + (char *) fp_regs[regi] + 4 * big_endian); + } + } + + regcache_raw_collect (regcache, rn->fp_control_status, + (char *) (fp_regs + 32) + 0); + regcache_raw_collect (regcache, rn->fp_implementation_revision, + (char *) (fp_regs + 32) + 4); + if (rn->config5 >= 0) + regcache_raw_collect (regcache, rn->config5, + (char *) (fp_regs + 33) + 0); + + /* don't modify iovec length from amount of data returned */ + ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iovec); + if (ret < 0) + { + if (errno == EIO) + have_ptrace_getregset_gp = 0; + else if (errno == EINVAL) + have_ptrace_getregset_fp = 0; + else + perror_with_name (_("Unable to store FP/MSA registers.")); + } + else + { + /* we've got fp registers now */ + is_fp = 0; + } + } + } - mips64_fill_fpregset (regcache, &fp_regs, regno); + /* Fall back to SETFPREGS. */ + if (is_fp) + { + mips64_elf_fpregset_t fp_regs; + + if (ptrace (PTRACE_GETFPREGS, tid, 0L, + (PTRACE_TYPE_ARG3) &fp_regs) == -1) + perror_with_name (_("Couldn't get FP registers")); - if (ptrace (PTRACE_SETFPREGS, tid, 0L, - (PTRACE_TYPE_ARG3) &fp_regs) == -1) - perror_with_name (_("Couldn't set FP registers")); + mips64_fill_fpregset (regcache, &fp_regs, regno); + + if (ptrace (PTRACE_SETFPREGS, tid, 0L, + (PTRACE_TYPE_ARG3) &fp_regs) == -1) + perror_with_name (_("Couldn't set FP registers")); + } } if (is_dsp) diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index ae4dc2e..28cfb57 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -993,6 +993,25 @@ mips_register_to_value (struct frame_info *frame, int regnum, } } +static struct type * +mips_config5_type (struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (tdep->config5_type == NULL) + { + struct type *t; + /* top half has flags */ + t = arch_flags_type (gdbarch, "__gdb_builtin_type_config5", 4); + append_flags_type_flag (t, 8, "FRE"); + + TYPE_NAME (t) = "config5"; + tdep->config5_type = t; + } + + return tdep->config5_type; +} + static void mips_value_to_register (struct frame_info *frame, int regnum, struct type *type, const gdb_byte *from) @@ -1080,6 +1099,8 @@ mips_register_type (struct gdbarch *gdbarch, int regnum) else if (rawnum == mips_regnum (gdbarch)->fp_control_status || rawnum == mips_regnum (gdbarch)->fp_implementation_revision) return builtin_type (gdbarch)->builtin_int32; + else if (rawnum == mips_regnum (gdbarch)->config5) + return mips_config5_type (gdbarch); else if (gdbarch_osabi (gdbarch) != GDB_OSABI_IRIX && gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX && rawnum >= MIPS_FIRST_EMBED_REGNUM @@ -1152,6 +1173,9 @@ mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum) && rawnum < mips_regnum (gdbarch)->dspacc + 6))) return builtin_type (gdbarch)->builtin_int32; + if (rawnum == mips_regnum (gdbarch)->config5) + return mips_config5_type (gdbarch); + if (gdbarch_osabi (gdbarch) != GDB_OSABI_IRIX && gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX && rawnum >= MIPS_EMBED_FP0_REGNUM + 32 @@ -8236,6 +8260,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) info.tdep_info = &tdep_info; /* Fill in the OS dependent register numbers and names. */ + mips_regnum.config5 = -1; if (info.osabi == GDB_OSABI_IRIX) { mips_regnum.fp0 = 32; @@ -8350,6 +8375,15 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) valid_p &= tdesc_numbered_register (feature, tdesc_data, mips_regnum.cause, "cause"); + /* Optionally, Config5 contains FP mode bits */ + if (tdesc_unnumbered_register (feature, "config5")) + { + /* Allocate a new register. */ + mips_regnum.config5 = num_regs++; + tdesc_numbered_register (feature, tdesc_data, + mips_regnum.config5, "config5"); + } + if (!valid_p) { tdesc_data_cleanup (tdesc_data); @@ -8666,6 +8700,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->register_size = 0; tdep->fp_register_size = info.tdep_info->fp_register_size; tdep->fp_register_size_fixed_p = 0; + tdep->config5_type = NULL; if (info.target_desc) { diff --git a/gdb/mips-tdep.h b/gdb/mips-tdep.h index 6c1d9ca..39af72b 100644 --- a/gdb/mips-tdep.h +++ b/gdb/mips-tdep.h @@ -63,6 +63,7 @@ struct mips_regnum int fp0; int fp_implementation_revision; int fp_control_status; + int config5; int badvaddr; /* Bad vaddr for addressing exception. */ int cause; /* Describes last exception. */ int hi; /* Multiply/divide temp. */ @@ -119,6 +120,9 @@ struct gdbarch_tdep int fp_register_size_fixed_p; int fp_register_size; + /* ISA-specific data types. */ + struct type *config5_type; + /* Return the expected next PC if FRAME is stopped at a syscall instruction. */ CORE_ADDR (*syscall_next_pc) (struct frame_info *frame);