* arm-tdep.c (arm_push_arguments): Delete.

(struct stack_item): New type.
(push_stack_item, pop_stack_item, arm_push_dummy_call): New functions.
(arm_store_struct_return): Delte.
(arm_gdbarch_init): Register arm_push_dummy_call.  Don't register
arm_push_arguments or arm_store_struct_return.
This commit is contained in:
Richard Earnshaw 2003-03-29 17:08:00 +00:00
parent e8933a55f2
commit 2dd604e7ef
2 changed files with 165 additions and 143 deletions

View File

@ -1,3 +1,12 @@
2003-03-29 Richard Earnshaw <rearnsha@arm.com>
* arm-tdep.c (arm_push_arguments): Delete.
(struct stack_item): New type.
(push_stack_item, pop_stack_item, arm_push_dummy_call): New functions.
(arm_store_struct_return): Delte.
(arm_gdbarch_init): Register arm_push_dummy_call. Don't register
arm_push_arguments or arm_store_struct_return.
2003-03-28 Andrew Cagney <cagney@redhat.com>
* Makefile.in (d10v-tdep.o): Update dependencies.

View File

@ -1334,137 +1334,6 @@ arm_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
write_register (4, fun);
}
/* Note: ScottB
This function does not support passing parameters using the FPA
variant of the APCS. It passes any floating point arguments in the
general registers and/or on the stack. */
static CORE_ADDR
arm_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
CORE_ADDR fp;
int argnum;
int argreg;
int nstack;
int simd_argreg;
int second_pass;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
/* Walk through the list of args and determine how large a temporary
stack is required. Need to take care here as structs may be
passed on the stack, and we have to to push them. On the second
pass, do the store. */
nstack = 0;
fp = sp;
for (second_pass = 0; second_pass < 2; second_pass++)
{
/* Compute the FP using the information computed during the
first pass. */
if (second_pass)
fp = sp - nstack;
simd_argreg = 0;
argreg = ARM_A1_REGNUM;
nstack = 0;
/* The struct_return pointer occupies the first parameter
passing register. */
if (struct_return)
{
if (second_pass)
{
if (arm_debug)
fprintf_unfiltered (gdb_stdlog,
"struct return in %s = 0x%s\n",
REGISTER_NAME (argreg),
paddr (struct_addr));
write_register (argreg, struct_addr);
}
argreg++;
}
for (argnum = 0; argnum < nargs; argnum++)
{
int len;
struct type *arg_type;
struct type *target_type;
enum type_code typecode;
char *val;
arg_type = check_typedef (VALUE_TYPE (args[argnum]));
len = TYPE_LENGTH (arg_type);
target_type = TYPE_TARGET_TYPE (arg_type);
typecode = TYPE_CODE (arg_type);
val = VALUE_CONTENTS (args[argnum]);
/* If the argument is a pointer to a function, and it is a
Thumb function, create a LOCAL copy of the value and set
the THUMB bit in it. */
if (second_pass
&& TYPE_CODE_PTR == typecode
&& target_type != NULL
&& TYPE_CODE_FUNC == TYPE_CODE (target_type))
{
CORE_ADDR regval = extract_address (val, len);
if (arm_pc_is_thumb (regval))
{
val = alloca (len);
store_address (val, len, MAKE_THUMB_ADDR (regval));
}
}
/* Copy the argument to general registers or the stack in
register-sized pieces. Large arguments are split between
registers and stack. */
while (len > 0)
{
int partial_len = len < REGISTER_SIZE ? len : REGISTER_SIZE;
if (argreg <= ARM_LAST_ARG_REGNUM)
{
/* The argument is being passed in a general purpose
register. */
if (second_pass)
{
CORE_ADDR regval = extract_address (val,
partial_len);
if (arm_debug)
fprintf_unfiltered (gdb_stdlog,
"arg %d in %s = 0x%s\n",
argnum,
REGISTER_NAME (argreg),
phex (regval, REGISTER_SIZE));
write_register (argreg, regval);
}
argreg++;
}
else
{
if (second_pass)
{
/* Push the arguments onto the stack. */
if (arm_debug)
fprintf_unfiltered (gdb_stdlog,
"arg %d @ 0x%s + %d\n",
argnum, paddr (fp), nstack);
write_memory (fp + nstack, val, REGISTER_SIZE);
}
nstack += REGISTER_SIZE;
}
len -= partial_len;
val += partial_len;
}
}
}
/* Return the bottom of the argument list (pointed to by fp). */
return fp;
}
/* Pop the current frame. So long as the frame info has been
initialized properly (see arm_init_extra_frame_info), this code
works for dummy frames as well as regular frames. I.e, there's no
@ -1499,6 +1368,161 @@ arm_pop_frame (void)
flush_cached_frames ();
}
/* When arguments must be pushed onto the stack, they go on in reverse
order. The code below implements a FILO (stack) to do this. */
struct stack_item
{
int len;
struct stack_item *prev;
void *data;
};
static struct stack_item *
push_stack_item (struct stack_item *prev, void *contents, int len)
{
struct stack_item *si;
si = xmalloc (sizeof (struct stack_item));
si->data = malloc (len);
si->len = len;
si->prev = prev;
memcpy (si->data, contents, len);
return si;
}
static struct stack_item *
pop_stack_item (struct stack_item *si)
{
struct stack_item *dead = si;
si = si->prev;
xfree (dead->data);
xfree (dead);
return si;
}
/* We currently only support passing parameters in integer registers. This
conforms with GCC's default model. Several other variants exist and
we should probably support some of them based on the selected ABI. */
static CORE_ADDR
arm_push_dummy_call (struct gdbarch *gdbarch, struct regcache *regcache,
CORE_ADDR dummy_addr, int nargs, struct value **args,
CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr)
{
int argnum;
int argreg;
int nstack;
struct stack_item *si = NULL;
/* Set the return address. For the ARM, the return breakpoint is always
at DUMMY_ADDR. */
/* XXX Fix for Thumb. */
regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, dummy_addr);
/* Walk through the list of args and determine how large a temporary
stack is required. Need to take care here as structs may be
passed on the stack, and we have to to push them. */
nstack = 0;
argreg = ARM_A1_REGNUM;
nstack = 0;
/* Some platforms require a double-word aligned stack. Make sure sp
is correctly aligned before we start. We always do this even if
it isn't really needed -- it can never hurt things. */
sp &= ~(CORE_ADDR)(2 * REGISTER_SIZE - 1);
/* The struct_return pointer occupies the first parameter
passing register. */
if (struct_return)
{
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n",
REGISTER_NAME (argreg), paddr (struct_addr));
regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
argreg++;
}
for (argnum = 0; argnum < nargs; argnum++)
{
int len;
struct type *arg_type;
struct type *target_type;
enum type_code typecode;
char *val;
arg_type = check_typedef (VALUE_TYPE (args[argnum]));
len = TYPE_LENGTH (arg_type);
target_type = TYPE_TARGET_TYPE (arg_type);
typecode = TYPE_CODE (arg_type);
val = VALUE_CONTENTS (args[argnum]);
/* If the argument is a pointer to a function, and it is a
Thumb function, create a LOCAL copy of the value and set
the THUMB bit in it. */
if (TYPE_CODE_PTR == typecode
&& target_type != NULL
&& TYPE_CODE_FUNC == TYPE_CODE (target_type))
{
CORE_ADDR regval = extract_address (val, len);
if (arm_pc_is_thumb (regval))
{
val = alloca (len);
store_address (val, len, MAKE_THUMB_ADDR (regval));
}
}
/* Copy the argument to general registers or the stack in
register-sized pieces. Large arguments are split between
registers and stack. */
while (len > 0)
{
int partial_len = len < REGISTER_SIZE ? len : REGISTER_SIZE;
if (argreg <= ARM_LAST_ARG_REGNUM)
{
/* The argument is being passed in a general purpose
register. */
CORE_ADDR regval = extract_address (val, partial_len);
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "arg %d in %s = 0x%s\n",
argnum, REGISTER_NAME (argreg),
phex (regval, REGISTER_SIZE));
regcache_cooked_write_unsigned (regcache, argreg, regval);
argreg++;
}
else
{
/* Push the arguments onto the stack. */
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n",
argnum, nstack);
si = push_stack_item (si, val, REGISTER_SIZE);
nstack += REGISTER_SIZE;
}
len -= partial_len;
val += partial_len;
}
}
/* If we have an odd number of words to push, then decrement the stack
by one word now, so first stack argument will be dword aligned. */
if (nstack & 4)
sp -= 4;
while (si)
{
sp -= si->len;
write_memory (sp, si->data, si->len);
si = pop_stack_item (si);
}
/* Finally, update teh SP register. */
regcache_cooked_write_unsigned (regcache, ARM_SP_REGNUM, sp);
return sp;
}
static void
print_fpu_flags (int flags)
{
@ -2456,15 +2480,6 @@ arm_store_return_value (struct type *type, struct regcache *regs,
}
}
/* Store the address of the place in which to copy the structure the
subroutine will return. This is called from call_function. */
static void
arm_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
{
write_register (ARM_A1_REGNUM, addr);
}
static int
arm_get_longjmp_target (CORE_ADDR *pc)
{
@ -2929,8 +2944,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
set_gdbarch_push_return_address (gdbarch, arm_push_return_address);
set_gdbarch_deprecated_push_arguments (gdbarch, arm_push_arguments);
set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
/* Frame handling. */
set_gdbarch_deprecated_frame_chain_valid (gdbarch, arm_frame_chain_valid);
@ -2994,7 +3008,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Returning results. */
set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value);
set_gdbarch_store_return_value (gdbarch, arm_store_return_value);
set_gdbarch_deprecated_store_struct_return (gdbarch, arm_store_struct_return);
set_gdbarch_use_struct_convention (gdbarch, arm_use_struct_convention);
set_gdbarch_extract_struct_value_address (gdbarch,
arm_extract_struct_value_address);