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.
This commit is contained in:
Michael Snyder 2002-08-10 00:34:04 +00:00
parent 94fdcfdc0a
commit cb3d25d11f
2 changed files with 273 additions and 26 deletions

View file

@ -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

View file

@ -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);
@ -2779,6 +2783,230 @@ mips_push_arguments (int nargs,
return sp;
}
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)
{
@ -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);