* alpha-tdep.c (alpha_push_dummy_call): Transmography from

alpha_push_arguments.  Don't dump argument register data to
        the target stack.  Fix float and 128-bit long double semantics.
        Store $t12 and $ra as specified by the ABI.  Use regcache everywhere.
        (alpha_fix_call_dummy): Remove.
        (alpha_call_dummy_words): Remove.
        (alpha_gdbarch_init): Kill deprecated call hooks; add push_dummy_call.
This commit is contained in:
Richard Henderson 2003-06-01 16:02:50 +00:00
parent f1a559ae83
commit c88e30c0a0
2 changed files with 95 additions and 50 deletions

View file

@ -1,3 +1,13 @@
2003-06-01 Richard Henderson <rth@redhat.com>
* alpha-tdep.c (alpha_push_dummy_call): Transmography from
alpha_push_arguments. Don't dump argument register data to
the target stack. Fix float and 128-bit long double semantics.
Store $t12 and $ra as specified by the ABI. Use regcache everywhere.
(alpha_fix_call_dummy): Remove.
(alpha_call_dummy_words): Remove.
(alpha_gdbarch_init): Kill deprecated call hooks; add push_dummy_call.
2003-06-01 Richard Henderson <rth@redhat.com>
* alpha-linux-tdep.c (alpha_linux_init_abi): Install dwarf2 unwinder.

View file

