aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Snyder <msnyder@vmware.com>2002-08-10 00:34:04 +0000
committerMichael Snyder <msnyder@vmware.com>2002-08-10 00:34:04 +0000
commitcb3d25d11f6af715fc361ab4f8e3631be3f6a110 (patch)
treef92d732c502f6311e42487fc7a3a6a34fc7647ce
parent94fdcfdc0a226c0c0f3620c2750e647da6a24bef (diff)
downloadgdb-cb3d25d11f6af715fc361ab4f8e3631be3f6a110.zip
gdb-cb3d25d11f6af715fc361ab4f8e3631be3f6a110.tar.gz
gdb-cb3d25d11f6af715fc361ab4f8e3631be3f6a110.tar.bz2
2002-08-09 Michael Snyder <msnyder@redhat.com>
* 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.
-rw-r--r--gdb/ChangeLog14
-rw-r--r--gdb/mips-tdep.c285
2 files changed, 273 insertions, 26 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 42d2bb0..af49ea7 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,17 @@
+2002-08-09 Michael Snyder <msnyder@redhat.com>
+
+ * 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.
+
2002-08-09 Don Howard <dhoward@redhat.com>
* memattr.c (mem_info_command): Print special case of upper bound
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 1faf071..c57a03b 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -2443,6 +2443,12 @@ mips_type_needs_double_align (struct type *type)
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,
@@ -2457,16 +2463,12 @@ mips_push_arguments (int nargs,
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. */
+ 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);
@@ -2478,8 +2480,8 @@ mips_push_arguments (int nargs,
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));
+ 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;
@@ -2490,8 +2492,8 @@ mips_push_arguments (int nargs,
{
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
- "mips_push_arguments: struct_return reg=%d 0x%lx\n",
- argreg, (long) struct_addr);
+ "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;
@@ -2503,7 +2505,7 @@ mips_push_arguments (int nargs,
for (argnum = 0; argnum < nargs; argnum++)
{
char *val;
- char valbuf[MAX_REGISTER_RAW_SIZE];
+ 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);
@@ -2675,10 +2677,10 @@ mips_push_arguments (int nargs,
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);
+ 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;
@@ -2686,10 +2688,12 @@ mips_push_arguments (int nargs,
if (mips_debug)
{
int i;
- fprintf_unfiltered (gdb_stdlog, " @0x%lx ", (long) addr);
+ fprintf_unfiltered (gdb_stdlog, " @0x%s ",
+ paddr_nz (addr));
for (i = 0; i < partial_len; i++)
{
- fprintf_unfiltered (gdb_stdlog, "%02x", val[i] & 0xff);
+ fprintf_unfiltered (gdb_stdlog, "%02x",
+ val[i] & 0xff);
}
}
write_memory (addr, val, partial_len);
@@ -2780,6 +2784,230 @@ mips_push_arguments (int nargs,
}
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
@@ -2791,7 +3019,7 @@ mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
static void
mips_push_register (CORE_ADDR * sp, int regno)
{
- char buffer[MAX_REGISTER_RAW_SIZE];
+ char *buffer = alloca (MAX_REGISTER_RAW_SIZE);
int regsize;
int offset;
if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno))
@@ -3070,7 +3298,7 @@ mips_read_fp_register_double (int regno, char *rare_buffer)
static void
mips_print_register (int regnum, int all)
{
- char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char *raw_buffer (MAX_REGISTER_RAW_SIZE);
/* Get the data in raw format. */
if (!frame_register_read (selected_frame, regnum, raw_buffer))
@@ -3087,7 +3315,7 @@ mips_print_register (int regnum, int all)
|| mips2_fp_compat ())
&& !((regnum - FP0_REGNUM) & 1))
{
- char dbuffer[2 * MAX_REGISTER_RAW_SIZE];
+ char *dbuffer = alloca (2 * MAX_REGISTER_RAW_SIZE);
mips_read_fp_register_double (regnum, dbuffer);
@@ -3222,7 +3450,7 @@ static int
do_gp_register_row (int regnum)
{
/* do values for GP (int) regs */
- char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ 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;
@@ -3715,7 +3943,7 @@ mips_extract_return_value (struct type *valtype,
void
mips_store_return_value (struct type *valtype, char *valbuf)
{
- char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
struct return_value_word lo;
struct return_value_word hi;
return_value_location (valtype, &hi, &lo);
@@ -4547,6 +4775,7 @@ mips_gdbarch_init (struct gdbarch_info info,
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;
@@ -4564,6 +4793,7 @@ mips_gdbarch_init (struct gdbarch_info info,
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;
@@ -4581,6 +4811,7 @@ mips_gdbarch_init (struct gdbarch_info info,
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;
@@ -4598,6 +4829,7 @@ mips_gdbarch_init (struct gdbarch_info info,
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;
@@ -4615,6 +4847,7 @@ mips_gdbarch_init (struct gdbarch_info info,
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;
@@ -4644,6 +4877,7 @@ mips_gdbarch_init (struct gdbarch_info info,
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;
@@ -4763,7 +4997,6 @@ mips_gdbarch_init (struct gdbarch_info info,
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);