2002-08-09 Michael Snyder * mips-tdep.c (ROUND_DOWN, ROUND_UP): Move to global scope. (mips_push_arguments): Correct some comments. Use paddr_nz for printing addresses in debug output. Replace static allocation using MAX_REGISTER_RAW_SIZE with alloca. (mips_n32n64_push_arguments): New function, cloned from mips_push_arguments and tuned for the n32/n64 ABI. (mips_push_register): Buffer needs dynamic allocation. (mips_print_register): Ditto. (do_gp_register_row): Ditto. (mips_store_return_value): Ditto. (mips_gdbarch_init): Set gdbarch_push_arguments per ABI. Index: mips-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/mips-tdep.c,v retrieving revision 1.97 diff -c -3 -p -r1.97 mips-tdep.c *** mips-tdep.c 9 Aug 2002 21:58:14 -0000 1.97 --- mips-tdep.c 10 Aug 2002 00:26:50 -0000 *************** mips_type_needs_double_align (struct typ *** 2443,2448 **** --- 2443,2454 ---- return 0; } + /* Macros to round N up or down to the next A boundary; + A must be a power of two. */ + + #define ROUND_DOWN(n,a) ((n) & ~((a)-1)) + #define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1)) + CORE_ADDR mips_push_arguments (int nargs, struct value **args, *************** mips_push_arguments (int nargs, *** 2457,2472 **** int stack_offset = 0; struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - /* Macros to round N up or down to the next A boundary; A must be - a power of two. */ - #define ROUND_DOWN(n,a) ((n) & ~((a)-1)) - #define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1)) - /* First ensure that the stack and structure return address (if any) ! are properly aligned. The stack has to be at least 64-bit aligned ! even on 32-bit machines, because doubles must be 64-bit aligned. ! 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, 16); --- 2463,2474 ---- int stack_offset = 0; struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); /* First ensure that the stack and structure return address (if any) ! are properly aligned. The stack has to be at least 64-bit ! aligned even on 32-bit machines, because doubles must be 64-bit ! aligned. For n32 and n64, 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, 16); *************** mips_push_arguments (int nargs, *** 2478,2485 **** sp -= ROUND_UP (len, 16); if (mips_debug) ! fprintf_unfiltered (gdb_stdlog, "mips_push_arguments: sp=0x%lx allocated %d\n", ! (long) sp, ROUND_UP (len, 16)); /* Initialize the integer and float register pointers. */ argreg = A0_REGNUM; --- 2480,2487 ---- sp -= ROUND_UP (len, 16); if (mips_debug) ! fprintf_unfiltered (gdb_stdlog, "mips_push_arguments: sp=0x%s allocated %d\n", ! paddr_nz (sp), ROUND_UP (len, 16)); /* Initialize the integer and float register pointers. */ argreg = A0_REGNUM; *************** mips_push_arguments (int nargs, *** 2490,2497 **** { if (mips_debug) fprintf_unfiltered (gdb_stdlog, ! "mips_push_arguments: struct_return reg=%d 0x%lx\n", ! argreg, (long) struct_addr); write_register (argreg++, struct_addr); if (MIPS_REGS_HAVE_HOME_P) stack_offset += MIPS_STACK_ARGSIZE; --- 2492,2499 ---- { if (mips_debug) fprintf_unfiltered (gdb_stdlog, ! "mips_push_arguments: struct_return reg=%d 0x%s\n", ! argreg, paddr_nz (struct_addr)); write_register (argreg++, struct_addr); if (MIPS_REGS_HAVE_HOME_P) stack_offset += MIPS_STACK_ARGSIZE; *************** mips_push_arguments (int nargs, *** 2503,2509 **** for (argnum = 0; argnum < nargs; argnum++) { char *val; ! char valbuf[MAX_REGISTER_RAW_SIZE]; struct value *arg = args[argnum]; struct type *arg_type = check_typedef (VALUE_TYPE (arg)); int len = TYPE_LENGTH (arg_type); --- 2505,2511 ---- for (argnum = 0; argnum < nargs; argnum++) { char *val; ! char *valbuf = alloca (MAX_REGISTER_RAW_SIZE); struct value *arg = args[argnum]; struct type *arg_type = check_typedef (VALUE_TYPE (arg)); int len = TYPE_LENGTH (arg_type); *************** mips_push_arguments (int nargs, *** 2675,2684 **** if (mips_debug) { ! fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%lx", ! (long) stack_offset); ! fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%lx", ! (long) longword_offset); } addr = sp + stack_offset + longword_offset; --- 2677,2686 ---- if (mips_debug) { ! fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s", ! paddr_nz (stack_offset)); ! fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s", ! paddr_nz (longword_offset)); } addr = sp + stack_offset + longword_offset; *************** mips_push_arguments (int nargs, *** 2686,2695 **** if (mips_debug) { int i; ! fprintf_unfiltered (gdb_stdlog, " @0x%lx ", (long) addr); for (i = 0; i < partial_len; i++) { ! fprintf_unfiltered (gdb_stdlog, "%02x", val[i] & 0xff); } } write_memory (addr, val, partial_len); --- 2688,2699 ---- if (mips_debug) { int i; ! fprintf_unfiltered (gdb_stdlog, " @0x%s ", ! paddr_nz (addr)); for (i = 0; i < partial_len; i++) { ! fprintf_unfiltered (gdb_stdlog, "%02x", ! val[i] & 0xff); } } write_memory (addr, val, partial_len); *************** mips_push_arguments (int nargs, *** 2780,2785 **** --- 2784,3013 ---- } CORE_ADDR + mips_n32n64_push_arguments (int nargs, + struct value **args, + CORE_ADDR sp, + int struct_return, + CORE_ADDR struct_addr) + { + int argreg; + int float_argreg; + int argnum; + int len = 0; + int stack_offset = 0; + + /* First ensure that the stack and structure return address (if any) + are properly aligned. The stack has to be at least 64-bit + aligned even on 32-bit machines, because doubles must be 64-bit + aligned. For n32 and n64, 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, 16); + + /* Now make space on the stack for the args. */ + for (argnum = 0; argnum < nargs; argnum++) + len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), + MIPS_STACK_ARGSIZE); + sp -= ROUND_UP (len, 16); + + if (mips_debug) + fprintf_unfiltered (gdb_stdlog, + "mips_n32n64_push_arguments: sp=0x%s allocated %d\n", + paddr_nz (sp), ROUND_UP (len, 16)); + + /* Initialize the integer and float register pointers. */ + argreg = A0_REGNUM; + float_argreg = FPA0_REGNUM; + + /* the struct_return pointer occupies the first parameter-passing reg */ + if (struct_return) + { + if (mips_debug) + fprintf_unfiltered (gdb_stdlog, + "mips_n32n64_push_arguments: struct_return reg=%d 0x%s\n", + argreg, paddr_nz (struct_addr)); + write_register (argreg++, struct_addr); + } + + /* Now load as many as possible of the first arguments into + registers, and push the rest onto the stack. Loop thru args + from first to last. */ + for (argnum = 0; argnum < nargs; argnum++) + { + char *val; + char *valbuf = alloca (MAX_REGISTER_RAW_SIZE); + struct value *arg = args[argnum]; + struct type *arg_type = check_typedef (VALUE_TYPE (arg)); + int len = TYPE_LENGTH (arg_type); + enum type_code typecode = TYPE_CODE (arg_type); + + if (mips_debug) + fprintf_unfiltered (gdb_stdlog, + "mips_n32n64_push_arguments: %d len=%d type=%d", + argnum + 1, len, (int) typecode); + + val = (char *) VALUE_CONTENTS (arg); + + if (fp_register_arg_p (typecode, arg_type) + && float_argreg <= MIPS_LAST_FP_ARG_REGNUM) + { + /* This is a floating point value that fits entirely + in a single register. */ + /* On 32 bit ABI's the float_argreg is further adjusted + above to ensure that it is even register aligned. */ + LONGEST regval = extract_unsigned_integer (val, len); + if (mips_debug) + fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s", + float_argreg, phex (regval, len)); + write_register (float_argreg++, regval); + + if (mips_debug) + fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s", + argreg, phex (regval, len)); + write_register (argreg, regval); + argreg += 1; + } + else + { + /* Copy the argument to general registers or the stack in + register-sized pieces. Large arguments are split between + registers and stack. */ + /* Note: structs whose size is not a multiple of MIPS_REGSIZE + are treated specially: Irix cc passes them in registers + where gcc sometimes puts them on the stack. For maximum + compatibility, we will put them in both places. */ + int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) && + (len % MIPS_SAVED_REGSIZE != 0)); + /* Note: Floating-point values that didn't fit into an FP + register are only written to memory. */ + while (len > 0) + { + /* Rememer if the argument was written to the stack. */ + int stack_used_p = 0; + int partial_len = len < MIPS_SAVED_REGSIZE ? + len : MIPS_SAVED_REGSIZE; + + if (mips_debug) + fprintf_unfiltered (gdb_stdlog, " -- partial=%d", + partial_len); + + /* Write this portion of the argument to the stack. */ + if (argreg > MIPS_LAST_ARG_REGNUM + || odd_sized_struct + || fp_register_arg_p (typecode, arg_type)) + { + /* Should shorter than int integer values be + promoted to int before being stored? */ + int longword_offset = 0; + CORE_ADDR addr; + stack_used_p = 1; + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + { + if (MIPS_STACK_ARGSIZE == 8 && + (typecode == TYPE_CODE_INT || + typecode == TYPE_CODE_PTR || + typecode == TYPE_CODE_FLT) && len <= 4) + longword_offset = MIPS_STACK_ARGSIZE - len; + else if ((typecode == TYPE_CODE_STRUCT || + typecode == TYPE_CODE_UNION) && + TYPE_LENGTH (arg_type) < MIPS_STACK_ARGSIZE) + longword_offset = MIPS_STACK_ARGSIZE - len; + } + + if (mips_debug) + { + fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s", + paddr_nz (stack_offset)); + fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s", + paddr_nz (longword_offset)); + } + + addr = sp + stack_offset + longword_offset; + + if (mips_debug) + { + int i; + fprintf_unfiltered (gdb_stdlog, " @0x%s ", + paddr_nz (addr)); + for (i = 0; i < partial_len; i++) + { + fprintf_unfiltered (gdb_stdlog, "%02x", + val[i] & 0xff); + } + } + write_memory (addr, val, partial_len); + } + + /* Note!!! This is NOT an else clause. Odd sized + structs may go thru BOTH paths. Floating point + arguments will not. */ + /* Write this portion of the argument to a general + purpose register. */ + if (argreg <= MIPS_LAST_ARG_REGNUM + && !fp_register_arg_p (typecode, arg_type)) + { + LONGEST regval = extract_unsigned_integer (val, partial_len); + + /* A non-floating-point argument being passed in a + general register. If a struct or union, and if + the remaining length is smaller than the register + size, we have to adjust the register value on + big endian targets. + + It does not seem to be necessary to do the + same for integral types. + + cagney/2001-07-23: gdb/179: Also, GCC, when + outputting LE O32 with sizeof (struct) < + MIPS_SAVED_REGSIZE, generates a left shift as + part of storing the argument in a register a + register (the left shift isn't generated when + sizeof (struct) >= MIPS_SAVED_REGSIZE). Since it + is quite possible that this is GCC contradicting + the LE/O32 ABI, GDB has not been adjusted to + accommodate this. Either someone needs to + demonstrate that the LE/O32 ABI specifies such a + left shift OR this new ABI gets identified as + such and GDB gets tweaked accordingly. */ + + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG + && partial_len < MIPS_SAVED_REGSIZE + && (typecode == TYPE_CODE_STRUCT || + typecode == TYPE_CODE_UNION)) + regval <<= ((MIPS_SAVED_REGSIZE - partial_len) * + TARGET_CHAR_BIT); + + if (mips_debug) + fprintf_filtered (gdb_stdlog, " - reg=%d val=%s", + argreg, + phex (regval, MIPS_SAVED_REGSIZE)); + write_register (argreg, regval); + argreg++; + } + + len -= partial_len; + val += partial_len; + + /* Compute the the offset into the stack at which we + will copy the next parameter. + + In N32 (N64?), the stack_offset only needs to be + adjusted when it has been used. */ + + if (stack_used_p) + stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE); + } + } + if (mips_debug) + fprintf_unfiltered (gdb_stdlog, "\n"); + } + + /* Return adjusted stack pointer. */ + return sp; + } + + CORE_ADDR mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp) { /* Set the return address register to point to the entry *************** mips_push_return_address (CORE_ADDR pc, *** 2791,2797 **** static void mips_push_register (CORE_ADDR * sp, int regno) { ! char buffer[MAX_REGISTER_RAW_SIZE]; int regsize; int offset; if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno)) --- 3019,3025 ---- static void mips_push_register (CORE_ADDR * sp, int regno) { ! char *buffer = alloca (MAX_REGISTER_RAW_SIZE); int regsize; int offset; if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno)) *************** mips_read_fp_register_double (int regno, *** 3070,3076 **** static void mips_print_register (int regnum, int all) { ! char raw_buffer[MAX_REGISTER_RAW_SIZE]; /* Get the data in raw format. */ if (!frame_register_read (selected_frame, regnum, raw_buffer)) --- 3298,3304 ---- static void mips_print_register (int regnum, int all) { ! char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE); /* Get the data in raw format. */ if (!frame_register_read (selected_frame, regnum, raw_buffer)) *************** mips_print_register (int regnum, int all *** 3087,3093 **** || mips2_fp_compat ()) && !((regnum - FP0_REGNUM) & 1)) { ! char dbuffer[2 * MAX_REGISTER_RAW_SIZE]; mips_read_fp_register_double (regnum, dbuffer); --- 3315,3321 ---- || mips2_fp_compat ()) && !((regnum - FP0_REGNUM) & 1)) { ! char *dbuffer = alloca (2 * MAX_REGISTER_RAW_SIZE); mips_read_fp_register_double (regnum, dbuffer); *************** static int *** 3222,3228 **** do_gp_register_row (int regnum) { /* do values for GP (int) regs */ ! char raw_buffer[MAX_REGISTER_RAW_SIZE]; int ncols = (MIPS_REGSIZE == 8 ? 4 : 8); /* display cols per row */ int col, byte; int start_regnum = regnum; --- 3450,3456 ---- do_gp_register_row (int regnum) { /* do values for GP (int) regs */ ! char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE); int ncols = (MIPS_REGSIZE == 8 ? 4 : 8); /* display cols per row */ int col, byte; int start_regnum = regnum; *************** mips_extract_return_value (struct type * *** 3715,3721 **** void mips_store_return_value (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, &hi, &lo); --- 3943,3949 ---- void mips_store_return_value (struct type *valtype, char *valbuf) { ! char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE); struct return_value_word lo; struct return_value_word hi; return_value_location (valtype, &hi, &lo); *************** mips_gdbarch_init (struct gdbarch_info i *** 4547,4552 **** --- 4775,4781 ---- switch (mips_abi) { case MIPS_ABI_O32: + set_gdbarch_push_arguments (gdbarch, mips_push_arguments); tdep->mips_default_saved_regsize = 4; tdep->mips_default_stack_argsize = 4; tdep->mips_fp_register_double = 0; *************** mips_gdbarch_init (struct gdbarch_info i *** 4564,4569 **** --- 4793,4799 ---- mips_o32_use_struct_convention); break; case MIPS_ABI_O64: + set_gdbarch_push_arguments (gdbarch, mips_push_arguments); tdep->mips_default_saved_regsize = 8; tdep->mips_default_stack_argsize = 8; tdep->mips_fp_register_double = 1; *************** mips_gdbarch_init (struct gdbarch_info i *** 4581,4586 **** --- 4811,4817 ---- mips_o32_use_struct_convention); break; case MIPS_ABI_EABI32: + set_gdbarch_push_arguments (gdbarch, mips_push_arguments); tdep->mips_default_saved_regsize = 4; tdep->mips_default_stack_argsize = 4; tdep->mips_fp_register_double = 0; *************** mips_gdbarch_init (struct gdbarch_info i *** 4598,4603 **** --- 4829,4835 ---- mips_eabi_use_struct_convention); break; case MIPS_ABI_EABI64: + set_gdbarch_push_arguments (gdbarch, mips_push_arguments); tdep->mips_default_saved_regsize = 8; tdep->mips_default_stack_argsize = 8; tdep->mips_fp_register_double = 1; *************** mips_gdbarch_init (struct gdbarch_info i *** 4615,4620 **** --- 4847,4853 ---- mips_eabi_use_struct_convention); break; case MIPS_ABI_N32: + set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments); tdep->mips_default_saved_regsize = 8; tdep->mips_default_stack_argsize = 8; tdep->mips_fp_register_double = 1; *************** mips_gdbarch_init (struct gdbarch_info i *** 4644,4649 **** --- 4877,4883 ---- mips_n32n64_reg_struct_has_addr); break; case MIPS_ABI_N64: + set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments); tdep->mips_default_saved_regsize = 8; tdep->mips_default_stack_argsize = 8; tdep->mips_fp_register_double = 1; *************** mips_gdbarch_init (struct gdbarch_info i *** 4763,4769 **** set_gdbarch_call_dummy_words (gdbarch, mips_call_dummy_words); set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (mips_call_dummy_words)); set_gdbarch_push_return_address (gdbarch, mips_push_return_address); - set_gdbarch_push_arguments (gdbarch, mips_push_arguments); set_gdbarch_register_convertible (gdbarch, generic_register_convertible_not); set_gdbarch_coerce_float_to_double (gdbarch, mips_coerce_float_to_double); --- 4997,5002 ---- Index: config/mips/tm-mips.h =================================================================== RCS file: /cvs/src/src/gdb/config/mips/tm-mips.h,v retrieving revision 1.30 diff -c -3 -p -r1.30 tm-mips.h *** config/mips/tm-mips.h 8 Aug 2002 23:32:52 -0000 1.30 --- config/mips/tm-mips.h 10 Aug 2002 00:45:43 -0000 *************** extern int mips_frame_num_args (struct f *** 312,322 **** function calls. We don't need STACK_ALIGN, PUSH_ARGUMENTS will handle it. */ - extern CORE_ADDR mips_push_arguments (int, struct value **, CORE_ADDR, int, - CORE_ADDR); - #define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \ - (mips_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr))) - extern CORE_ADDR mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp); #define PUSH_RETURN_ADDRESS(PC, SP) (mips_push_return_address ((PC), (SP))) --- 312,317 ----