@ -173,38 +173,50 @@ alpha_register_convert_to_raw (struct type *valtype, int regnum,
/* The alpha passes the first six arguments in the registers, the rest on
the stack. The register arguments are eventually transferred to the
argument transfer area immediately below the stack by the called function
anyway. So we `push' at least six arguments on the stack, `reload' the
argument registers and then adjust the stack pointer to point past the
sixth argument. This algorithm simplifies the passing of a large struct
which extends from the registers to the stack.
the stack. The register arguments are stored in ARG_REG_BUFFER, and
then moved into the register file; this simplifies the passing of a
large struct which extends from the registers to the stack, plus avoids
three ptrace invocations per word.
We don't bother tracking which register values should go in integer
regs or fp regs; we load the same values into both.
If the called function is returning a structure, the address of the
structure to be returned is passed as a hidden first argument. */
static CORE_ADDR
alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
alpha_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int i;
int accumulate_size = struct_return ? 8 : 0;
int arg_regs_size = ALPHA_NUM_ARG_REGS * 8;
struct alpha_arg
{
char *contents;
int len;
int offset;
};
struct alpha_arg *alpha_args =
(struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
struct alpha_arg *alpha_args
= (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
register struct alpha_arg *m_arg;
char raw_buffer[ALPHA_REGISTER_BYTES];
char arg_reg_buffer[ALPHA_REGISTER_SIZE * ALPHA_NUM_ARG_REGS];
int required_arg_regs;
/* The ABI places the address of the called function in T12. */
regcache_cooked_write_signed (regcache, ALPHA_T12_REGNUM, func_addr);
/* Set the return address register to point to the entry point
of the program, where a breakpoint lies in wait. */
regcache_cooked_write_signed (regcache, ALPHA_RA_REGNUM, bp_addr);
/* Lay out the arguments in memory. */
for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++)
{
struct value *arg = args[i];
struct type *arg_type = check_typedef (VALUE_TYPE (arg));
/* Cast argument to long if necessary as the compiler does it too. */
switch (TYPE_CODE (arg_type))
{
@ -219,6 +231,30 @@ alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
arg = value_cast (arg_type, arg);
}
break;
case TYPE_CODE_FLT:
/* "float" arguments loaded in registers must be passed in
register format, aka "double". */
if (accumulate_size < sizeof (arg_reg_buffer)
&& TYPE_LENGTH (arg_type) == 4)
{
arg_type = builtin_type_double;
arg = value_cast (arg_type, arg);
}
/* Tru64 5.1 has a 128-bit long double, and passes this by
invisible reference. No one else uses this data type. */
else if (TYPE_LENGTH (arg_type) == 16)
{
/* Allocate aligned storage. */
sp = (sp & -16) - 16;
/* Write the real data into the stack. */
write_memory (sp, VALUE_CONTENTS (arg), 16);
/* Construct the indirection. */
arg_type = lookup_pointer_type (arg_type);
arg = value_from_pointer (arg_type, sp);
}
break;
default:
break;
}
@ -235,33 +271,58 @@ alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
required_arg_regs = ALPHA_NUM_ARG_REGS;
/* Make room for the arguments on the stack. */
if (accumulate_size < arg_regs_size)
accumulate_size = arg_regs_size;
if (accumulate_size < sizeof(arg_reg_buffer))
accumulate_size = 0;
else
accumulate_size -= sizeof(arg_reg_buffer);
sp -= accumulate_size;
/* Keep sp aligned to a multiple of 16 as the compiler does it too. */
/* Keep sp aligned to a multiple of 16 as the ABI requires. */
sp &= ~15;
/* `Push' arguments on the stack. */
for (i = nargs; m_arg--, --i >= 0;)
write_memory (sp + m_arg->offset, m_arg->contents, m_arg->len);
if (struct_return)
{
store_unsigned_integer (raw_buffer, ALPHA_REGISTER_BYTES, struct_addr);
write_memory (sp, raw_buffer, ALPHA_REGISTER_BYTES);
char *contents = m_arg->contents;
int offset = m_arg->offset;
int len = m_arg->len;
/* Copy the bytes destined for registers into arg_reg_buffer. */
if (offset < sizeof(arg_reg_buffer))
{
if (offset + len <= sizeof(arg_reg_buffer))
{
memcpy (arg_reg_buffer + offset, contents, len);
continue;
}
else
{
int tlen = sizeof(arg_reg_buffer) - offset;
memcpy (arg_reg_buffer + offset, contents, tlen);
offset += tlen;
contents += tlen;
len -= tlen;
}
}
/* Everything else goes to the stack. */
write_memory (sp + offset - sizeof(arg_reg_buffer), contents, len);
}
if (struct_return)
store_unsigned_integer (arg_reg_buffer, ALPHA_REGISTER_SIZE, struct_addr);
/* Load the argument registers. */
for (i = 0; i < required_arg_regs; i++)
{
LONGEST val;
val = read_memory_integer (sp + i * 8, ALPHA_REGISTER_BYTES);
write_register (ALPHA_A0_REGNUM + i, val);
write_register (ALPHA_FPA0_REGNUM + i, val);
val = extract_unsigned_integer (arg_reg_buffer + i*ALPHA_REGISTER_SIZE,
ALPHA_REGISTER_SIZE);
regcache_cooked_write_signed (regcache, ALPHA_A0_REGNUM + i, val);
regcache_cooked_write_signed (regcache, ALPHA_FPA0_REGNUM + i, val);
}
return sp + arg_regs_size;
return sp;
}
/* Given a return value in `regbuf' with a type `valtype',
@ -437,28 +498,6 @@ alpha_skip_prologue (CORE_ADDR pc)
return pc + offset;
}
/* Construct an inferior call to FUN. For Alpha this is as simple as
initializing the RA and T12 registers; everything else is set up by
generic code. */
static void
alpha_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
struct value **args, struct type *type, int gcc_p)
{
CORE_ADDR bp_address = CALL_DUMMY_ADDRESS ();
if (bp_address == 0)
error ("no place to put call");
write_register (ALPHA_RA_REGNUM, bp_address);
write_register (ALPHA_T12_REGNUM, fun);
}
/* On the Alpha, the call dummy code is never copied to user space
(see alpha_fix_call_dummy() above). The contents of this do not
matter. */
LONGEST alpha_call_dummy_words[] = { 0 };
/* Figure out where the longjmp will land.
We expect the first arg to be a pointer to the jmp_buf structure from
@ -1242,11 +1281,7 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
alpha_extract_struct_value_address);
/* Settings for calling functions in the inferior. */
set_gdbarch_deprecated_push_arguments (gdbarch, alpha_push_arguments);
set_gdbarch_deprecated_call_dummy_words (gdbarch, alpha_call_dummy_words);
set_gdbarch_deprecated_sizeof_call_dummy_words (gdbarch, 0);
set_gdbarch_deprecated_pc_in_call_dummy (gdbarch, deprecated_pc_in_call_dummy_at_entry_point);
set_gdbarch_deprecated_fix_call_dummy (gdbarch, alpha_fix_call_dummy);
set_gdbarch_push_dummy_call (gdbarch, alpha_push_dummy_call);
/* Methods for saving / extracting a dummy frame's ID. */
set_gdbarch_unwind_dummy_id (gdbarch, alpha_unwind_dummy_id);