Boston, MA 02111-1307, USA. */
#include "defs.h"
+#include "doublest.h"
#include "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "gdb_string.h"
#include "linespec.h"
#include "regcache.h"
-#include "doublest.h"
+#include "reggroups.h"
#include "arch-utils.h"
#include "osabi.h"
#include "block.h"
static const char *
alpha_register_name (int regno)
{
- static char *register_names[] =
+ static const char * const register_names[] =
{
"v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
"t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "fpcr",
- "pc", "vfp", "unique",
+ "pc", "", "unique"
};
if (regno < 0)
- return (NULL);
+ return NULL;
if (regno >= (sizeof(register_names) / sizeof(*register_names)))
- return (NULL);
- return (register_names[regno]);
+ return NULL;
+ return register_names[regno];
}
static int
alpha_cannot_fetch_register (int regno)
{
- return (regno == ALPHA_FP_REGNUM || regno == ALPHA_ZERO_REGNUM);
+ return regno == ALPHA_ZERO_REGNUM;
}
static int
alpha_cannot_store_register (int regno)
{
- return (regno == ALPHA_FP_REGNUM || regno == ALPHA_ZERO_REGNUM);
+ return regno == ALPHA_ZERO_REGNUM;
}
static int
static struct type *
alpha_register_virtual_type (int regno)
{
- return ((regno >= FP0_REGNUM && regno < (FP0_REGNUM+31))
- ? builtin_type_double : builtin_type_long);
+ if (regno == ALPHA_SP_REGNUM || regno == ALPHA_GP_REGNUM)
+ return builtin_type_void_data_ptr;
+ if (regno == ALPHA_PC_REGNUM)
+ return builtin_type_void_func_ptr;
+
+ /* Don't need to worry about little vs big endian until
+ some jerk tries to port to alpha-unicosmk. */
+ if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 31)
+ return builtin_type_ieee_double_little;
+
+ return builtin_type_int64;
+}
+
+/* Is REGNUM a member of REGGROUP? */
+
+static int
+alpha_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
+{
+ /* Filter out any registers eliminated, but whose regnum is
+ reserved for backward compatibility, e.g. the vfp. */
+ if (REGISTER_NAME (regnum) == NULL || *REGISTER_NAME (regnum) == '\0')
+ return 0;
+
+ /* Since we implement no pseudo registers, save/restore is equal to all. */
+ if (group == all_reggroup
+ || group == save_reggroup
+ || group == restore_reggroup)
+ return 1;
+
+ /* All other groups are non-overlapping. */
+
+ /* Since this is really a PALcode memory slot... */
+ if (regnum == ALPHA_UNIQUE_REGNUM)
+ return group == system_reggroup;
+
+ /* Force the FPCR to be considered part of the floating point state. */
+ if (regnum == ALPHA_FPCR_REGNUM)
+ return group == float_reggroup;
+
+ if (regnum >= ALPHA_FP0_REGNUM && regnum < ALPHA_FP0_REGNUM + 31)
+ return group == float_reggroup;
+ else
+ return group == general_reggroup;
}
static int
bytes or less, as the representation of integers in floating point
registers is different. */
+static void
+alpha_convert_flt_dbl (void *out, const void *in)
+{
+ DOUBLEST d = extract_typed_floating (in, builtin_type_ieee_single_little);
+ store_typed_floating (out, builtin_type_ieee_double_little, d);
+}
+
+static void
+alpha_convert_dbl_flt (void *out, const void *in)
+{
+ DOUBLEST d = extract_typed_floating (in, builtin_type_ieee_double_little);
+ store_typed_floating (out, builtin_type_ieee_single_little, d);
+}
+
static void
alpha_register_convert_to_virtual (int regnum, struct type *valtype,
char *raw_buffer, char *virtual_buffer)
{
- if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
+ if (TYPE_LENGTH (valtype) >= ALPHA_REGISTER_SIZE)
{
- memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
+ memcpy (virtual_buffer, raw_buffer, ALPHA_REGISTER_SIZE);
return;
}
+ /* Note that everything below is less than 8 bytes long. */
+
if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
- {
- double d = deprecated_extract_floating (raw_buffer, REGISTER_RAW_SIZE (regnum));
- deprecated_store_floating (virtual_buffer, TYPE_LENGTH (valtype), d);
- }
- else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
+ alpha_convert_dbl_flt (virtual_buffer, raw_buffer);
+ else if (TYPE_CODE (valtype) == TYPE_CODE_INT)
{
ULONGEST l;
- l = extract_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum));
+ l = extract_unsigned_integer (raw_buffer, ALPHA_REGISTER_SIZE);
l = ((l >> 32) & 0xc0000000) | ((l >> 29) & 0x3fffffff);
store_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype), l);
}
alpha_register_convert_to_raw (struct type *valtype, int regnum,
char *virtual_buffer, char *raw_buffer)
{
- if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
+ if (TYPE_LENGTH (valtype) >= ALPHA_REGISTER_SIZE)
{
- memcpy (raw_buffer, virtual_buffer, REGISTER_RAW_SIZE (regnum));
+ memcpy (raw_buffer, virtual_buffer, ALPHA_REGISTER_SIZE);
return;
}
+ /* Note that everything below is less than 8 bytes long. */
+
if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+ alpha_convert_flt_dbl (raw_buffer, virtual_buffer);
+ else if (TYPE_CODE (valtype) == TYPE_CODE_INT)
{
- double d = deprecated_extract_floating (virtual_buffer, TYPE_LENGTH (valtype));
- deprecated_store_floating (raw_buffer, REGISTER_RAW_SIZE (regnum), d);
- }
- else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
- {
- ULONGEST l;
- if (TYPE_UNSIGNED (valtype))
- l = extract_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype));
- else
- l = extract_signed_integer (virtual_buffer, TYPE_LENGTH (valtype));
+ ULONGEST l = unpack_long (valtype, virtual_buffer);
l = ((l & 0xc0000000) << 32) | ((l & 0x3fffffff) << 29);
- store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), l);
+ store_unsigned_integer (raw_buffer, ALPHA_REGISTER_SIZE, l);
}
else
error ("Cannot store value in floating point register");
\f
/* 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))
{
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;
}
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);
+ regcache_cooked_write (regcache, ALPHA_A0_REGNUM + i,
+ arg_reg_buffer + i*ALPHA_REGISTER_SIZE);
+ regcache_cooked_write (regcache, ALPHA_FPA0_REGNUM + i,
+ arg_reg_buffer + i*ALPHA_REGISTER_SIZE);
}
- return sp + arg_regs_size;
+ /* Finally, update the stack pointer. */
+ regcache_cooked_write_signed (regcache, ALPHA_SP_REGNUM, sp);
+
+ return sp;
}
/* Given a return value in `regbuf' with a type `valtype',
static void
alpha_store_return_value (struct type *valtype, char *valbuf)
{
- char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
+ char raw_buffer[ALPHA_REGISTER_SIZE];
int regnum = ALPHA_V0_REGNUM;
int length = TYPE_LENGTH (valtype);
if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
{
regnum = FP0_REGNUM;
- length = REGISTER_RAW_SIZE (regnum);
+ length = ALPHA_REGISTER_SIZE;
alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer);
}
else
static CORE_ADDR
alpha_extract_struct_value_address (char *regbuf)
{
- return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
- REGISTER_RAW_SIZE (ALPHA_V0_REGNUM)));
+ return (extract_unsigned_integer (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
+ REGISTER_RAW_SIZE (ALPHA_V0_REGNUM)));
}
\f
return pc + offset;
}
-\f
-/* 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 };
-
\f
/* Figure out where the longjmp will land.
We expect the first arg to be a pointer to the jmp_buf structure from
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
CORE_ADDR jb_addr;
- char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
+ char raw_buffer[ALPHA_REGISTER_SIZE];
jb_addr = read_register (ALPHA_A0_REGNUM);
raw_buffer, tdep->jb_elt_size))
return 0;
- *pc = extract_address (raw_buffer, tdep->jb_elt_size);
+ *pc = extract_unsigned_integer (raw_buffer, tdep->jb_elt_size);
return 1;
}
/* Register info */
set_gdbarch_num_regs (gdbarch, ALPHA_NUM_REGS);
set_gdbarch_sp_regnum (gdbarch, ALPHA_SP_REGNUM);
- set_gdbarch_deprecated_fp_regnum (gdbarch, ALPHA_FP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, ALPHA_PC_REGNUM);
set_gdbarch_fp0_regnum (gdbarch, ALPHA_FP0_REGNUM);
set_gdbarch_register_name (gdbarch, alpha_register_name);
- set_gdbarch_deprecated_register_size (gdbarch, ALPHA_REGISTER_SIZE);
- set_gdbarch_deprecated_register_bytes (gdbarch, ALPHA_REGISTER_BYTES);
set_gdbarch_register_byte (gdbarch, alpha_register_byte);
set_gdbarch_register_raw_size (gdbarch, alpha_register_raw_size);
- set_gdbarch_deprecated_max_register_raw_size (gdbarch, ALPHA_MAX_REGISTER_RAW_SIZE);
set_gdbarch_register_virtual_size (gdbarch, alpha_register_virtual_size);
- set_gdbarch_deprecated_max_register_virtual_size (gdbarch,
- ALPHA_MAX_REGISTER_VIRTUAL_SIZE);
set_gdbarch_register_virtual_type (gdbarch, alpha_register_virtual_type);
set_gdbarch_cannot_fetch_register (gdbarch, alpha_cannot_fetch_register);
alpha_register_convert_to_virtual);
set_gdbarch_register_convert_to_raw (gdbarch, alpha_register_convert_to_raw);
+ set_gdbarch_register_reggroup_p (gdbarch, alpha_register_reggroup_p);
+
/* Prologue heuristics. */
set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue);
+ /* Disassembler. */
+ set_gdbarch_print_insn (gdbarch, print_insn_alpha);
+
/* Call info. */
set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
set_gdbarch_frameless_function_invocation (gdbarch,
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);
struct cmd_list_element *c;
gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, NULL);
- deprecated_tm_print_insn = print_insn_alpha;
/* Let the user set the fence post for heuristic_proc_start. */