#include "gdb_assert.h"
+static int arm_debug;
+
/* Each OS has a different mechanism for accessing the various
registers stored in the sigcontext structure.
arm_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
- char *fp;
- int argnum, argreg, nstack_size;
+ 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. */
- nstack_size = -4 * REGISTER_SIZE; /* Some arguments go into A1-A4. */
- if (struct_return) /* The struct address goes in A1. */
- nstack_size += REGISTER_SIZE;
-
- /* Walk through the arguments and add their size to nstack_size. */
- for (argnum = 0; argnum < nargs; argnum++)
- {
- int len;
- struct type *arg_type;
-
- arg_type = check_typedef (VALUE_TYPE (args[argnum]));
- len = TYPE_LENGTH (arg_type);
-
- nstack_size += len;
- }
-
- /* Allocate room on the stack, and initialize our stack frame
- pointer. */
- fp = NULL;
- if (nstack_size > 0)
- {
- sp -= nstack_size;
- fp = (char *) sp;
- }
-
- /* Initialize the integer argument register pointer. */
- argreg = ARM_A1_REGNUM;
-
- /* The struct_return pointer occupies the first parameter passing
- register. */
- if (struct_return)
- write_register (argreg++, struct_addr);
-
- /* Process arguments from left to right. Store as many as allowed
- in the parameter passing registers (A1-A4), and save the rest on
- the temporary stack. */
- for (argnum = 0; argnum < nargs; argnum++)
+ 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++)
{
- int len;
- char *val;
- CORE_ADDR regval;
- enum type_code typecode;
- struct type *arg_type, *target_type;
-
- arg_type = check_typedef (VALUE_TYPE (args[argnum]));
- target_type = TYPE_TARGET_TYPE (arg_type);
- len = TYPE_LENGTH (arg_type);
- typecode = TYPE_CODE (arg_type);
- val = (char *) VALUE_CONTENTS (args[argnum]);
-
-#if 1
- /* I don't know why this code was disable. The only logical use
- for a function pointer is to call that function, so setting
- the mode bit is perfectly fine. FN */
- /* If the argument is a pointer to a function, and it is a Thumb
- function, set the low bit of the pointer. */
- if (TYPE_CODE_PTR == typecode
- && NULL != target_type
- && TYPE_CODE_FUNC == TYPE_CODE (target_type))
+ /* 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)
{
- CORE_ADDR regval = extract_address (val, len);
- if (arm_pc_is_thumb (regval))
- store_address (val, len, MAKE_THUMB_ADDR (regval));
+ 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++;
}
-#endif
- /* 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)
+ 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))
{
- /* It's an argument being passed in a general register. */
- regval = extract_address (val, partial_len);
- write_register (argreg++, regval);
+ CORE_ADDR regval = extract_address (val, len);
+ if (arm_pc_is_thumb (regval))
+ {
+ val = alloca (len);
+ store_address (val, len, MAKE_THUMB_ADDR (regval));
+ }
}
- else
+
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ while (len > 0)
{
- /* Push the arguments onto the stack. */
- write_memory ((CORE_ADDR) fp, val, REGISTER_SIZE);
- fp += REGISTER_SIZE;
+ 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;
}
- len -= partial_len;
- val += partial_len;
}
}
- /* Return adjusted stack pointer. */
- return sp;
+ /* Return the botom of the argument list (pointed to by fp). */
+ return fp;
}
/* Pop the current frame. So long as the frame info has been
prologue_cache.saved_regs = NULL;
prologue_cache.extra_info = (struct frame_extra_info *)
xcalloc (1, sizeof (struct frame_extra_info));
+
+ /* Debugging flag. */
+ add_show_from_set (add_set_cmd ("arm", class_maintenance, var_zinteger,
+ &arm_debug, "Set arm debugging.\n\
+When non-zero, arm specific debugging is enabled.", &setdebuglist),
+ &showdebuglist);
}