From patchwork Mon Jun 27 14:49:36 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bhushan Attarde X-Patchwork-Id: 13391 Received: (qmail 10883 invoked by alias); 27 Jun 2016 14:50:42 -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 10820 invoked by uid 89); 27 Jun 2016 14:50:41 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=4.4 required=5.0 tests=AWL, BAYES_00, GARBLED_SUBJECT, KAM_WEIRDTRICK1, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, SPF_PASS autolearn=no version=3.3.2 spammy=eight, Therefore, Eight, odd 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:32 +0000 Received: from hhmail02.hh.imgtec.org (unknown [10.100.10.20]) by Forcepoint Email with ESMTPS id 80EFBF95196C3 for ; Mon, 27 Jun 2016 15:50:25 +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:28 +0100 From: Bhushan Attarde To: CC: , , , , , Bhushan Attarde Subject: [PATCH 09/24] MIPS: Enhance cooked FP format Date: Mon, 27 Jun 2016 20:19:36 +0530 Message-ID: <1467038991-6600-9-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 Define cooked FP types as unions representing the possible interpretations of the registers. Previously the type of the cooked floating point registers depended directly on the raw type, so for MIPS32 targets they were single precision, and for MIPS64 targets they were single or double precision depending on the FP mode. However in both cases it is possible for the FP registers to be interpreted as either single or double precision values depending on the instruction executed, and in a different way depending on the FP mode. When FR=0: - Even FP registers can be interpreted as a double (aliasing both odd and even singles), or a single (aliasing the least significant half of the double). - Odd FP registers can be interpreted only as a single (aliasing the most significant half of the even double). When FR=1: - All FP registers can be interpreted as a double, or a single (aliasing the least significant half of the double). Some instructions can also treat them as 32-bit or 64-bit integers for the purposes of converting between formats. Therefore define two cooked fp types, as follows. The first type, fp32, is used for odd FP registers when FR=0, which can only be interpreted as singles or 32-bit integers. It is equivalent to this C definition: union fp32 { float f32; int32_t i32; }; The second type, fp64, is used for even FP registers when FR=0, and all FP registers when FR=1, which can be interpreted as either singles or doubles, with the single always in the least significant half of the double. It is roughly equivalent to this C definition (when interpreted as little endian): union fp64 { float f32; double f64; int32 i32; int64 i64; }; Since multiple bits of code need to handle the different raw register layouts and these new cooked types for different modes, the details are abstracted with the following functions: - mips_get_fp_single_location: Gets the raw register and offset containing a single precision register value. - mips_get_fp_double_location: Gets the raw register(s) and offset(s) composing a double precision register value. - mips_get_fp_multi_location: Gets the raw register(s) and offset(s) composing a cooked register value. These abstractions are used by the code which reads and writes the cooked (pseudo) FP registers, and the code which prints out the FP registers ("info float"). Now that the cooked type may be composed of multiple raw registers (where only single precision raw values are provided), there is no need to provide conversion functions from the 32-bit cooked value to double. Instead the opposite is required for extracting a single out of the 64-bit cooked value. For example, with FR=0: (gdb) info float ... f30: 0x41f00000 flt: 30 dbl: 6442451998.9999998 f31: 0x41f80000 flt: 31 (gdb) p $f30 $1 = {f32 = 30, f64 = 6442451998.9999998, i32 = 1106247680, i64 = 4753549407795806208} (gdb) p $f31 $2 = {f32 = 31, i32 = 1106771968} And with FR=1: (gdb) info float ... f30: 0x403e000041f00000 flt: 30 dbl: 30.000003930181265 f31: 0x403f000041f80000 flt: 31 dbl: 31.00000393204391 (gdb) p $f30 $1 = {f32 = 30, f64 = 30.000003930181265, i32 = 1106247680, i64 = 4629137468089696256} (gdb) p $f31 $2 = {f32 = 31, f64 = 31.00000393204391, i32 = 1106771968, i64 = 4629418943066931200} gdb/ChangeLog: * mips-tdep.c (mips_register_reggroup_p): Match FP registers with mips_float_register_p rather than TYPE_CODE_FLT. (struct mips_reg_part, mips_get_fp_single_location, mips_get_fp_double_location, mips_get_fp_multi_location, mips_regcache_raw_read_parts, mips_regcache_raw_write_parts, mips_fp32_type, mips_fp64_type, mips_fp_type): New definitions. (mips_pseudo_register_read, mips_pseudo_register_write, mips_convert_register_float_case_p, mips_register_to_value, mips_value_to_register, mips_register_type, mips_pseudo_register_type, mips_read_fp_register_single, mips_read_fp_register_double, mips_print_fp_register): Convert to handle new cooked FP format. (mips_gdbarch_init): Initialise tdep->fp32_type and tdep->fp64_type. mips-tdep.h (struct gdbarch_tdep): Add fp32_type and fp64_type. --- gdb/mips-tdep.c | 537 ++++++++++++++++++++++++++++++++++++++++++++------------ gdb/mips-tdep.h | 2 + 2 files changed, 430 insertions(+), 109 deletions(-) diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 47ddef4..0024edf 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -789,6 +789,185 @@ mips_tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regnum, return mips_register_reggroup_p (gdbarch, regnum, reggroup); } +/* Describes a part of a raw register, used for constructing cooked registers. + */ + +struct mips_reg_part +{ + unsigned int regnum; + unsigned char offset; + unsigned char size; +}; + +/* Get the raw register containing a single precision float. + Returns the number of parts (maximum 1) written through loc. */ + +static unsigned int +mips_get_fp_single_location (struct gdbarch *gdbarch, + unsigned int idx, + struct mips_reg_part *loc) +{ + int raw_num = mips_regnum (gdbarch)->fp0; + int raw_len = register_size (gdbarch, raw_num); + enum mips_fpu_mode fp_mode = gdbarch_tdep (gdbarch)->fp_mode; + int big_endian; + + /* Only even doubles provided, in pairs of 32-bit registers. */ + if (raw_len == 4) + { + /* In 64-bit FP mode, odd singles don't alias even doubles. */ + if (fp_mode == MIPS_FPU_64 && idx & 1) + return 0; + + loc->regnum = raw_num + idx; + loc->offset = 0; + loc->size = 4; + return 1; + } + + if (raw_len != 8) + return 0; + + /* All doubles provided. */ + big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG); + + loc->size = 4; + switch (fp_mode) + { + case MIPS_FPU_32: + loc->regnum = raw_num + (idx & ~1); + loc->offset = 4 * (big_endian ^ (idx & 1)); + return 1; + case MIPS_FPU_64: + loc->regnum = raw_num + idx; + loc->offset = 4 * big_endian; + return 1; + default: + return 0; + } +} + +/* Get the raw register part(s) containing a double precision float. + Returns the number of parts (maximum 2) written through loc. */ + +static unsigned int +mips_get_fp_double_location (struct gdbarch *gdbarch, + unsigned int idx, + struct mips_reg_part *loc) +{ + int raw_num = mips_regnum (gdbarch)->fp0; + int raw_len = register_size (gdbarch, raw_num); + enum mips_fpu_mode fp_mode = gdbarch_tdep (gdbarch)->fp_mode; + int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG); + + /* Only even doubles provided, in pairs of 32-bit registers. */ + if (raw_len == 4) + { + /* No odd doubles. */ + if (idx & 1) + return 0; + + /* Even register contains even single, least significant end of double */ + loc[big_endian].regnum = raw_num + idx; + loc[big_endian].offset = 0; + loc[big_endian].size = 4; + loc[!big_endian].regnum = raw_num + idx + 1; + loc[!big_endian].offset = 0; + loc[!big_endian].size = 4; + return 2; + } + + if (raw_len != 8) + return 0; + + /* FPU32 doesn't have odd doubles */ + if (fp_mode == MIPS_FPU_32 && idx & 1) + return 0; + + /* All doubles provided. */ + loc->regnum = raw_num + idx; + loc->offset = 0; + loc->size = 8; + return 1; +} + +/* Get the raw register part(s) composing a cooked float register. + Returns the number of parts (maximum 2) written through loc. */ + +static unsigned int +mips_get_fp_multi_location (struct gdbarch *gdbarch, + unsigned int idx, + unsigned int cooked_len, + struct mips_reg_part *loc) +{ + unsigned int parts, total_parts = 0; + + /* The cooked formats supported are: + fp32 (len=4): just a single. + fp64 (len=8): double (with aliased single). */ + if (cooked_len > 8 || cooked_len < 4 || cooked_len & 0x3) + internal_error (__FILE__, __LINE__, _("bad cooked register size")); + + /* Formats containing a distinct double. */ + if (cooked_len & 8) + { + parts = mips_get_fp_double_location (gdbarch, idx, loc); + if (!parts) + return 0; + total_parts += parts; + loc += parts; + } + + /* Formats containing a distinct single. */ + if (cooked_len & 4) + { + parts = mips_get_fp_single_location (gdbarch, idx, loc); + if (!parts) + return 0; + total_parts += parts; + } + + return total_parts; +} + +/* Read multiple register parts from the register cache into a buffer. */ + +static enum register_status +mips_regcache_raw_read_parts (struct regcache *regcache, + struct mips_reg_part *loc, + unsigned int parts, + gdb_byte **buf) +{ + enum register_status ret = REG_UNAVAILABLE; + + for (; parts; --parts, ++loc) + { + ret = regcache_raw_read_part (regcache, loc->regnum, loc->offset, + loc->size, *buf); + if (ret != REG_VALID) + return ret; + *buf += loc->size; + } + + return ret; +} + +/* Write multiple register parts of the register cache from a buffer. */ + +static void +mips_regcache_raw_write_parts (struct regcache *regcache, + struct mips_reg_part *loc, + unsigned int parts, + const gdb_byte **buf) +{ + for (; parts; --parts, ++loc) + { + regcache_raw_write_part (regcache, loc->regnum, loc->offset, loc->size, + *buf); + *buf += loc->size; + } +} + /* Map the symbol table registers which live in the range [1 * gdbarch_num_regs .. 2 * gdbarch_num_regs) back onto the corresponding raw registers. Take care of alignment and size problems. */ @@ -798,12 +977,27 @@ mips_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, gdb_byte *buf) { int rawnum = cookednum % gdbarch_num_regs (gdbarch); + int fpnum; + int raw_len, cooked_len; + gdb_assert (cookednum >= gdbarch_num_regs (gdbarch) && cookednum < 2 * gdbarch_num_regs (gdbarch)); - if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum)) + + raw_len = register_size (gdbarch, rawnum); + cooked_len = register_size (gdbarch, cookednum); + + if (mips_float_register_p (gdbarch, rawnum)) + { + struct mips_reg_part loc[2]; + unsigned int parts; + + fpnum = rawnum - mips_regnum (gdbarch)->fp0; + parts = mips_get_fp_multi_location (gdbarch, fpnum, cooked_len, loc); + return mips_regcache_raw_read_parts (regcache, loc, parts, &buf); + } + else if (raw_len == cooked_len) return regcache_raw_read (regcache, rawnum, buf); - else if (register_size (gdbarch, rawnum) > - register_size (gdbarch, cookednum)) + else if (raw_len > cooked_len) { if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p) return regcache_raw_read_part (regcache, rawnum, 0, 4, buf); @@ -829,12 +1023,27 @@ mips_pseudo_register_write (struct gdbarch *gdbarch, const gdb_byte *buf) { int rawnum = cookednum % gdbarch_num_regs (gdbarch); + int fpnum; + int raw_len, cooked_len; + gdb_assert (cookednum >= gdbarch_num_regs (gdbarch) && cookednum < 2 * gdbarch_num_regs (gdbarch)); - if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum)) + + raw_len = register_size (gdbarch, rawnum); + cooked_len = register_size (gdbarch, cookednum); + + if (mips_float_register_p (gdbarch, rawnum)) + { + struct mips_reg_part loc[2]; + unsigned int parts; + + fpnum = rawnum - mips_regnum (gdbarch)->fp0; + parts = mips_get_fp_multi_location (gdbarch, fpnum, cooked_len, loc); + mips_regcache_raw_write_parts (regcache, loc, parts, &buf); + } + else if (raw_len == cooked_len) regcache_raw_write (regcache, rawnum, buf); - else if (register_size (gdbarch, rawnum) > - register_size (gdbarch, cookednum)) + else if (raw_len > cooked_len) { if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p) regcache_raw_write_part (regcache, rawnum, 0, 4, buf); @@ -927,18 +1136,17 @@ set_mips64_transfers_32bit_regs (char *args, int from_tty, /* Convert to/from a register and the corresponding memory value. */ -/* This predicate tests for the case of an 8 byte floating point - value that is being transferred to or from a pair of floating point - registers each of which are (or are considered to be) only 4 bytes - wide. */ +/* This predicate tests for the case of a 4 byte floating point + value that is being transferred to or from a floating point + register which is 8 bytes wide. */ + static int mips_convert_register_float_case_p (struct gdbarch *gdbarch, int regnum, struct type *type) { - return (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG - && register_size (gdbarch, regnum) == 4 + return (register_size (gdbarch, regnum) == 8 && mips_float_register_p (gdbarch, regnum) - && TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8); + && TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 4); } /* This predicate tests for the case of a value of less than 8 @@ -972,16 +1180,19 @@ mips_register_to_value (struct frame_info *frame, int regnum, if (mips_convert_register_float_case_p (gdbarch, regnum, type)) { - get_frame_register (frame, regnum + 0, to + 4); - get_frame_register (frame, regnum + 1, to + 0); - - if (!get_frame_register_bytes (frame, regnum + 0, 0, 4, to + 4, - optimizedp, unavailablep)) - return 0; - - if (!get_frame_register_bytes (frame, regnum + 1, 0, 4, to + 0, - optimizedp, unavailablep)) - return 0; + /* single comes from low half of 64-bit register */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + { + if (!get_frame_register_bytes (frame, regnum, 4, 4, to, + optimizedp, unavailablep)) + return 0; + } + else + { + if (!get_frame_register_bytes (frame, regnum, 0, 4, to, + optimizedp, unavailablep)) + return 0; + } *optimizedp = *unavailablep = 0; return 1; } @@ -1024,6 +1235,101 @@ mips_config5_type (struct gdbarch *gdbarch) return tdep->config5_type; } +/* Get 32-bit only floating point type, which can be interpreted as either a + single precision float or a 32-bit signed integer. + This is used for odd fp registers when FR=0. In this case there are no odd + doubles. */ + +static struct type * +mips_fp32_type (struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (tdep->fp32_type == NULL) + { + const struct builtin_type *bt = builtin_type (gdbarch); + struct type *t; + + /* The type we're building is this: + union __gdb_builtin_mips_fp32 { + float f32; + int32_t i32; + }; */ + + t = arch_composite_type (gdbarch, "__gdb_builtin_type_mips_fp32", + TYPE_CODE_UNION); + append_composite_type_field (t, "f32", bt->builtin_float); + append_composite_type_field (t, "i32", bt->builtin_int32); + + TYPE_NAME (t) = "fp32"; + tdep->fp32_type = t; + } + + return tdep->fp32_type; +} + +/* Get general floating point type, which can be interpreted as either a + single or double precision float, or a 32-bit or 64-bit signed integer. + This is used for even fp registers when FR=0 (doubles are constructed from + even/odd pairs of fp registers so only even registers can be interpreted as + double precision flaots) and for all fp registers when FR=1. */ + +static struct type * +mips_fp64_type (struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (tdep->fp64_type == NULL) + { + const struct builtin_type *bt = builtin_type (gdbarch); + int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG); + struct type *t; + struct field *f; + + /* The type we're building is roughly this (little endian): + + union __gdb_builtin_mips_fp64 { + float f32; + double f64; + int32 i32; + int64 i64; + }; */ + + t = arch_composite_type (gdbarch, "__gdb_builtin_type_mips_fp64", + TYPE_CODE_UNION); + f = append_composite_type_field_raw (t, "f32", bt->builtin_float); + SET_FIELD_BITPOS (*f, 32*big_endian); + f = append_composite_type_field_raw (t, "f64", bt->builtin_double); + SET_FIELD_BITPOS (*f, 0); + f = append_composite_type_field_raw (t, "i32", bt->builtin_int32); + SET_FIELD_BITPOS (*f, 32*big_endian); + f = append_composite_type_field_raw (t, "i64", bt->builtin_int64); + SET_FIELD_BITPOS (*f, 0); + + TYPE_LENGTH (t) = 8; + TYPE_NAME (t) = "fp64"; + tdep->fp64_type = t; + } + + return tdep->fp64_type; +} + +/* Get the floating point type for an arbitrary FP register. This returns the + appropriate type depending on the possible types and overlaps of the + register. */ + +static struct type * +mips_fp_type (struct gdbarch *gdbarch, int fpnum) +{ + if ((fpnum & 1) == 0 || mips_float_regsize (gdbarch) == 8) + /* Even singles and doubles always overlap, as do odd singles and + doubles when FR=1. */ + return mips_fp64_type (gdbarch); + else + /* 32-bit odd singles (there are no odd doubles). */ + return mips_fp32_type (gdbarch); +} + static void mips_value_to_register (struct frame_info *frame, int regnum, struct type *type, const gdb_byte *from) @@ -1032,8 +1338,11 @@ mips_value_to_register (struct frame_info *frame, int regnum, if (mips_convert_register_float_case_p (gdbarch, regnum, type)) { - put_frame_register (frame, regnum + 0, from + 4); - put_frame_register (frame, regnum + 1, from + 0); + /* single goes in low half of 64-bit register */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + put_frame_register_bytes (frame, regnum, 4, 4, from); + else + put_frame_register_bytes (frame, regnum, 0, 4, from); } else if (mips_convert_register_gpreg_case_p (gdbarch, regnum, type)) { @@ -1105,9 +1414,7 @@ mips_register_type (struct gdbarch *gdbarch, int regnum) either 64-bit or 32-bit via the CP0 Status register's FR bit. Use the current setting for cooked registers. */ if (mips_float_register_p (gdbarch, regnum)) - return (mips_float_regsize (gdbarch) == 4 - ? builtin_type (gdbarch)->builtin_float - : builtin_type (gdbarch)->builtin_double); + return mips_fp_type (gdbarch, rawnum - mips_regnum (gdbarch)->fp0); else if (rawnum == mips_regnum (gdbarch)->fp_control_status || rawnum == mips_regnum (gdbarch)->fp_implementation_revision) return builtin_type (gdbarch)->builtin_int32; @@ -1145,7 +1452,7 @@ mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum) { const int num_regs = gdbarch_num_regs (gdbarch); int rawnum = regnum % num_regs; - struct type *rawtype; + struct type *rawtype, *fp_rawtype; gdb_assert (regnum >= num_regs && regnum < 2 * num_regs); @@ -1159,7 +1466,7 @@ mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum) not try to convert between FPU layouts. A target description is expected to have taken the CP0 Status register's FR bit into account as necessary, this has been already verified in mips_gdbarch_init. */ - return rawtype; + return mips_fp_type (gdbarch, rawnum - mips_regnum (gdbarch)->fp0); /* Use pointer types for registers if we can. For n32 we can not, since we do not have a 64-bit pointer type. */ @@ -6266,79 +6573,60 @@ mips_o64_return_value (struct gdbarch *gdbarch, struct value *function, and below). */ /* Copy a 32-bit single-precision value from the current frame - into rare_buffer. */ + into rare_buffer. This is done by reading the pseudo register and extracting + the relevant part so as not to duplicate code. + Returns 0 on failure. */ -static void +static int mips_read_fp_register_single (struct frame_info *frame, int regno, gdb_byte *rare_buffer) { struct gdbarch *gdbarch = get_frame_arch (frame); - int fpsize = register_size (gdbarch, regno); - gdb_byte *raw_buffer = alloca (fpsize); + int cooked_size = register_size (gdbarch, regno); + gdb_byte *raw_buffer = alloca (cooked_size); + int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG); - if (!deprecated_frame_register_read (frame, regno, raw_buffer)) - error (_("can't read register %d (%s)"), - regno, gdbarch_register_name (gdbarch, regno)); - if (fpsize == 8) - { - /* We have a 64-bit value for this register. Find the low-order - 32 bits. */ - int offset; + if (cooked_size < 4) + return 0; - if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) - offset = 4; - else - offset = 0; + if (cooked_size == 4) + /* FR=0 odd */ + return deprecated_frame_register_read (frame, regno, rare_buffer); - memcpy (rare_buffer, raw_buffer + offset, 4); - } + if (!deprecated_frame_register_read (frame, regno, raw_buffer)) + return 0; + + if (cooked_size == 8) + /* FR=1 + Single is overlapping double. */ + memcpy(rare_buffer, raw_buffer + 4*big_endian, 4); else - { - memcpy (rare_buffer, raw_buffer, 4); - } + return 0; + return 1; } /* Copy a 64-bit double-precision value from the current frame into - rare_buffer. This may include getting half of it from the next - register. */ + rare_buffer. This is done by reading the pseudo register and extracting the + relevant part so as not to duplicate code. + Returns 0 on failure. */ -static void +static int mips_read_fp_register_double (struct frame_info *frame, int regno, gdb_byte *rare_buffer) { struct gdbarch *gdbarch = get_frame_arch (frame); - int fpsize = register_size (gdbarch, regno); + int cooked_size = register_size (gdbarch, regno); + gdb_byte *raw_buffer = alloca (cooked_size); - if (fpsize == 8) - { - /* We have a 64-bit value for this register, and we should use - all 64 bits. */ - if (!deprecated_frame_register_read (frame, regno, rare_buffer)) - error (_("can't read register %d (%s)"), - regno, gdbarch_register_name (gdbarch, regno)); - } - else - { - int rawnum = regno % gdbarch_num_regs (gdbarch); + if (cooked_size < 8) + /* FR=0 odd */ + return 0; - if ((rawnum - mips_regnum (gdbarch)->fp0) & 1) - internal_error (__FILE__, __LINE__, - _("mips_read_fp_register_double: bad access to " - "odd-numbered FP register")); + if (!deprecated_frame_register_read (frame, regno, raw_buffer)) + return 0; - /* mips_read_fp_register_single will find the correct 32 bits from - each register. */ - if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) - { - mips_read_fp_register_single (frame, regno, rare_buffer + 4); - mips_read_fp_register_single (frame, regno + 1, rare_buffer); - } - else - { - mips_read_fp_register_single (frame, regno, rare_buffer); - mips_read_fp_register_single (frame, regno + 1, rare_buffer + 4); - } - } + memcpy(rare_buffer, raw_buffer, 8); + return 1; } static void @@ -6349,7 +6637,7 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame, int fpsize = register_size (gdbarch, regnum); gdb_byte *raw_buffer; double doub, flt1; /* Doubles extracted from raw hex data. */ - int inv1, inv2; + int res1, res2, inv1, inv2; raw_buffer = alloca (2 * fpsize); @@ -6364,29 +6652,39 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame, /* 4-byte registers: Print hex and floating. Also print even numbered registers as doubles. */ - mips_read_fp_register_single (frame, regnum, raw_buffer); - flt1 = unpack_double (builtin_type (gdbarch)->builtin_float, - raw_buffer, &inv1); + res1 = mips_read_fp_register_single (frame, regnum, raw_buffer); + if (res1) + { + flt1 = unpack_double (builtin_type (gdbarch)->builtin_float, + raw_buffer, &inv1); - get_formatted_print_options (&opts, 'x'); - print_scalar_formatted (raw_buffer, - builtin_type (gdbarch)->builtin_uint32, - &opts, 'w', file); + get_formatted_print_options (&opts, 'x'); + print_scalar_formatted (raw_buffer, + builtin_type (gdbarch)->builtin_uint32, + &opts, 'w', file); + } + else + fprintf_filtered (file, "0x????????"); fprintf_filtered (file, " flt: "); - if (inv1) + if (!res1) + fprintf_filtered (file, " "); + else if (inv1) fprintf_filtered (file, " "); else fprintf_filtered (file, "%-17.9g", flt1); if ((regnum - gdbarch_num_regs (gdbarch)) % 2 == 0) { - mips_read_fp_register_double (frame, regnum, raw_buffer); - doub = unpack_double (builtin_type (gdbarch)->builtin_double, - raw_buffer, &inv2); + res2 = mips_read_fp_register_double (frame, regnum, raw_buffer); + if (res2) + doub = unpack_double (builtin_type (gdbarch)->builtin_double, + raw_buffer, &inv2); fprintf_filtered (file, " dbl: "); - if (inv2) + if (!res2) + fprintf_filtered (file, ""); + else if (inv2) fprintf_filtered (file, ""); else fprintf_filtered (file, "%-24.17g", doub); @@ -6395,29 +6693,48 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame, else { struct value_print_options opts; + int no_odd; + + /* if top half isn't provided we can't access odd floats or doubles */ + if ((regnum - gdbarch_num_regs (gdbarch)) & 1 && + register_size (gdbarch, regnum % gdbarch_num_regs (gdbarch)) < 8) + { + fprintf_filtered (file, ""); + return; + } /* Eight byte registers: print each one as hex, float and double. */ - mips_read_fp_register_single (frame, regnum, raw_buffer); - flt1 = unpack_double (builtin_type (gdbarch)->builtin_float, - raw_buffer, &inv1); + res1 = mips_read_fp_register_single (frame, regnum, raw_buffer); + if (res1) + flt1 = unpack_double (builtin_type (gdbarch)->builtin_float, + raw_buffer, &inv1); - mips_read_fp_register_double (frame, regnum, raw_buffer); - doub = unpack_double (builtin_type (gdbarch)->builtin_double, - raw_buffer, &inv2); + res2 = mips_read_fp_register_double (frame, regnum, raw_buffer); + if (res2) + { + doub = unpack_double (builtin_type (gdbarch)->builtin_double, + raw_buffer, &inv2); - get_formatted_print_options (&opts, 'x'); - print_scalar_formatted (raw_buffer, - builtin_type (gdbarch)->builtin_uint64, - &opts, 'g', file); + get_formatted_print_options (&opts, 'x'); + print_scalar_formatted (raw_buffer, + builtin_type (gdbarch)->builtin_uint64, + &opts, 'g', file); + } + else + fprintf_filtered (file, "0x????????????????"); fprintf_filtered (file, " flt: "); - if (inv1) - fprintf_filtered (file, ""); + if (!res1) + fprintf_filtered (file, " "); + else if (inv1) + fprintf_filtered (file, " "); else fprintf_filtered (file, "%-17.9g", flt1); fprintf_filtered (file, " dbl: "); - if (inv2) + if (!res2) + fprintf_filtered (file, " "); + else if (inv2) fprintf_filtered (file, ""); else fprintf_filtered (file, "%-24.17g", doub); @@ -8716,6 +9033,8 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->fp_mode = ((struct gdbarch_tdep_info*)(info.tdep_info))->fp_mode; tdep->fp_register_mode_fixed_p = 0; tdep->config5_type = NULL; + tdep->fp32_type = NULL; + tdep->fp64_type = NULL; if (info.target_desc) { diff --git a/gdb/mips-tdep.h b/gdb/mips-tdep.h index b6f99f2..11353be 100644 --- a/gdb/mips-tdep.h +++ b/gdb/mips-tdep.h @@ -130,6 +130,8 @@ struct gdbarch_tdep /* ISA-specific data types. */ struct type *config5_type; + struct type *fp32_type; + struct type *fp64_type; /* Return the expected next PC if FRAME is stopped at a syscall instruction. */