diff options
Diffstat (limited to 'gdb/mips-tdep.c')
-rw-r--r-- | gdb/mips-tdep.c | 227 |
1 files changed, 173 insertions, 54 deletions
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index f0a27d9..3cee42e 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -1,7 +1,7 @@ /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger. - Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin. @@ -44,6 +44,10 @@ #include "elf-bfd.h" #include "symcat.h" +/* A useful bit in the CP0 status register (PS_REGNUM). */ +/* This bit is set if we are emulating 32-bit FPRs on a 64-bit chip. */ +#define ST0_FR (1 << 26) + /* The sizes of floating point registers. */ enum @@ -174,6 +178,31 @@ mips_saved_regsize (void) return 4; } +/* 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 (void) +{ + /* MIPS1 and MIPS2 have only 32 bit FPRs, and the FR bit is not + meaningful. */ + if (REGISTER_RAW_SIZE (FP0_REGNUM) == 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 ((read_register (PS_REGNUM) & ST0_FR) == 0) + return 1; +#endif + + return 0; +} + /* Indicate that the ABI makes use of double-precision registers provided by the FPU (rather than combining pairs of registers to form double-precision values). Do not use "TARGET_IS_MIPS64" to @@ -257,6 +286,9 @@ find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame); static CORE_ADDR after_prologue (CORE_ADDR pc, mips_extra_func_info_t proc_desc); +static void mips_read_fp_register_single (int regno, char *rare_buffer); +static void mips_read_fp_register_double (int regno, char *rare_buffer); + /* This value is the model of MIPS in use. It is derived from the value of the PrID register. */ @@ -2076,7 +2108,7 @@ mips_init_extra_frame_info (int fromleaf, struct frame_info *fci) We can't use fci->signal_handler_caller, it is not yet set. */ find_pc_partial_function (fci->pc, &name, (CORE_ADDR *) NULL, (CORE_ADDR *) NULL); - if (!IN_SIGTRAMP (fci->pc, name)) + if (!PC_IN_SIGTRAMP (fci->pc, name)) { frame_saved_regs_zalloc (fci); memcpy (fci->saved_regs, temp_saved_regs, SIZEOF_FRAME_SAVED_REGS); @@ -2676,34 +2708,133 @@ mips_pop_frame (void) } } +/* Floating point register management. + + Background: MIPS1 & 2 fp registers are 32 bits wide. To support + 64bit operations, these early MIPS cpus treat fp register pairs + (f0,f1) as a single register (d0). Later MIPS cpu's have 64 bit fp + registers and offer a compatibility mode that emulates the MIPS2 fp + model. When operating in MIPS2 fp compat mode, later cpu's split + double precision floats into two 32-bit chunks and store them in + consecutive fp regs. To display 64-bit floats stored in this + fashion, we have to combine 32 bits from f0 and 32 bits from f1. + Throw in user-configurable endianness and you have a real mess. + + The way this works is: + - If we are in 32-bit mode or on a 32-bit processor, then a 64-bit + double-precision value will be split across two logical registers. + The lower-numbered logical register will hold the low-order bits, + regardless of the processor's endianness. + - If we are on a 64-bit processor, and we are looking for a + single-precision value, it will be in the low ordered bits + of a 64-bit GPR (after mfc1, for example) or a 64-bit register + save slot in memory. + - If we are in 64-bit mode, everything is straightforward. + + Note that this code only deals with "live" registers at the top of the + stack. We will attempt to deal with saved registers later, when + the raw/cooked register interface is in place. (We need a general + interface that can deal with dynamic saved register sizes -- fp + regs could be 32 bits wide in one frame and 64 on the frame above + and below). */ + +/* Copy a 32-bit single-precision value from the current frame + into rare_buffer. */ + +static void +mips_read_fp_register_single (int regno, char *rare_buffer) +{ + int raw_size = REGISTER_RAW_SIZE (regno); + char *raw_buffer = alloca (raw_size); + + if (!frame_register_read (selected_frame, regno, raw_buffer)) + error ("can't read register %d (%s)", regno, REGISTER_NAME (regno)); + if (raw_size == 8) + { + /* We have a 64-bit value for this register. Find the low-order + 32 bits. */ + int offset; + + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + offset = 4; + else + offset = 0; + + memcpy (rare_buffer, raw_buffer + offset, 4); + } + else + { + memcpy (rare_buffer, raw_buffer, 4); + } +} + +/* 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. */ + +static void +mips_read_fp_register_double (int regno, char *rare_buffer) +{ + int raw_size = REGISTER_RAW_SIZE (regno); + + if (raw_size == 8 && !mips2_fp_compat ()) + { + /* We have a 64-bit value for this register, and we should use + all 64 bits. */ + if (!frame_register_read (selected_frame, regno, rare_buffer)) + error ("can't read register %d (%s)", regno, REGISTER_NAME (regno)); + } + else + { + if ((regno - FP0_REGNUM) & 1) + internal_error (__FILE__, __LINE__, + "mips_read_fp_register_double: bad access to " + "odd-numbered FP register"); + + /* mips_read_fp_register_single will find the correct 32 bits from + each register. */ + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + { + mips_read_fp_register_single (regno, rare_buffer + 4); + mips_read_fp_register_single (regno + 1, rare_buffer); + } + else + { + mips_read_fp_register_single (regno, rare_buffer); + mips_read_fp_register_single (regno + 1, rare_buffer + 4); + } + } +} + static void mips_print_register (int regnum, int all) { char raw_buffer[MAX_REGISTER_RAW_SIZE]; /* Get the data in raw format. */ - if (read_relative_register_raw_bytes (regnum, raw_buffer)) + if (!frame_register_read (selected_frame, regnum, raw_buffer)) { printf_filtered ("%s: [Invalid]", REGISTER_NAME (regnum)); return; } - /* If an even floating point register, also print as double. */ + /* If we have a actual 32-bit floating point register (or we are in + 32-bit compatibility mode), and the register is even-numbered, + also print it as a double (spanning two registers). */ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT + && (REGISTER_RAW_SIZE (regnum) == 4 + || mips2_fp_compat ()) && !((regnum - FP0_REGNUM) & 1)) - if (REGISTER_RAW_SIZE (regnum) == 4) /* this would be silly on MIPS64 or N32 (Irix 6) */ - { - char dbuffer[2 * MAX_REGISTER_RAW_SIZE]; + { + char dbuffer[2 * MAX_REGISTER_RAW_SIZE]; - read_relative_register_raw_bytes (regnum, dbuffer); - read_relative_register_raw_bytes (regnum + 1, dbuffer + MIPS_REGSIZE); - REGISTER_CONVERT_TO_TYPE (regnum, builtin_type_double, dbuffer); + mips_read_fp_register_double (regnum, dbuffer); - printf_filtered ("(d%d: ", regnum - FP0_REGNUM); - val_print (builtin_type_double, dbuffer, 0, 0, - gdb_stdout, 0, 1, 0, Val_pretty_default); - printf_filtered ("); "); - } + printf_filtered ("(d%d: ", regnum - FP0_REGNUM); + val_print (builtin_type_double, dbuffer, 0, 0, + gdb_stdout, 0, 1, 0, Val_pretty_default); + printf_filtered ("); "); + } fputs_filtered (REGISTER_NAME (regnum), gdb_stdout); /* The problem with printing numeric register names (r26, etc.) is that @@ -2717,8 +2848,10 @@ mips_print_register (int regnum, int all) /* If virtual format is floating, print it that way. */ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT) - if (FP_REGISTER_DOUBLE) - { /* show 8-byte floats as float AND double: */ + if (REGISTER_RAW_SIZE (regnum) == 8 && !mips2_fp_compat ()) + { + /* We have a meaningful 64-bit value in this register. Show + it as a 32-bit float and a 64-bit double. */ int offset = 4 * (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG); printf_filtered (" (float) "); @@ -2753,35 +2886,25 @@ mips_print_register (int regnum, int all) static int do_fp_register_row (int regnum) { /* do values for FP (float) regs */ - char *raw_buffer[2]; - char *dbl_buffer; - /* use HI and LO to control the order of combining two flt regs */ - int HI = (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG); - int LO = (TARGET_BYTE_ORDER != BFD_ENDIAN_BIG); + char *raw_buffer; double doub, flt1, flt2; /* doubles extracted from raw hex data */ int inv1, inv2, inv3; - raw_buffer[0] = (char *) alloca (REGISTER_RAW_SIZE (FP0_REGNUM)); - raw_buffer[1] = (char *) alloca (REGISTER_RAW_SIZE (FP0_REGNUM)); - dbl_buffer = (char *) alloca (2 * REGISTER_RAW_SIZE (FP0_REGNUM)); + raw_buffer = (char *) alloca (2 * REGISTER_RAW_SIZE (FP0_REGNUM)); - /* Get the data in raw format. */ - if (read_relative_register_raw_bytes (regnum, raw_buffer[HI])) - error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum)); - if (REGISTER_RAW_SIZE (regnum) == 4) + if (REGISTER_RAW_SIZE (regnum) == 4 || mips2_fp_compat ()) { - /* 4-byte registers: we can fit two registers per row. */ - /* Also print every pair of 4-byte regs as an 8-byte double. */ - if (read_relative_register_raw_bytes (regnum + 1, raw_buffer[LO])) - error ("can't read register %d (%s)", - regnum + 1, REGISTER_NAME (regnum + 1)); - - /* copy the two floats into one double, and unpack both */ - memcpy (dbl_buffer, raw_buffer, 2 * REGISTER_RAW_SIZE (FP0_REGNUM)); - flt1 = unpack_double (builtin_type_float, raw_buffer[HI], &inv1); - flt2 = unpack_double (builtin_type_float, raw_buffer[LO], &inv2); - doub = unpack_double (builtin_type_double, dbl_buffer, &inv3); + /* 4-byte registers: we can fit two registers per row. */ + /* Also print every pair of 4-byte regs as an 8-byte double. */ + mips_read_fp_register_single (regnum, raw_buffer); + flt1 = unpack_double (builtin_type_float, raw_buffer, &inv1); + + mips_read_fp_register_single (regnum + 1, raw_buffer); + flt2 = unpack_double (builtin_type_float, raw_buffer, &inv2); + mips_read_fp_register_double (regnum, raw_buffer); + doub = unpack_double (builtin_type_double, raw_buffer, &inv3); + printf_filtered (" %-5s", REGISTER_NAME (regnum)); if (inv1) printf_filtered (": <invalid float>"); @@ -2805,14 +2928,14 @@ do_fp_register_row (int regnum) regnum += 2; } else - { /* eight byte registers: print each one as float AND as double. */ - int offset = 4 * (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG); - - memcpy (dbl_buffer, raw_buffer[HI], 2 * REGISTER_RAW_SIZE (FP0_REGNUM)); - flt1 = unpack_double (builtin_type_float, - &raw_buffer[HI][offset], &inv1); - doub = unpack_double (builtin_type_double, dbl_buffer, &inv3); + { + /* Eight byte registers: print each one as float AND as double. */ + mips_read_fp_register_single (regnum, raw_buffer); + flt1 = unpack_double (builtin_type_double, raw_buffer, &inv1); + mips_read_fp_register_double (regnum, raw_buffer); + doub = unpack_double (builtin_type_double, raw_buffer, &inv3); + printf_filtered (" %-5s: ", REGISTER_NAME (regnum)); if (inv1) printf_filtered ("<invalid float>"); @@ -2869,7 +2992,7 @@ do_gp_register_row (int regnum) if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT) break; /* end row: reached FP register */ /* OK: get the data in raw format. */ - if (read_relative_register_raw_bytes (regnum, raw_buffer)) + if (!frame_register_read (selected_frame, regnum, raw_buffer)) error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum)); /* pad small registers */ for (byte = 0; byte < (MIPS_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++) @@ -3589,7 +3712,7 @@ gdb_print_insn_mips (bfd_vma memaddr, disassemble_info *info) (if necessary) to point to the actual memory location where the breakpoint should be inserted. */ -unsigned char * +const unsigned char * mips_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr) { if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) @@ -4238,7 +4361,6 @@ mips_gdbarch_init (struct gdbarch_info info, set_gdbarch_read_pc (gdbarch, mips_read_pc); set_gdbarch_write_pc (gdbarch, generic_target_write_pc); set_gdbarch_read_fp (gdbarch, generic_target_read_fp); - set_gdbarch_write_fp (gdbarch, generic_target_write_fp); set_gdbarch_read_sp (gdbarch, generic_target_read_sp); set_gdbarch_write_sp (gdbarch, generic_target_write_sp); @@ -4455,9 +4577,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) "mips_dump_tdep: IGNORE_HELPER_CALL # %s\n", XSTRING (IGNORE_HELPER_CALL (PC))); fprintf_unfiltered (file, - "mips_dump_tdep: IN_SIGTRAMP # %s\n", - XSTRING (IN_SIGTRAMP (PC, NAME))); - fprintf_unfiltered (file, "mips_dump_tdep: IN_SOLIB_CALL_TRAMPOLINE # %s\n", XSTRING (IN_SOLIB_CALL_TRAMPOLINE (PC, NAME))); fprintf_unfiltered (file, |