diff options
Diffstat (limited to 'gdb/mips-tdep.c')
-rw-r--r-- | gdb/mips-tdep.c | 281 |
1 files changed, 229 insertions, 52 deletions
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index e4aa2bb..80bf1c4 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -36,8 +36,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "opcode/mips.h" -/* Some MIPS boards don't support floating point, so we permit the - user to turn it off. */ +/* Some MIPS boards don't support floating point while others only + support single-precision floating-point operations. See also + FP_REGISTER_DOUBLE. */ enum mips_fpu_type { @@ -53,11 +54,17 @@ static int mips_fpu_type_auto = 1; static enum mips_fpu_type mips_fpu_type = MIPS_DEFAULT_FPU_TYPE; #define MIPS_FPU_TYPE mips_fpu_type - -#define VM_MIN_ADDRESS (CORE_ADDR)0x400000 +#ifndef MIPS_SAVED_REGSIZE +#define MIPS_SAVED_REGSIZE MIPS_REGSIZE +#endif /* Do not use "TARGET_IS_MIPS64" to test the size of floating point registers */ +#ifndef FP_REGISTER_DOUBLE #define FP_REGISTER_DOUBLE (REGISTER_VIRTUAL_SIZE(FP0_REGNUM) == 8) +#endif + + +#define VM_MIN_ADDRESS (CORE_ADDR)0x400000 #if 0 static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR)); @@ -223,7 +230,7 @@ mips_use_struct_convention (gcc_p, type) struct type *type; { if (MIPS_EABI) - return (TYPE_LENGTH (type) > 2 * MIPS_REGSIZE); + return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE); else return 1; /* Structures are returned by ref in extra arg0 */ } @@ -933,7 +940,7 @@ mips_find_saved_regs (fci) if (gen_mask & 0x80000000) { fci->saved_regs[ireg] = reg_position; - reg_position -= MIPS_REGSIZE; + reg_position -= MIPS_SAVED_REGSIZE; } /* The MIPS16 entry instruction saves $s0 and $s1 in the reverse order @@ -951,13 +958,13 @@ mips_find_saved_regs (fci) /* Check if the ra register was pushed on the stack. */ reg_position = fci->frame + PROC_REG_OFFSET (proc_desc); if (inst & 0x20) - reg_position -= MIPS_REGSIZE; + reg_position -= MIPS_SAVED_REGSIZE; /* Check if the s0 and s1 registers were pushed on the stack. */ for (reg = 16; reg < sreg_count+16; reg++) { fci->saved_regs[reg] = reg_position; - reg_position -= MIPS_REGSIZE; + reg_position -= MIPS_SAVED_REGSIZE; } } } @@ -969,7 +976,7 @@ mips_find_saved_regs (fci) /* The freg_offset points to where the first *double* register is saved. So skip to the high-order word. */ if (! GDB_TARGET_IS_MIPS64) - reg_position += MIPS_REGSIZE; + reg_position += MIPS_SAVED_REGSIZE; /* Fill in the offsets for the float registers which float_mask says were saved. */ @@ -977,7 +984,7 @@ mips_find_saved_regs (fci) if (float_mask & 0x80000000) { fci->saved_regs[FP0_REGNUM+ireg] = reg_position; - reg_position -= MIPS_REGSIZE; + reg_position -= MIPS_SAVED_REGSIZE; } fci->saved_regs[PC_REGNUM] = fci->saved_regs[RA_REGNUM]; @@ -999,7 +1006,7 @@ read_next_frame_reg(fi, regno) if (fi->saved_regs == NULL) mips_find_saved_regs (fi); if (fi->saved_regs[regno]) - return read_memory_integer(fi->saved_regs[regno], MIPS_REGSIZE); + return read_memory_integer(fi->saved_regs[regno], MIPS_SAVED_REGSIZE); } } return read_register (regno); @@ -1065,9 +1072,9 @@ mips_frame_saved_pc(frame) : (proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM); if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc)) - saved_pc = read_memory_integer(frame->frame - MIPS_REGSIZE, MIPS_REGSIZE); + saved_pc = read_memory_integer (frame->frame - MIPS_SAVED_REGSIZE, MIPS_SAVED_REGSIZE); else - saved_pc = read_next_frame_reg(frame, pcreg); + saved_pc = read_next_frame_reg (frame, pcreg); return ADDR_BITS_REMOVE (saved_pc); } @@ -1359,7 +1366,7 @@ mips16_heuristic_proc_desc(start_pc, limit_pc, next_frame, sp) { PROC_REG_MASK(&temp_proc_desc) |= 1 << reg; set_reg_offset (reg, sp + offset); - offset += MIPS_REGSIZE; + offset += MIPS_SAVED_REGSIZE; } /* Check if the ra register was pushed on the stack. */ @@ -1368,7 +1375,7 @@ mips16_heuristic_proc_desc(start_pc, limit_pc, next_frame, sp) { PROC_REG_MASK(&temp_proc_desc) |= 1 << RA_REGNUM; set_reg_offset (RA_REGNUM, sp + offset); - offset -= MIPS_REGSIZE; + offset -= MIPS_SAVED_REGSIZE; } /* Check if the s0 and s1 registers were pushed on the stack. */ @@ -1376,7 +1383,7 @@ mips16_heuristic_proc_desc(start_pc, limit_pc, next_frame, sp) { PROC_REG_MASK(&temp_proc_desc) |= 1 << reg; set_reg_offset (reg, sp + offset); - offset -= MIPS_REGSIZE; + offset -= MIPS_SAVED_REGSIZE; } } } @@ -1754,7 +1761,7 @@ setup_arbitrary_frame (argc, argv) #define STACK_ARGSIZE 8 #else #define MIPS_NABI32 0 -#define STACK_ARGSIZE MIPS_REGSIZE +#define STACK_ARGSIZE MIPS_SAVED_REGSIZE #endif CORE_ADDR @@ -1782,13 +1789,13 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) On at least one MIPS variant, stack frames need to be 128-bit aligned, so we round to this widest known alignment. */ sp = ROUND_DOWN (sp, 16); - struct_addr = ROUND_DOWN (struct_addr, MIPS_REGSIZE); + struct_addr = ROUND_DOWN (struct_addr, MIPS_SAVED_REGSIZE); /* Now make space on the stack for the args. We allocate more than necessary for EABI, because the first few arguments are passed in registers, but that's OK. */ for (argnum = 0; argnum < nargs; argnum++) - len += ROUND_UP (TYPE_LENGTH(VALUE_TYPE(args[argnum])), MIPS_REGSIZE); + len += ROUND_UP (TYPE_LENGTH(VALUE_TYPE(args[argnum])), MIPS_SAVED_REGSIZE); sp -= ROUND_UP (len, 16); /* Initialize the integer and float register pointers. */ @@ -1813,12 +1820,12 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) /* The EABI passes structures that do not fit in a register by reference. In all other cases, pass the structure by value. */ - if (MIPS_EABI && len > MIPS_REGSIZE && + if (MIPS_EABI && len > MIPS_SAVED_REGSIZE && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) { - store_address (valbuf, MIPS_REGSIZE, VALUE_ADDRESS (arg)); + store_address (valbuf, MIPS_SAVED_REGSIZE, VALUE_ADDRESS (arg)); typecode = TYPE_CODE_PTR; - len = MIPS_REGSIZE; + len = MIPS_SAVED_REGSIZE; val = valbuf; } else @@ -1887,11 +1894,11 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) where gcc sometimes puts them on the stack. For maximum compatibility, we will put them in both places. */ - int odd_sized_struct = ((len > MIPS_REGSIZE) && - (len % MIPS_REGSIZE != 0)); + int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) && + (len % MIPS_SAVED_REGSIZE != 0)); while (len > 0) { - int partial_len = len < MIPS_REGSIZE ? len : MIPS_REGSIZE; + int partial_len = len < MIPS_SAVED_REGSIZE ? len : MIPS_SAVED_REGSIZE; if (argreg > MIPS_LAST_ARG_REGNUM || odd_sized_struct) { @@ -1901,16 +1908,18 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) int longword_offset = 0; if (TARGET_BYTE_ORDER == BIG_ENDIAN) - if (STACK_ARGSIZE == 8 && - (typecode == TYPE_CODE_INT || - typecode == TYPE_CODE_PTR || - typecode == TYPE_CODE_FLT) && len <= 4) - longword_offset = STACK_ARGSIZE - len; - else if ((typecode == TYPE_CODE_STRUCT || - typecode == TYPE_CODE_UNION) && - TYPE_LENGTH (arg_type) < STACK_ARGSIZE) - longword_offset = STACK_ARGSIZE - len; - + { + if (STACK_ARGSIZE == 8 && + (typecode == TYPE_CODE_INT || + typecode == TYPE_CODE_PTR || + typecode == TYPE_CODE_FLT) && len <= 4) + longword_offset = STACK_ARGSIZE - len; + else if ((typecode == TYPE_CODE_STRUCT || + typecode == TYPE_CODE_UNION) && + TYPE_LENGTH (arg_type) < STACK_ARGSIZE) + longword_offset = STACK_ARGSIZE - len; + } + write_memory (sp + stack_offset + longword_offset, val, partial_len); } @@ -1934,12 +1943,12 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) binaries. */ if (!MIPS_EABI - && (MIPS_REGSIZE < 8) + && MIPS_SAVED_REGSIZE < 8 && TARGET_BYTE_ORDER == BIG_ENDIAN - && (partial_len < MIPS_REGSIZE) + && partial_len < MIPS_SAVED_REGSIZE && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) - regval <<= ((MIPS_REGSIZE - partial_len) * + regval <<= ((MIPS_SAVED_REGSIZE - partial_len) * TARGET_CHAR_BIT); write_register (argreg, regval); @@ -1981,21 +1990,33 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) } static void -mips_push_register(CORE_ADDR *sp, int regno) +mips_push_register (CORE_ADDR *sp, int regno) { char buffer[MAX_REGISTER_RAW_SIZE]; - int regsize = REGISTER_RAW_SIZE (regno); - + int regsize; + int offset; + if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno)) + { + regsize = MIPS_SAVED_REGSIZE; + offset = (TARGET_BYTE_ORDER == BIG_ENDIAN + ? REGISTER_RAW_SIZE (regno) - MIPS_SAVED_REGSIZE + : 0); + } + else + { + regsize = REGISTER_RAW_SIZE (regno); + offset = 0; + } *sp -= regsize; read_register_gen (regno, buffer); - write_memory (*sp, buffer, regsize); + write_memory (*sp, buffer + offset, regsize); } /* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<(MIPS_NUMREGS-1). */ #define MASK(i,j) (((1 << ((j)+1))-1) ^ ((1 << (i))-1)) void -mips_push_dummy_frame() +mips_push_dummy_frame () { int ireg; struct linked_proc_info *link = (struct linked_proc_info*) @@ -2046,7 +2067,7 @@ mips_push_dummy_frame() /* Save general CPU registers */ PROC_REG_MASK(proc_desc) = GEN_REG_SAVE_MASK; /* PROC_REG_OFFSET is the offset of the first saved register from FP. */ - PROC_REG_OFFSET(proc_desc) = sp - old_sp - MIPS_REGSIZE; + PROC_REG_OFFSET(proc_desc) = sp - old_sp - MIPS_SAVED_REGSIZE; for (ireg = 32; --ireg >= 0; ) if (PROC_REG_MASK(proc_desc) & (1 << ireg)) mips_push_register (&sp, ireg); @@ -2091,7 +2112,7 @@ mips_pop_frame() && frame->saved_regs[regnum]) write_register (regnum, read_memory_integer (frame->saved_regs[regnum], - MIPS_REGSIZE)); + MIPS_SAVED_REGSIZE)); } write_register (SP_REGNUM, new_sp); flush_cached_frames (); @@ -2119,12 +2140,15 @@ mips_pop_frame() free (pi_ptr); write_register (HI_REGNUM, - read_memory_integer (new_sp - 2*MIPS_REGSIZE, MIPS_REGSIZE)); + read_memory_integer (new_sp - 2*MIPS_SAVED_REGSIZE, + MIPS_SAVED_REGSIZE)); write_register (LO_REGNUM, - read_memory_integer (new_sp - 3*MIPS_REGSIZE, MIPS_REGSIZE)); + read_memory_integer (new_sp - 3*MIPS_SAVED_REGSIZE, + MIPS_SAVED_REGSIZE)); if (MIPS_FPU_TYPE != MIPS_FPU_NONE) write_register (FCRCS_REGNUM, - read_memory_integer (new_sp - 4*MIPS_REGSIZE, MIPS_REGSIZE)); + read_memory_integer (new_sp - 4*MIPS_SAVED_REGSIZE, + MIPS_SAVED_REGSIZE)); } } @@ -2614,14 +2638,143 @@ mips_in_lenient_prologue (startaddr, pc) } #endif -/* Given a return value in `regbuf' with a type `valtype', - extract and copy its value into `valbuf'. */ +/* Determine how a return value is stored within the MIPS register + file, given the return type `valtype'. */ + +struct return_value_word +{ + int len; + int reg; + int reg_offset; + int buf_offset; +}; + +static void return_value_location PARAMS ((struct type *, struct return_value_word *, struct return_value_word *)); + +static void +return_value_location (valtype, hi, lo) + struct type *valtype; + struct return_value_word *hi; + struct return_value_word *lo; +{ + int len = TYPE_LENGTH (valtype); + + if (TYPE_CODE (valtype) == TYPE_CODE_FLT + && ((MIPS_FPU_TYPE == MIPS_FPU_DOUBLE && (len == 4 || len == 8)) + || (MIPS_FPU_TYPE == MIPS_FPU_SINGLE && len == 4))) + { + if (!FP_REGISTER_DOUBLE && len == 8) + { + /* We need to break a 64bit float in two 32 bit halves and + spread them across a floating-point register pair. */ + lo->buf_offset = TARGET_BYTE_ORDER == BIG_ENDIAN ? 4 : 0; + hi->buf_offset = TARGET_BYTE_ORDER == BIG_ENDIAN ? 0 : 4; + lo->reg_offset = ((TARGET_BYTE_ORDER == BIG_ENDIAN + && REGISTER_RAW_SIZE (FP0_REGNUM) == 8) + ? 4 : 0); + hi->reg_offset = lo->reg_offset; + lo->reg = FP0_REGNUM + 0; + hi->reg = FP0_REGNUM + 1; + lo->len = 4; + hi->len = 4; + } + else + { + /* The floating point value fits in a single floating-point + register. */ + lo->reg_offset = ((TARGET_BYTE_ORDER == BIG_ENDIAN + && REGISTER_RAW_SIZE (FP0_REGNUM) == 8 + && len == 4) + ? 4 : 0); + lo->reg = FP0_REGNUM; + lo->len = len; + lo->buf_offset = 0; + hi->len = 0; + hi->reg_offset = 0; + hi->buf_offset = 0; + hi->reg = 0; + } + } + else + { + /* Locate a result possibly spread across two registers. */ + int regnum = 2; + lo->reg = regnum + 0; + hi->reg = regnum + 1; + if (TARGET_BYTE_ORDER == BIG_ENDIAN + && len < MIPS_SAVED_REGSIZE) + { + /* "un-left-justify" the value in the low register */ + lo->reg_offset = MIPS_SAVED_REGSIZE - len; + lo->len = len; + hi->reg_offset = 0; + hi->len = 0; + } + else if (TARGET_BYTE_ORDER == BIG_ENDIAN + && len > MIPS_SAVED_REGSIZE /* odd-size structs */ + && len < MIPS_SAVED_REGSIZE * 2 + && (TYPE_CODE (valtype) == TYPE_CODE_STRUCT || + TYPE_CODE (valtype) == TYPE_CODE_UNION)) + { + /* "un-left-justify" the value spread across two registers. */ + lo->reg_offset = 2 * MIPS_SAVED_REGSIZE - len; + lo->len = MIPS_SAVED_REGSIZE - lo->reg_offset; + hi->reg_offset = 0; + hi->len = len - lo->len; + } + else + { + /* Only perform a partial copy of the second register. */ + lo->reg_offset = 0; + hi->reg_offset = 0; + if (len > MIPS_SAVED_REGSIZE) + { + lo->len = MIPS_SAVED_REGSIZE; + hi->len = len - MIPS_SAVED_REGSIZE; + } + else + { + lo->len = len; + hi->len = 0; + } + } + if (TARGET_BYTE_ORDER == BIG_ENDIAN + && REGISTER_RAW_SIZE (regnum) == 8 + && MIPS_SAVED_REGSIZE == 4) + { + /* Account for the fact that only the least-signficant part + of the register is being used */ + lo->reg_offset += 4; + hi->reg_offset += 4; + } + lo->buf_offset = 0; + hi->buf_offset = lo->len; + } +} + +/* Given a return value in `regbuf' with a type `valtype', extract and + copy its value into `valbuf'. */ + void mips_extract_return_value (valtype, regbuf, valbuf) struct type *valtype; char regbuf[REGISTER_BYTES]; char *valbuf; { + struct return_value_word lo; + struct return_value_word hi; + return_value_location (valtype, &lo, &hi); + + memcpy (valbuf + lo.buf_offset, + regbuf + REGISTER_BYTE (lo.reg) + lo.reg_offset, + lo.len); + + if (hi.len > 0) + memcpy (valbuf + hi.buf_offset, + regbuf + REGISTER_BYTE (hi.reg) + hi.reg_offset, + hi.len); + +#if 0 int regnum; int offset = 0; int len = TYPE_LENGTH (valtype); @@ -2645,15 +2798,38 @@ mips_extract_return_value (valtype, regbuf, valbuf) } memcpy (valbuf, regbuf + REGISTER_BYTE (regnum) + offset, len); REGISTER_CONVERT_TO_TYPE (regnum, valtype, valbuf); +#endif } -/* Given a return value in `regbuf' with a type `valtype', - write it's value into the appropriate register. */ +/* Given a return value in `valbuf' with a type `valtype', write it's + value into the appropriate register. */ + void mips_store_return_value (valtype, valbuf) struct type *valtype; char *valbuf; { + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + struct return_value_word lo; + struct return_value_word hi; + return_value_location (valtype, &lo, &hi); + + memset (raw_buffer, 0, sizeof (raw_buffer)); + memcpy (raw_buffer + lo.reg_offset, valbuf + lo.buf_offset, lo.len); + write_register_bytes (REGISTER_BYTE (lo.reg), + raw_buffer, + REGISTER_RAW_SIZE (lo.reg)); + + if (hi.len > 0) + { + memset (raw_buffer, 0, sizeof (raw_buffer)); + memcpy (raw_buffer + hi.reg_offset, valbuf + hi.buf_offset, hi.len); + write_register_bytes (REGISTER_BYTE (hi.reg), + raw_buffer, + REGISTER_RAW_SIZE (hi.reg)); + } + +#if 0 int regnum; int offset = 0; int len = TYPE_LENGTH (valtype); @@ -2681,6 +2857,7 @@ mips_store_return_value (valtype, valbuf) write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, len > REGISTER_RAW_SIZE (regnum) ? len : REGISTER_RAW_SIZE (regnum)); +#endif } /* Exported procedure: Is PC in the signal trampoline code */ |