From patchwork Mon Jun 27 14:49:28 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bhushan Attarde X-Patchwork-Id: 13382 Received: (qmail 7784 invoked by alias); 27 Jun 2016 14:50:15 -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 7769 invoked by uid 89); 27 Jun 2016 14:50:14 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=3.9 required=5.0 tests=AWL, BAYES_50, GARBLED_SUBJECT, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, SPF_PASS autolearn=no version=3.3.2 spammy=drow, Wire, sr, stephens 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:03 +0000 Received: from hhmail02.hh.imgtec.org (unknown [10.100.10.20]) by Forcepoint Email with ESMTPS id 6F276BEEAF78A for ; Mon, 27 Jun 2016 15:49:56 +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:49:59 +0100 From: Bhushan Attarde To: CC: , , , , , Bhushan Attarde Subject: [PATCH 01/24] MIPS: Handle run-time reconfigurable FPR size Date: Mon, 27 Jun 2016 20:19:28 +0530 Message-ID: <1467038991-6600-1-git-send-email-bhushan.attarde@imgtec.com> MIME-Version: 1.0 Many MIPS architecture processors can reconfigure the size of their floating-point registers at the run time. The file comprising 32 registers can be either 32-bit or 64-bit wide depending on whether CP0 Status register's bit FR is zero or one, respectively. Fortunately access to Status is available on all targets. Here's a change to handle this property. It requires the generic register access code to raise the target backend's attention whenever a new register set has been retrieved so that it can examine the state of CP0.Status.FR and act accordingly. I have added this hook to get_thread_regcache, the backend has then an opportunity to switch gdbarch as necessary and let the caller know if it did so. If that indeed happened, then the register cache originally retrieved is then discarded and another one obtained using the newly-selected gdbarch. This new register cache is not revalidated. This has been regression-tested successfully, using o32 and n64 multilibs on mips-sde-elf and mips-linux-gnu targets. The ability to flip CP0.Status.FR is not however covered by any test suite, and was therefore tested manually. An example session with a bare-iron MIPS64 target looks like this (I've stripped out some noise): (gdb) info all-registers zero at v0 v1 R0 0000000000000000 0000000000000000 0000000000000000 0000000020000000 a0 a1 a2 a3 R4 0000000000000000 0000000000000000 0000000000000000 0000000000000000 a4 a5 a6 a7 R8 0000000000000000 0000000000000000 0000000000000000 0000000000000000 t0 t1 t2 t3 R12 0000000000000000 0000000000000000 0000000000000000 0000000000000000 s0 s1 s2 s3 R16 0000000000000000 0000000000000000 0000000000000000 0000000000000000 s4 s5 s6 s7 R20 0000000000000000 0000000000000000 0000000000000000 0000000000000000 t8 t9 k0 k1 R24 0000000000000000 0000000000000000 0000000000000000 0000000000000000 gp sp s8 ra R28 0000000000000000 0000000000000000 0000000000000000 0000000000000000 sr lo hi bad 0000000024000000 0000000000000000 0000000000000000 0000000000000000 cause pc 0000000000000000 ffffffff80000000 f0: 0x0000000000000000 flt: 0 dbl: 0 f1: 0x000000003f800000 flt: 1 dbl: 5.2635442471208903e-315 f2: 0x0000000000000000 flt: 0 dbl: 0 f3: 0x0000000040000000 flt: 2 dbl: 5.3049894774131808e-315 f4: 0x0000000000000000 flt: 0 dbl: 0 f5: 0x0000000040400000 flt: 3 dbl: 5.325712092559326e-315 f6: 0x0000000000000000 flt: 0 dbl: 0 f7: 0x0000000040800000 flt: 4 dbl: 5.3464347077054713e-315 f8: 0x0000000000000000 flt: 0 dbl: 0 f9: 0x0000000040a00000 flt: 5 dbl: 5.3567960152785439e-315 f10: 0x0000000000000000 flt: 0 dbl: 0 f11: 0x0000000040c00000 flt: 6 dbl: 5.3671573228516165e-315 f12: 0x0000000000000000 flt: 0 dbl: 0 f13: 0x0000000040e00000 flt: 7 dbl: 5.3775186304246891e-315 f14: 0x0000000000000000 flt: 0 dbl: 0 f15: 0x0000000041000000 flt: 8 dbl: 5.3878799379977617e-315 f16: 0x0000000000000000 flt: 0 dbl: 0 f17: 0x0000000041100000 flt: 9 dbl: 5.393060591784298e-315 f18: 0x0000000000000000 flt: 0 dbl: 0 f19: 0x0000000041200000 flt: 10 dbl: 5.3982412455708344e-315 f20: 0x0000000000000000 flt: 0 dbl: 0 f21: 0x0000000041300000 flt: 11 dbl: 5.4034218993573707e-315 f22: 0x0000000000000000 flt: 0 dbl: 0 f23: 0x0000000041400000 flt: 12 dbl: 5.408602553143907e-315 f24: 0x0000000000000000 flt: 0 dbl: 0 f25: 0x0000000041500000 flt: 13 dbl: 5.4137832069304433e-315 f26: 0x0000000000000000 flt: 0 dbl: 0 f27: 0x0000000041600000 flt: 14 dbl: 5.4189638607169796e-315 f28: 0x0000000000000000 flt: 0 dbl: 0 f29: 0x0000000041700000 flt: 15 dbl: 5.4241445145035159e-315 f30: 0x0000000000000000 flt: 0 dbl: 0 f31: 0x0000000041800000 flt: 16 dbl: 5.4293251682900522e-315 fsr fir 00000000 00738900 (gdb) x /i $pc => 0xffffffff80000000: mtc0 v1,c0_status (gdb) stepi 0xffffffff80000004 in ?? () (gdb) info all-registers zero at v0 v1 R0 0000000000000000 0000000000000000 0000000000000000 0000000020000000 a0 a1 a2 a3 R4 0000000000000000 0000000000000000 0000000000000000 0000000000000000 a4 a5 a6 a7 R8 0000000000000000 0000000000000000 0000000000000000 0000000000000000 t0 t1 t2 t3 R12 0000000000000000 0000000000000000 0000000000000000 0000000000000000 s0 s1 s2 s3 R16 0000000000000000 0000000000000000 0000000000000000 0000000000000000 s4 s5 s6 s7 R20 0000000000000000 0000000000000000 0000000000000000 0000000000000000 t8 t9 k0 k1 R24 0000000000000000 0000000000000000 0000000000000000 0000000000000000 gp sp s8 ra R28 0000000000000000 0000000000000000 0000000000000000 0000000000000000 sr lo hi bad 0000000020000000 0000000000000000 0000000000000000 0000000000000000 cause pc 0000000000000000 ffffffff80000004 f0: 0x00000000 flt: 0 dbl: 0.0078125 f1: 0x3f800000 flt: 1 f2: 0x00000000 flt: 0 dbl: 2 f3: 0x40000000 flt: 2 f4: 0x00000000 flt: 0 dbl: 32 f5: 0x40400000 flt: 3 f6: 0x00000000 flt: 0 dbl: 512 f7: 0x40800000 flt: 4 f8: 0x00000000 flt: 0 dbl: 2048 f9: 0x40a00000 flt: 5 f10: 0x00000000 flt: 0 dbl: 8192 f11: 0x40c00000 flt: 6 f12: 0x00000000 flt: 0 dbl: 32768 f13: 0x40e00000 flt: 7 f14: 0x00000000 flt: 0 dbl: 131072 f15: 0x41000000 flt: 8 f16: 0x00000000 flt: 0 dbl: 262144 f17: 0x41100000 flt: 9 f18: 0x00000000 flt: 0 dbl: 524288 f19: 0x41200000 flt: 10 f20: 0x00000000 flt: 0 dbl: 1048576 f21: 0x41300000 flt: 11 f22: 0x00000000 flt: 0 dbl: 2097152 f23: 0x41400000 flt: 12 f24: 0x00000000 flt: 0 dbl: 4194304 f25: 0x41500000 flt: 13 f26: 0x00000000 flt: 0 dbl: 8388608 f27: 0x41600000 flt: 14 f28: 0x00000000 flt: 0 dbl: 16777216 f29: 0x41700000 flt: 15 f30: 0x00000000 flt: 0 dbl: 33554432 f31: 0x41800000 flt: 16 fsr fir 00000000 00738900 (gdb) set $sr ^= 1 << 26 (gdb) info all-registers zero at v0 v1 R0 0000000000000000 0000000000000000 0000000000000000 0000000020000000 a0 a1 a2 a3 R4 0000000000000000 0000000000000000 0000000000000000 0000000000000000 a4 a5 a6 a7 R8 0000000000000000 0000000000000000 0000000000000000 0000000000000000 t0 t1 t2 t3 R12 0000000000000000 0000000000000000 0000000000000000 0000000000000000 s0 s1 s2 s3 R16 0000000000000000 0000000000000000 0000000000000000 0000000000000000 s4 s5 s6 s7 R20 0000000000000000 0000000000000000 0000000000000000 0000000000000000 t8 t9 k0 k1 R24 0000000000000000 0000000000000000 0000000000000000 0000000000000000 gp sp s8 ra R28 0000000000000000 0000000000000000 0000000000000000 0000000000000000 sr lo hi bad 0000000024000000 0000000000000000 0000000000000000 0000000000000000 cause pc 0000000000000000 ffffffff80000004 f0: 0x0000000000000000 flt: 0 dbl: 0 f1: 0x000000003f800000 flt: 1 dbl: 5.2635442471208903e-315 f2: 0x0000000000000000 flt: 0 dbl: 0 f3: 0x0000000040000000 flt: 2 dbl: 5.3049894774131808e-315 f4: 0x0000000000000000 flt: 0 dbl: 0 f5: 0x0000000040400000 flt: 3 dbl: 5.325712092559326e-315 f6: 0x0000000000000000 flt: 0 dbl: 0 f7: 0x0000000040800000 flt: 4 dbl: 5.3464347077054713e-315 f8: 0x0000000000000000 flt: 0 dbl: 0 f9: 0x0000000040a00000 flt: 5 dbl: 5.3567960152785439e-315 f10: 0x0000000000000000 flt: 0 dbl: 0 f11: 0x0000000040c00000 flt: 6 dbl: 5.3671573228516165e-315 f12: 0x0000000000000000 flt: 0 dbl: 0 f13: 0x0000000040e00000 flt: 7 dbl: 5.3775186304246891e-315 f14: 0x0000000000000000 flt: 0 dbl: 0 f15: 0x0000000041000000 flt: 8 dbl: 5.3878799379977617e-315 f16: 0x0000000000000000 flt: 0 dbl: 0 f17: 0x0000000041100000 flt: 9 dbl: 5.393060591784298e-315 f18: 0x0000000000000000 flt: 0 dbl: 0 f19: 0x0000000041200000 flt: 10 dbl: 5.3982412455708344e-315 f20: 0x0000000000000000 flt: 0 dbl: 0 f21: 0x0000000041300000 flt: 11 dbl: 5.4034218993573707e-315 f22: 0x0000000000000000 flt: 0 dbl: 0 f23: 0x0000000041400000 flt: 12 dbl: 5.408602553143907e-315 f24: 0x0000000000000000 flt: 0 dbl: 0 f25: 0x0000000041500000 flt: 13 dbl: 5.4137832069304433e-315 f26: 0x0000000000000000 flt: 0 dbl: 0 f27: 0x0000000041600000 flt: 14 dbl: 5.4189638607169796e-315 f28: 0x0000000000000000 flt: 0 dbl: 0 f29: 0x0000000041700000 flt: 15 dbl: 5.4241445145035159e-315 f30: 0x0000000000000000 flt: 0 dbl: 0 f31: 0x0000000041800000 flt: 16 dbl: 5.4293251682900522e-315 fsr fir 00000000 00738900 (gdb) This is implemented by retaining the raw register size for the FPRs at its native size (64-bits; this is required for remote packet offsets to work out correctly) and then truncating the cooked register size or not as required. I have skipped `maintenance print registers' dumps here for brevity, the types flip between "double" and "float" as expected. This change supports bare-iron, Linux and IRIX targets. For Linux and IRIX the width of the floating-point registers is set by the ABI of the program being run by the OS kernel and the kernel is responsible for setting CP0.Status.FR correctly; the image of Status accessible via ptrace(2) is read-only. Therefore the respective backends mark the width as fixed and cause the run-time check to be skipped for efficiency. I have verified that the Linux target does that correctly; the change for IRIX is the same and is expected to be all right, but I have no access to such a system (I will appreciate anyone verifying that). The change currently supports 64-bit processors only as GDB has no way to access upper halves of floating-point registers on 32-bit processors that have a 64-bit FPU (i.e. MIPS32r2 and newer processors); this is mentioned in the explanatory notes included with the change itself. The change also supports both XML and non-XML targets, but currently bare-iron targets for which this update has any significant meaning do not really support XML. Any XML target is supposed to always provide an FPU description that matches the current setting of CP0.Status.FR, the new code verifies this is always the case and rejects the description as invalid otherwise. Generic parts require a general maintainer's approval, would whoever finds themselves most familiar with regcache internals please have a look at these bits? Thanks. This addresses the CP0.Status.FR part of PR gdb/7518 (former GNATS PR gdb/413) and is based on work started by Nigel and David (neither at MIPS Technologies anymore). 2012-06-06 Maciej W. Rozycki Nigel Stephens David Ung PR gdb/7518 gdb/ * gdbarch.sh (regcache_changed): New function. * regcache.c (set_current_thread_ptid_arch): New function, factored out from... (get_thread_regcache): ... here. Call gdbarch_regcache_changed as necessary. * mips-tdep.h (gdbarch_tdep): Add fp_register_size_fixed_p and fp_register_size members. (gdbarch_tdep_info): New structure. * mips-tdep.c (mips_register_type): Remove forward declaration. (mips_set_float_regsize, mips_float_regsize): New functions. (mips2_fp_compat): Remove function. (mips_register_type): Use mips_float_regsize to handle cooked floating-point registers. Fold floating-point cases into common code. (mips_pseudo_register_type): Update comment on floating-point registers. (mips_read_fp_register_single): Rename raw_size local variable to fpsize. (mips_read_fp_register_double): Likewise. Remove call to mips2_fp_compat. (mips_print_fp_register): Check the size of the register requested rather than $f0 and use fpsize local variable to hold it. Remove call to mips2_fp_compat. (mips_print_float_info): Use mips_float_regsize. (mips_gdbarch_init): Use a proper tdep_info structure. Match gdbarch against fp_register_size requested if any. Initialize fp_register_size and fp_register_size_fixed_p in gdbarch target data. Install mips_set_float_regsize as gdbarch regcache_changed routine. * mips-irix-tdep.c (mips_irix_init_abi): Set fp_register_size_fixed_p in gdbarch target data. * mips-linux-tdep.c (mips_linux_init_abi): Likewise. Adjust for tdep_info update. * gdbarch.h: Regenerate. * gdbarch.c: Regenerate. --- gdb/gdbarch.c | 32 +++++++++ gdb/gdbarch.h | 11 +++ gdb/gdbarch.sh | 5 ++ gdb/mips-linux-tdep.c | 7 +- gdb/mips-tdep.c | 194 +++++++++++++++++++++++++++++++++++--------------- gdb/mips-tdep.h | 16 +++++ gdb/regcache.c | 25 ++++++- 7 files changed, 227 insertions(+), 63 deletions(-) diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 4143744..0673fc1 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -199,6 +199,7 @@ struct gdbarch gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum; gdbarch_register_name_ftype *register_name; gdbarch_register_type_ftype *register_type; + gdbarch_regcache_changed_ftype *regcache_changed; gdbarch_dummy_id_ftype *dummy_id; int deprecated_fp_regnum; gdbarch_push_dummy_call_ftype *push_dummy_call; @@ -543,6 +544,7 @@ verify_gdbarch (struct gdbarch *gdbarch) if (gdbarch->register_name == 0) fprintf_unfiltered (log, "\n\tregister_name"); /* Skip verify of register_type, has predicate. */ + /* Skip verify of regcache_changed, has predicate. */ /* Skip verify of dummy_id, has predicate. */ /* Skip verify of deprecated_fp_regnum, invalid_p == 0 */ /* Skip verify of push_dummy_call, has predicate. */ @@ -1225,6 +1227,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: record_special_symbol = <%s>\n", host_address_to_string (gdbarch->record_special_symbol)); fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_regcache_changed_p() = %d\n", + gdbarch_regcache_changed_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: regcache_changed = <%s>\n", + host_address_to_string (gdbarch->regcache_changed)); + fprintf_unfiltered (file, "gdbarch_dump: register_name = <%s>\n", host_address_to_string (gdbarch->register_name)); fprintf_unfiltered (file, @@ -2171,6 +2179,30 @@ set_gdbarch_register_type (struct gdbarch *gdbarch, } int +gdbarch_regcache_changed_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->regcache_changed != NULL; +} + +int +gdbarch_regcache_changed (struct gdbarch *gdbarch, struct regcache *regcache) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->regcache_changed != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_regcache_changed called\n"); + return gdbarch->regcache_changed (gdbarch, regcache); +} + +void +set_gdbarch_regcache_changed (struct gdbarch *gdbarch, + gdbarch_regcache_changed_ftype regcache_changed) +{ + gdbarch->regcache_changed = regcache_changed; +} + +int gdbarch_dummy_id_p (struct gdbarch *gdbarch) { gdb_assert (gdbarch != NULL); diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 3fadcd1..22b02a3 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -356,6 +356,17 @@ typedef struct type * (gdbarch_register_type_ftype) (struct gdbarch *gdbarch, in extern struct type * gdbarch_register_type (struct gdbarch *gdbarch, int reg_nr); extern void set_gdbarch_register_type (struct gdbarch *gdbarch, gdbarch_register_type_ftype *register_type); +/* Notify the architecture that the registers have changed and we now have + a new regcache to examine. Return one if a new architecture has been + selected that changed the layout of the regcache and it has to be + discarded and a new one initialised, zero otherwise. */ + +extern int gdbarch_regcache_changed_p (struct gdbarch *gdbarch); + +typedef int (gdbarch_regcache_changed_ftype) (struct gdbarch *gdbarch, struct regcache *regcache); +extern int gdbarch_regcache_changed (struct gdbarch *gdbarch, struct regcache *regcache); +extern void set_gdbarch_regcache_changed (struct gdbarch *gdbarch, gdbarch_regcache_changed_ftype *regcache_changed); + extern int gdbarch_dummy_id_p (struct gdbarch *gdbarch); typedef struct frame_id (gdbarch_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *this_frame); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 4ac6b90..2c09371 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -469,6 +469,11 @@ m:const char *:register_name:int regnr:regnr::0 # the register cache should call this function directly; others should # use "register_type". M:struct type *:register_type:int reg_nr:reg_nr +# Notify the architecture that the registers have changed and we now have +# a new regcache to examine. Return one if a new architecture has been +# selected that changed the layout of the regcache and it has to be +# discarded and a new one initialised, zero otherwise. +M:int:regcache_changed:struct regcache *regcache:regcache M:struct frame_id:dummy_id:struct frame_info *this_frame:this_frame # Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 8dc0566..6b9743b 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -1737,8 +1737,9 @@ mips_linux_init_abi (struct gdbarch_info info, mips_gdb_signal_to_target); tdep->syscall_next_pc = mips_linux_syscall_next_pc; + tdep->fp_register_size_fixed_p = 1; - if (tdesc_data) + if (((struct gdbarch_tdep_info*)(info.tdep_info))->tdesc_data) { const struct tdesc_feature *feature; @@ -1753,8 +1754,8 @@ mips_linux_init_abi (struct gdbarch_info info, feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.mips.linux"); if (feature != NULL) - tdesc_numbered_register (feature, tdesc_data, MIPS_RESTART_REGNUM, - "restart"); + tdesc_numbered_register (feature, (((struct gdbarch_tdep_info*)(info.tdep_info))->tdesc_data), + MIPS_RESTART_REGNUM, "restart"); } } diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 63c1560..ae4dc2e 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -58,8 +58,6 @@ static const struct objfile_data *mips_pdr_data; -static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum); - static int mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, ULONGEST inst); static int micromips_instruction_has_delay_slot (ULONGEST insn, int mustbe32); @@ -274,6 +272,77 @@ mips_abi_regsize (struct gdbarch *gdbarch) } } +/* Determine the current floating-point register size and update our + architecture data accordingly. Return one if the size has changed + and a new architecture has been selected, zero otherwise. + + For MIPS1, MIPS2 and MIPS32 rev. 1 processors the size is hardwired + to 32 bits. For MIPS3 and other 64-bit processors up to the MIPS64 + rev. 1 ISA the size is determined by the CP0 Status register's bit + FR. If this bit is 1, then the size is 64 bits. If it is 0, then + the FPU operates in the compatibility mode and the size is 32 bits. + + From MIPS32 and MIPS64 rev. 2 ISAs up the size is implementation + specific and reported by the CP1 FIR register's bit F64. If this + bit is 0, then the size is hardwired to 32 bits. If this bit is 1, + then the size is determined by the CP0 Status register's bit FR as + described above. Unfortunately we may not have access to the CP0 + registers needed to determine whether the ISA implemented is MIPS32 + or MIPS64 rev. 2 or higher. + + We currently cannot handle the 64-bit floating-point register size + on MIPS32 rev. 2 and higher ISA processors though as no target + provides access to upper halves of such registers. Therefore we + hardcode the size to 32 bits for any 32-bit processors. + + As the CP0 Status register's bit FR cannot be modified on processors + that do not implement an FPU, backends for operating systems that + can emulate the FPU in software should set the size according to the + ABI in use and then set fp_register_size_fixed_p to 1 to prevent + further updates. */ + +static int +mips_set_float_regsize (struct gdbarch *gdbarch, struct regcache *regcache) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct gdbarch_tdep_info tdep_info = { NULL }; + struct gdbarch_info info; + int fpsize; + + if (tdep->fp_register_size_fixed_p) + return 0; + + fpsize = mips_isa_regsize (gdbarch); + if (fpsize == 8) + { + enum register_status status; + ULONGEST sr; + + status = regcache_raw_read_unsigned (regcache, MIPS_PS_REGNUM, &sr); + if (status == REG_VALID) + fpsize = (sr & ST0_FR) ? 8 : 4; + } + + if (fpsize == tdep->fp_register_size) + return 0; + + /* Need a new gdbarch, go get one. */ + gdbarch_info_init (&info); + info.tdep_info = &tdep_info; + info.tdep_info->fp_register_size = fpsize; + gdbarch_update_p (info); + + return 1; +} + +/* Return the currently configured floating-point register size. */ + +static int +mips_float_regsize (struct gdbarch *gdbarch) +{ + return gdbarch_tdep (gdbarch)->fp_register_size; +} + /* MIPS16/microMIPS function addresses are odd (bit 0 is set). Here are some functions to handle addresses associated with compressed code including but not limited to testing, setting, or clearing @@ -504,32 +573,6 @@ mips_xfer_register (struct gdbarch *gdbarch, struct regcache *regcache, fprintf_unfiltered (gdb_stdlog, "\n"); } -/* Determine if a MIPS3 or later cpu is operating in MIPS{1,2} FPU - compatiblity mode. A return value of 1 means that we have - physical 64-bit registers, but should treat them as 32-bit registers. */ - -static int -mips2_fp_compat (struct frame_info *frame) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - /* MIPS1 and MIPS2 have only 32 bit FPRs, and the FR bit is not - meaningful. */ - if (register_size (gdbarch, mips_regnum (gdbarch)->fp0) == 4) - return 0; - -#if 0 - /* FIXME drow 2002-03-10: This is disabled until we can do it consistently, - in all the places we deal with FP registers. PR gdb/413. */ - /* Otherwise check the FR bit in the status register - it controls - the FP compatiblity mode. If it is clear we are in compatibility - mode. */ - if ((get_frame_register_unsigned (frame, MIPS_PS_REGNUM) & ST0_FR) == 0) - return 1; -#endif - - return 0; -} - #define VM_MIN_ADDRESS (CORE_ADDR)0x400000 static CORE_ADDR heuristic_proc_start (struct gdbarch *, CORE_ADDR); @@ -1005,31 +1048,36 @@ static struct type * mips_register_type (struct gdbarch *gdbarch, int regnum) { gdb_assert (regnum >= 0 && regnum < 2 * gdbarch_num_regs (gdbarch)); - if (mips_float_register_p (gdbarch, regnum)) - { - /* The floating-point registers raw, or cooked, always match - mips_isa_regsize(), and also map 1:1, byte for byte. */ - if (mips_isa_regsize (gdbarch) == 4) - return builtin_type (gdbarch)->builtin_float; - else - return builtin_type (gdbarch)->builtin_double; - } - else if (regnum < gdbarch_num_regs (gdbarch)) + if (regnum < gdbarch_num_regs (gdbarch)) { /* The raw or ISA registers. These are all sized according to the ISA regsize. */ - if (mips_isa_regsize (gdbarch) == 4) - return builtin_type (gdbarch)->builtin_int32; + int regsize = mips_isa_regsize (gdbarch); + + if (mips_float_register_p (gdbarch, regnum)) + return (regsize == 4 + ? builtin_type (gdbarch)->builtin_float + : builtin_type (gdbarch)->builtin_double); else - return builtin_type (gdbarch)->builtin_int64; + return (regsize == 4 + ? builtin_type (gdbarch)->builtin_int32 + : builtin_type (gdbarch)->builtin_int64); } else { - int rawnum = regnum - gdbarch_num_regs (gdbarch); - /* The cooked or ABI registers. These are sized according to the ABI (with a few complications). */ - if (rawnum == mips_regnum (gdbarch)->fp_control_status + int rawnum = regnum - gdbarch_num_regs (gdbarch); + + /* Floating-point registers of most 64-bit and some 32-bit MIPS + processors can be reconfigured dynamically at the run time as + 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); + else if (rawnum == mips_regnum (gdbarch)->fp_control_status || rawnum == mips_regnum (gdbarch)->fp_implementation_revision) return builtin_type (gdbarch)->builtin_int32; else if (gdbarch_osabi (gdbarch) != GDB_OSABI_IRIX @@ -1074,8 +1122,10 @@ mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum) return rawtype; if (mips_float_register_p (gdbarch, rawnum)) - /* Present the floating point registers however the hardware did; - do not try to convert between FPU layouts. */ + /* Present the floating point registers however the hardware did; do + 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; /* Use pointer types for registers if we can. For n32 we can not, @@ -6187,13 +6237,13 @@ mips_read_fp_register_single (struct frame_info *frame, int regno, gdb_byte *rare_buffer) { struct gdbarch *gdbarch = get_frame_arch (frame); - int raw_size = register_size (gdbarch, regno); - gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size); + int fpsize = register_size (gdbarch, regno); + gdb_byte *raw_buffer = alloca (fpsize); if (!deprecated_frame_register_read (frame, regno, raw_buffer)) error (_("can't read register %d (%s)"), regno, gdbarch_register_name (gdbarch, regno)); - if (raw_size == 8) + if (fpsize == 8) { /* We have a 64-bit value for this register. Find the low-order 32 bits. */ @@ -6221,9 +6271,9 @@ mips_read_fp_register_double (struct frame_info *frame, int regno, gdb_byte *rare_buffer) { struct gdbarch *gdbarch = get_frame_arch (frame); - int raw_size = register_size (gdbarch, regno); + int fpsize = register_size (gdbarch, regno); - if (raw_size == 8 && !mips2_fp_compat (frame)) + if (fpsize == 8) { /* We have a 64-bit value for this register, and we should use all 64 bits. */ @@ -6260,20 +6310,19 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame, int regnum) { /* Do values for FP (float) regs. */ struct gdbarch *gdbarch = get_frame_arch (frame); + int fpsize = register_size (gdbarch, regnum); gdb_byte *raw_buffer; double doub, flt1; /* Doubles extracted from raw hex data. */ int inv1, inv2; - raw_buffer - = ((gdb_byte *) - alloca (2 * register_size (gdbarch, mips_regnum (gdbarch)->fp0))); + raw_buffer = alloca (2 * fpsize); fprintf_filtered (file, "%s:", gdbarch_register_name (gdbarch, regnum)); fprintf_filtered (file, "%*s", 4 - (int) strlen (gdbarch_register_name (gdbarch, regnum)), ""); - if (register_size (gdbarch, regnum) == 4 || mips2_fp_compat (frame)) + if (fpsize == 4) { struct value_print_options opts; @@ -8167,6 +8216,7 @@ value_of_mips_user_reg (struct frame_info *frame, const void *baton) static struct gdbarch * mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { + struct gdbarch_tdep_info tdep_info = { NULL }; struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; int elf_flags; @@ -8181,6 +8231,10 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) int dspacc; int dspctl; + /* Wire in an empty template tdep_info if one hasn't been supplied. */ + if (info.tdep_info == NULL) + info.tdep_info = &tdep_info; + /* Fill in the OS dependent register numbers and names. */ if (info.osabi == GDB_OSABI_IRIX) { @@ -8252,6 +8306,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) const struct tdesc_feature *feature; int valid_p; + int fpsize; feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.mips.cpu"); @@ -8311,7 +8366,15 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) return NULL; } - valid_p = 1; + /* Set the floating-point register size, assuming that whoever + supplied the description got the current setting right wrt + CP0 Status register's bit FR if applicable. */ + fpsize = tdesc_register_size (feature, mips_fprs[0]) / 8; + + /* Only accept a description whose floating-point register size + matches the requested size or if none was specified. */ + valid_p = (info.tdep_info->fp_register_size == 0 + || info.tdep_info->fp_register_size == fpsize); for (i = 0; i < 32; i++) valid_p &= tdesc_numbered_register (feature, tdesc_data, i + mips_regnum.fp0, mips_fprs[i]); @@ -8366,6 +8429,9 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } } + /* Fix the floating-point register size found. */ + info.tdep_info->fp_register_size = fpsize; + /* It would be nice to detect an attempt to use a 64-bit ABI when only 32-bit registers are provided. */ reg_names = NULL; @@ -8576,6 +8642,11 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Be pedantic about which FPU is selected. */ if (gdbarch_tdep (arches->gdbarch)->mips_fpu_type != fpu_type) continue; + /* Ditto the requested floating-point register size if any. */ + if (info.tdep_info->fp_register_size != 0 + && (gdbarch_tdep (arches->gdbarch)->fp_register_size) + != info.tdep_info->fp_register_size) + continue; if (tdesc_data != NULL) tdesc_data_cleanup (tdesc_data); @@ -8593,6 +8664,8 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->mips_fpu_type = fpu_type; tdep->register_size_valid_p = 0; tdep->register_size = 0; + tdep->fp_register_size = info.tdep_info->fp_register_size; + tdep->fp_register_size_fixed_p = 0; if (info.target_desc) { @@ -8609,6 +8682,12 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } } + /* If we haven't figured out the size of floating-point registers + by now yet, then assume it is the same as for general-purpose + registers. */ + if (tdep->fp_register_size == 0) + tdep->fp_register_size = mips_isa_regsize (gdbarch); + /* Initially set everything according to the default ABI/ISA. */ set_gdbarch_short_bit (gdbarch, 16); set_gdbarch_int_bit (gdbarch, 32); @@ -8830,6 +8909,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_integer_to_address (gdbarch, mips_integer_to_address); set_gdbarch_register_type (gdbarch, mips_register_type); + set_gdbarch_regcache_changed (gdbarch, mips_set_float_regsize); set_gdbarch_print_registers_info (gdbarch, mips_print_registers_info); @@ -8869,7 +8949,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) mips_register_g_packet_guesses (gdbarch); /* Hook in OS ABI-specific overrides, if they have been registered. */ - info.tdep_info = tdesc_data; + ((struct gdbarch_tdep_info*)(info.tdep_info))->tdesc_data = tdesc_data; gdbarch_init_osabi (info, gdbarch); /* The hook may have adjusted num_regs, fetch the final value and diff --git a/gdb/mips-tdep.h b/gdb/mips-tdep.h index 2e4d194..6c1d9ca 100644 --- a/gdb/mips-tdep.h +++ b/gdb/mips-tdep.h @@ -113,11 +113,27 @@ struct gdbarch_tdep int register_size_valid_p; int register_size; + /* The size of floating-point registers determined at the run time. + This corresponds to CP0 Status register's bit FR setting if + implemented unless fixed_p is set. */ + int fp_register_size_fixed_p; + int fp_register_size; + /* Return the expected next PC if FRAME is stopped at a syscall instruction. */ CORE_ADDR (*syscall_next_pc) (struct frame_info *frame); }; +/* MIPS specific per-architecture initialization information. */ +struct gdbarch_tdep_info +{ + /* Target description data. */ + struct tdesc_arch_data *tdesc_data; + + /* The size of floating-point registers determined at the run time. */ + int fp_register_size; +}; + /* Register numbers of various important registers. */ enum diff --git a/gdb/regcache.c b/gdb/regcache.c index f0ba0cf..c3405b6 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -534,16 +534,35 @@ get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch) static ptid_t current_thread_ptid; static struct gdbarch *current_thread_arch; -struct regcache * -get_thread_regcache (ptid_t ptid) +static void +set_current_thread_ptid_arch (ptid_t ptid) { if (!current_thread_arch || !ptid_equal (current_thread_ptid, ptid)) { current_thread_ptid = ptid; current_thread_arch = target_thread_architecture (ptid); } +} + +struct regcache * +get_thread_regcache (ptid_t ptid) +{ + int registers_changed_p = current_regcache == NULL; + struct regcache *new_regcache; + + set_current_thread_ptid_arch (ptid); + new_regcache = get_thread_arch_regcache (ptid, current_thread_arch); + + if (registers_changed_p + && gdbarch_regcache_changed_p (current_thread_arch) + && gdbarch_regcache_changed (current_thread_arch, new_regcache)) + { + registers_changed (); + set_current_thread_ptid_arch (ptid); + new_regcache = get_thread_arch_regcache (ptid, current_thread_arch); + } - return get_thread_arch_regcache (ptid, current_thread_arch); + return new_regcache; } struct regcache *