/* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger.
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- Free Software Foundation, Inc.
+
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2005 Free Software Foundation, Inc.
This file is part of GDB.
Boston, MA 02111-1307, USA. */
#include "defs.h"
+#include "doublest.h"
#include "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
+#include "dwarf2-frame.h"
#include "inferior.h"
#include "symtab.h"
#include "value.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"
+#include "infcall.h"
#include "elf-bfd.h"
#include "alpha-tdep.h"
\f
+/* Return the name of the REGNO register.
+
+ An empty name corresponds to a register number that used to
+ be used for a virtual register. That virtual register has
+ been removed, but the index is still reserved to maintain
+ compatibility with existing remote alpha targets. */
+
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
+ || strlen (alpha_register_name (regno)) == 0);
}
static int
alpha_cannot_store_register (int regno)
{
- return (regno == ALPHA_FP_REGNUM || regno == ALPHA_ZERO_REGNUM);
+ return (regno == ALPHA_ZERO_REGNUM
+ || strlen (alpha_register_name (regno)) == 0);
}
-static int
-alpha_register_convertible (int regno)
+static struct type *
+alpha_register_type (struct gdbarch *gdbarch, int regno)
{
- return (regno >= FP0_REGNUM && regno <= FP0_REGNUM + 31);
+ 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 >= ALPHA_FP0_REGNUM && regno < ALPHA_FP0_REGNUM + 31)
+ return builtin_type_ieee_double_little;
+
+ return builtin_type_int64;
}
-static struct type *
-alpha_register_virtual_type (int regno)
+/* Is REGNUM a member of REGGROUP? */
+
+static int
+alpha_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
{
- return ((regno >= FP0_REGNUM && regno < (FP0_REGNUM+31))
- ? builtin_type_double : builtin_type_long);
+ /* 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;
+
+ if (group == all_reggroup)
+ return 1;
+
+ /* Zero should not be saved or restored. Technically it is a general
+ register (just as $f31 would be a float if we represented it), but
+ there's no point displaying it during "info regs", so leave it out
+ of all groups except for "all". */
+ if (regnum == ALPHA_ZERO_REGNUM)
+ return 0;
+
+ /* All other registers are saved and restored. */
+ if (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
return (regno * 8);
}
-static int
-alpha_register_raw_size (int regno)
+/* The following represents exactly the conversion performed by
+ the LDS instruction. This applies to both single-precision
+ floating point and 32-bit integers. */
+
+static void
+alpha_lds (void *out, const void *in)
{
- return 8;
+ ULONGEST mem = extract_unsigned_integer (in, 4);
+ ULONGEST frac = (mem >> 0) & 0x7fffff;
+ ULONGEST sign = (mem >> 31) & 1;
+ ULONGEST exp_msb = (mem >> 30) & 1;
+ ULONGEST exp_low = (mem >> 23) & 0x7f;
+ ULONGEST exp, reg;
+
+ exp = (exp_msb << 10) | exp_low;
+ if (exp_msb)
+ {
+ if (exp_low == 0x7f)
+ exp = 0x7ff;
+ }
+ else
+ {
+ if (exp_low != 0x00)
+ exp |= 0x380;
+ }
+
+ reg = (sign << 63) | (exp << 52) | (frac << 29);
+ store_unsigned_integer (out, 8, reg);
}
-static int
-alpha_register_virtual_size (int regno)
+/* Similarly, this represents exactly the conversion performed by
+ the STS instruction. */
+
+static void
+alpha_sts (void *out, const void *in)
{
- return 8;
+ ULONGEST reg, mem;
+
+ reg = extract_unsigned_integer (in, 8);
+ mem = ((reg >> 32) & 0xc0000000) | ((reg >> 29) & 0x3fffffff);
+ store_unsigned_integer (out, 4, mem);
}
/* The alpha needs a conversion between register and memory format if the
bytes or less, as the representation of integers in floating point
registers is different. */
-static void
-alpha_register_convert_to_virtual (int regnum, struct type *valtype,
- char *raw_buffer, char *virtual_buffer)
+static int
+alpha_convert_register_p (int regno, struct type *type)
{
- if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
- {
- memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
- return;
- }
-
- 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)
- {
- ULONGEST l;
- l = extract_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum));
- l = ((l >> 32) & 0xc0000000) | ((l >> 29) & 0x3fffffff);
- store_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype), l);
- }
- else
- error ("Cannot retrieve value from floating point register");
+ return (regno >= ALPHA_FP0_REGNUM && regno < ALPHA_FP0_REGNUM + 31);
}
static void
-alpha_register_convert_to_raw (struct type *valtype, int regnum,
- char *virtual_buffer, char *raw_buffer)
+alpha_register_to_value (struct frame_info *frame, int regnum,
+ struct type *valtype, gdb_byte *out)
{
- if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
+ char in[MAX_REGISTER_SIZE];
+ frame_register_read (frame, regnum, in);
+ switch (TYPE_LENGTH (valtype))
{
- memcpy (raw_buffer, virtual_buffer, REGISTER_RAW_SIZE (regnum));
- return;
+ case 4:
+ alpha_sts (out, in);
+ break;
+ case 8:
+ memcpy (out, in, 8);
+ break;
+ default:
+ error (_("Cannot retrieve value from floating point register"));
}
+}
- if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
- {
- 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)
+static void
+alpha_value_to_register (struct frame_info *frame, int regnum,
+ struct type *valtype, const gdb_byte *in)
+{
+ char out[MAX_REGISTER_SIZE];
+ switch (TYPE_LENGTH (valtype))
{
- 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));
- l = ((l & 0xc0000000) << 32) | ((l & 0x3fffffff) << 29);
- store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), l);
+ case 4:
+ alpha_lds (out, in);
+ break;
+ case 8:
+ memcpy (out, in, 8);
+ break;
+ default:
+ error (_("Cannot store value in floating point register"));
}
- else
- error ("Cannot store value in floating point register");
+ put_frame_register (frame, regnum, out);
}
\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, struct value *function,
+ 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));
- register struct alpha_arg *m_arg;
- char raw_buffer[ALPHA_REGISTER_BYTES];
+ struct alpha_arg *alpha_args
+ = (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
+ struct alpha_arg *m_arg;
+ char arg_reg_buffer[ALPHA_REGISTER_SIZE * ALPHA_NUM_ARG_REGS];
int required_arg_regs;
+ CORE_ADDR func_addr = find_function_addr (function, NULL);
+
+ /* 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));
+ 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))
{
case TYPE_CODE_CHAR:
case TYPE_CODE_RANGE:
case TYPE_CODE_ENUM:
- if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long))
+ if (TYPE_LENGTH (arg_type) == 4)
{
- arg_type = builtin_type_long;
+ /* 32-bit values must be sign-extended to 64 bits
+ even if the base data type is unsigned. */
+ arg_type = builtin_type_int32;
arg = value_cast (arg_type, arg);
}
+ if (TYPE_LENGTH (arg_type) < ALPHA_REGISTER_SIZE)
+ {
+ arg_type = builtin_type_int64;
+ 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_ieee_double_little;
+ 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;
+
+ case TYPE_CODE_COMPLEX:
+ /* ??? The ABI says that complex values are passed as two
+ separate scalar values. This distinction only matters
+ for complex float. However, GCC does not implement this. */
+
+ /* Tru64 5.1 has a 128-bit long double, and passes this by
+ invisible reference. */
+ if (TYPE_LENGTH (arg_type) == 32)
+ {
+ /* Allocate aligned storage. */
+ sp = (sp & -16) - 16;
+
+ /* Write the real data into the stack. */
+ write_memory (sp, value_contents (arg), 32);
+
+ /* Construct the indirection. */
+ arg_type = lookup_pointer_type (arg_type);
+ arg = value_from_pointer (arg_type, sp);
+ }
break;
+
default:
break;
}
m_arg->len = TYPE_LENGTH (arg_type);
m_arg->offset = accumulate_size;
accumulate_size = (accumulate_size + m_arg->len + 7) & ~7;
- m_arg->contents = VALUE_CONTENTS (arg);
+ m_arg->contents = value_contents_writeable (arg);
}
/* Determine required argument register loads, loading an argument register
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;
-}
-
-/* Given a return value in `regbuf' with a type `valtype',
- extract and copy its value into `valbuf'. */
+ /* Finally, update the stack pointer. */
+ regcache_cooked_write_signed (regcache, ALPHA_SP_REGNUM, sp);
-static void
-alpha_extract_return_value (struct type *valtype,
- char regbuf[ALPHA_REGISTER_BYTES], char *valbuf)
-{
- if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
- alpha_register_convert_to_virtual (FP0_REGNUM, valtype,
- regbuf + REGISTER_BYTE (FP0_REGNUM),
- valbuf);
- else
- memcpy (valbuf, regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
- TYPE_LENGTH (valtype));
+ return sp;
}
-/* Given a return value in `regbuf' with a type `valtype',
- write its value into the appropriate register. */
+/* Extract from REGCACHE the value about to be returned from a function
+ and copy it into VALBUF. */
static void
-alpha_store_return_value (struct type *valtype, char *valbuf)
+alpha_extract_return_value (struct type *valtype, struct regcache *regcache,
+ gdb_byte *valbuf)
{
- char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
- int regnum = ALPHA_V0_REGNUM;
int length = TYPE_LENGTH (valtype);
+ char raw_buffer[ALPHA_REGISTER_SIZE];
+ ULONGEST l;
- if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+ switch (TYPE_CODE (valtype))
{
- regnum = FP0_REGNUM;
- length = REGISTER_RAW_SIZE (regnum);
- alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer);
- }
- else
- memcpy (raw_buffer, valbuf, length);
+ case TYPE_CODE_FLT:
+ switch (length)
+ {
+ case 4:
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, raw_buffer);
+ alpha_sts (valbuf, raw_buffer);
+ break;
+
+ case 8:
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
+ break;
+
+ case 16:
+ regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l);
+ read_memory (l, valbuf, 16);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown floating point width"));
+ }
+ break;
+
+ case TYPE_CODE_COMPLEX:
+ switch (length)
+ {
+ case 8:
+ /* ??? This isn't correct wrt the ABI, but it's what GCC does. */
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
+ break;
+
+ case 16:
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
+ regcache_cooked_read (regcache, ALPHA_FP0_REGNUM+1,
+ (char *)valbuf + 8);
+ break;
+
+ case 32:
+ regcache_cooked_read_signed (regcache, ALPHA_V0_REGNUM, &l);
+ read_memory (l, valbuf, 32);
+ break;
- deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length);
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown floating point width"));
+ }
+ break;
+
+ default:
+ /* Assume everything else degenerates to an integer. */
+ regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l);
+ store_unsigned_integer (valbuf, length, l);
+ break;
+ }
}
-static int
-alpha_use_struct_convention (int gcc_p, struct type *type)
+/* Extract from REGCACHE the address of a structure about to be returned
+ from a function. */
+
+static CORE_ADDR
+alpha_extract_struct_value_address (struct regcache *regcache)
{
- /* Structures are returned by ref in extra arg0. */
- return 1;
+ ULONGEST addr;
+ regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &addr);
+ return addr;
}
+/* Insert the given value into REGCACHE as if it was being
+ returned by a function. */
+
static void
-alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+alpha_store_return_value (struct type *valtype, struct regcache *regcache,
+ const gdb_byte *valbuf)
{
- /* Store the address of the place in which to copy the structure the
- subroutine will return. Handled by alpha_push_arguments. */
-}
+ int length = TYPE_LENGTH (valtype);
+ char raw_buffer[ALPHA_REGISTER_SIZE];
+ ULONGEST l;
-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)));
+ switch (TYPE_CODE (valtype))
+ {
+ case TYPE_CODE_FLT:
+ switch (length)
+ {
+ case 4:
+ alpha_lds (raw_buffer, valbuf);
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, raw_buffer);
+ break;
+
+ case 8:
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
+ break;
+
+ case 16:
+ /* FIXME: 128-bit long doubles are returned like structures:
+ by writing into indirect storage provided by the caller
+ as the first argument. */
+ error (_("Cannot set a 128-bit long double return value."));
+
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown floating point width"));
+ }
+ break;
+
+ case TYPE_CODE_COMPLEX:
+ switch (length)
+ {
+ case 8:
+ /* ??? This isn't correct wrt the ABI, but it's what GCC does. */
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
+ break;
+
+ case 16:
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
+ regcache_cooked_write (regcache, ALPHA_FP0_REGNUM+1,
+ (const char *)valbuf + 8);
+ break;
+
+ case 32:
+ /* FIXME: 128-bit long doubles are returned like structures:
+ by writing into indirect storage provided by the caller
+ as the first argument. */
+ error (_("Cannot set a 128-bit long double return value."));
+
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown floating point width"));
+ }
+ break;
+
+ default:
+ /* Assume everything else degenerates to an integer. */
+ /* 32-bit values must be sign-extended to 64 bits
+ even if the base data type is unsigned. */
+ if (length == 4)
+ valtype = builtin_type_int32;
+ l = unpack_long (valtype, valbuf);
+ regcache_cooked_write_unsigned (regcache, ALPHA_V0_REGNUM, l);
+ break;
+ }
}
\f
char buf[4];
int status;
- status = read_memory_nobpt (pc, buf, 4);
+ status = deprecated_read_memory_nobpt (pc, buf, 4);
if (status)
memory_error (status, pc);
return extract_unsigned_integer (buf, 4);
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;
}
return info;
}
-/* Return the address of REGNO in a sigtramp frame. Since this is all
- arithmetic, it doesn't seem worthwhile to cache it. */
-
-#ifndef SIGFRAME_PC_OFF
-#define SIGFRAME_PC_OFF (2 * 8)
-#define SIGFRAME_REGSAVE_OFF (4 * 8)
-#define SIGFRAME_FPREGSAVE_OFF (SIGFRAME_REGSAVE_OFF + 32 * 8 + 8)
-#endif
+/* Return the address of REGNUM in a sigtramp frame. Since this is
+ all arithmetic, it doesn't seem worthwhile to cache it. */
static CORE_ADDR
-alpha_sigtramp_register_address (CORE_ADDR sigcontext_addr, unsigned int regno)
+alpha_sigtramp_register_address (CORE_ADDR sigcontext_addr, int regnum)
{
- if (regno < 32)
- return sigcontext_addr + SIGFRAME_REGSAVE_OFF + regno * 8;
- if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
- return sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + regno * 8;
- if (regno == PC_REGNUM)
- return sigcontext_addr + SIGFRAME_PC_OFF;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (regnum >= 0 && regnum < 32)
+ return sigcontext_addr + tdep->sc_regs_offset + regnum * 8;
+ else if (regnum >= ALPHA_FP0_REGNUM && regnum < ALPHA_FP0_REGNUM + 32)
+ return sigcontext_addr + tdep->sc_fpregs_offset + regnum * 8;
+ else if (regnum == ALPHA_PC_REGNUM)
+ return sigcontext_addr + tdep->sc_pc_offset;
return 0;
}
/* The stack address is trivially read from the sigcontext. */
stack_addr = alpha_sigtramp_register_address (info->sigcontext_addr,
ALPHA_SP_REGNUM);
- stack_addr = read_memory_unsigned_integer (stack_addr, ALPHA_REGISTER_SIZE);
+ stack_addr = get_frame_memory_unsigned (next_frame, stack_addr,
+ ALPHA_REGISTER_SIZE);
*this_id = frame_id_build (stack_addr, code_addr);
}
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *bufferp)
+ int *realnump, gdb_byte *bufferp)
{
struct alpha_sigtramp_unwind_cache *info
= alpha_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
*addrp = addr;
*realnump = -1;
if (bufferp != NULL)
- read_memory (addr, bufferp, ALPHA_REGISTER_SIZE);
+ get_frame_memory (next_frame, addr, bufferp, ALPHA_REGISTER_SIZE);
return;
}
}
};
static const struct frame_unwind *
-alpha_sigtramp_frame_p (CORE_ADDR pc)
+alpha_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
char *name;
- /* We shouldn't even bother to try if the OSABI didn't register
- a sigcontext_addr handler. */
- if (!gdbarch_tdep (current_gdbarch)->sigcontext_addr)
+ /* NOTE: cagney/2004-04-30: Do not copy/clone this code. Instead
+ look at tramp-frame.h and other simplier per-architecture
+ sigtramp unwinders. */
+
+ /* We shouldn't even bother to try if the OSABI didn't register a
+ sigcontext_addr handler or pc_in_sigtramp hander. */
+ if (gdbarch_tdep (current_gdbarch)->sigcontext_addr == NULL)
+ return NULL;
+ if (gdbarch_tdep (current_gdbarch)->pc_in_sigtramp == NULL)
return NULL;
/* Otherwise we should be in a signal frame. */
find_pc_partial_function (pc, &name, NULL, NULL);
- if (PC_IN_SIGTRAMP (pc, name))
+ if (gdbarch_tdep (current_gdbarch)->pc_in_sigtramp (pc, name))
return &alpha_sigtramp_frame_unwind;
return NULL;
static int blurb_printed = 0;
if (fence == tdep->vm_min_address)
- warning ("Hit beginning of text section without finding");
+ warning (_("Hit beginning of text section without finding \
+enclosing function for address 0x%s"), paddr_nz (orig_pc));
else
- warning ("Hit heuristic-fence-post without finding");
- warning ("enclosing function for address 0x%s", paddr_nz (orig_pc));
+ warning (_("Hit heuristic-fence-post without finding \
+enclosing function for address 0x%s"), paddr_nz (orig_pc));
if (!blurb_printed)
{
- printf_filtered ("\
+ printf_filtered (_("\
This warning occurs if you are debugging a function without any symbols\n\
(for example, in a stripped executable). In that case, you may wish to\n\
increase the size of the search with the `set heuristic-fence-post' command.\n\
\n\
Otherwise, you told GDB there was a function where there isn't one, or\n\
-(more likely) you have encountered a bug in GDB.\n");
+(more likely) you have encountered a bug in GDB.\n"));
blurb_printed = 1;
}
}
{
reg = (word & 0x03e00000) >> 21;
+ /* Ignore this instruction if we have already encountered
+ an instruction saving the same register earlier in the
+ function code. The current instruction does not tell
+ us where the original value upon function entry is saved.
+ All it says is that the function we are scanning reused
+ that register for some computation of its own, and is now
+ saving its result. */
+ if (info->saved_regs[reg])
+ continue;
+
if (reg == 31)
continue;
struct alpha_heuristic_unwind_cache *info
= alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
- /* This is meant to halt the backtrace at "_start". Make sure we
- don't halt it at a generic dummy frame. */
- if (inside_entry_file (info->start_pc))
- return;
-
*this_id = frame_id_build (info->vfp, info->start_pc);
}
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *bufferp)
+ int *realnump, gdb_byte *bufferp)
{
struct alpha_heuristic_unwind_cache *info
= alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
*addrp = info->saved_regs[regnum];
*realnump = -1;
if (bufferp != NULL)
- read_memory (*addrp, bufferp, ALPHA_REGISTER_SIZE);
+ get_frame_memory (next_frame, *addrp, bufferp, ALPHA_REGISTER_SIZE);
return;
}
}
/* Otherwise assume the next frame has the same register value. */
- frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
- realnump, bufferp);
+ frame_register_unwind (next_frame, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
}
static const struct frame_unwind alpha_heuristic_frame_unwind = {
};
static const struct frame_unwind *
-alpha_heuristic_frame_p (CORE_ADDR pc)
+alpha_heuristic_frame_sniffer (struct frame_info *next_frame)
{
return &alpha_heuristic_frame_unwind;
}
}
\f
-/* ALPHA stack frames are almost impenetrable. When execution stops,
- we basically have to look at symbol information for the function
- that we stopped in, which tells us *which* register (if any) is
- the base of the frame pointer, and what offset from that register
- the frame itself is at.
-
- This presents a problem when trying to examine a stack in memory
- (that isn't executing at the moment), using the "frame" command. We
- don't have a PC, nor do we have any registers except SP.
-
- This routine takes two arguments, SP and PC, and tries to make the
- cached frames look as if these two arguments defined a frame on the
- cache. This allows the rest of info frame to extract the important
- arguments without difficulty. */
-
-struct frame_info *
-alpha_setup_arbitrary_frame (int argc, CORE_ADDR *argv)
-{
- if (argc != 2)
- error ("ALPHA frame specifications require two arguments: sp and pc");
-
- return create_new_frame (argv[0], argv[1]);
-}
-
/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
dummy frame. The frame ID's base needs to match the TOS value
saved by save_dummy_frame_tos(), and the PC match the dummy frame's
}
\f
+/* Helper routines for alpha*-nat.c files to move register sets to and
+ from core files. The UNIQUE pointer is allowed to be NULL, as most
+ targets don't supply this value in their core files. */
+
+void
+alpha_supply_int_regs (int regno, const void *r0_r30,
+ const void *pc, const void *unique)
+{
+ int i;
+
+ for (i = 0; i < 31; ++i)
+ if (regno == i || regno == -1)
+ regcache_raw_supply (current_regcache, i, (const char *)r0_r30 + i*8);
+
+ if (regno == ALPHA_ZERO_REGNUM || regno == -1)
+ regcache_raw_supply (current_regcache, ALPHA_ZERO_REGNUM, NULL);
+
+ if (regno == ALPHA_PC_REGNUM || regno == -1)
+ regcache_raw_supply (current_regcache, ALPHA_PC_REGNUM, pc);
+
+ if (regno == ALPHA_UNIQUE_REGNUM || regno == -1)
+ regcache_raw_supply (current_regcache, ALPHA_UNIQUE_REGNUM, unique);
+}
+
+void
+alpha_fill_int_regs (int regno, void *r0_r30, void *pc, void *unique)
+{
+ int i;
+
+ for (i = 0; i < 31; ++i)
+ if (regno == i || regno == -1)
+ regcache_raw_collect (current_regcache, i, (char *)r0_r30 + i*8);
+
+ if (regno == ALPHA_PC_REGNUM || regno == -1)
+ regcache_raw_collect (current_regcache, ALPHA_PC_REGNUM, pc);
+
+ if (unique && (regno == ALPHA_UNIQUE_REGNUM || regno == -1))
+ regcache_raw_collect (current_regcache, ALPHA_UNIQUE_REGNUM, unique);
+}
+
+void
+alpha_supply_fp_regs (int regno, const void *f0_f30, const void *fpcr)
+{
+ int i;
+
+ for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i)
+ if (regno == i || regno == -1)
+ regcache_raw_supply (current_regcache, i,
+ (const char *)f0_f30 + (i - ALPHA_FP0_REGNUM) * 8);
+
+ if (regno == ALPHA_FPCR_REGNUM || regno == -1)
+ regcache_raw_supply (current_regcache, ALPHA_FPCR_REGNUM, fpcr);
+}
+
+void
+alpha_fill_fp_regs (int regno, void *f0_f30, void *fpcr)
+{
+ int i;
+
+ for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i)
+ if (regno == i || regno == -1)
+ regcache_raw_collect (current_regcache, i,
+ (char *)f0_f30 + (i - ALPHA_FP0_REGNUM) * 8);
+
+ if (regno == ALPHA_FPCR_REGNUM || regno == -1)
+ regcache_raw_collect (current_regcache, ALPHA_FPCR_REGNUM, fpcr);
+}
+
+\f
+
+/* Return nonzero if the G_floating register value in REG is equal to
+ zero for FP control instructions. */
+
+static int
+fp_register_zero_p (LONGEST reg)
+{
+ /* Check that all bits except the sign bit are zero. */
+ const LONGEST zero_mask = ((LONGEST) 1 << 63) ^ -1;
+
+ return ((reg & zero_mask) == 0);
+}
+
+/* Return the value of the sign bit for the G_floating register
+ value held in REG. */
+
+static int
+fp_register_sign_bit (LONGEST reg)
+{
+ const LONGEST sign_mask = (LONGEST) 1 << 63;
+
+ return ((reg & sign_mask) != 0);
+}
+
/* alpha_software_single_step() is called just before we want to resume
the inferior, if we want to single-step it but there is no hardware
or kernel single-step support (NetBSD on Alpha, for example). We find
{
unsigned int insn;
unsigned int op;
+ int regno;
int offset;
LONGEST rav;
+ char reg[8];
- insn = read_memory_unsigned_integer (pc, sizeof (insn));
+ insn = alpha_read_insn (pc);
/* Opcode is top 6 bits. */
op = (insn >> 26) & 0x3f;
}
/* Need to determine if branch is taken; read RA. */
- rav = (LONGEST) read_register ((insn >> 21) & 0x1f);
+ regno = (insn >> 21) & 0x1f;
+ switch (op)
+ {
+ case 0x31: /* FBEQ */
+ case 0x36: /* FBGE */
+ case 0x37: /* FBGT */
+ case 0x33: /* FBLE */
+ case 0x32: /* FBLT */
+ case 0x35: /* FBNE */
+ regno += FP0_REGNUM;
+ }
+
+ regcache_cooked_read (current_regcache, regno, reg);
+ rav = extract_signed_integer (reg, 8);
+
switch (op)
{
case 0x38: /* BLBC */
goto branch_taken;
break;
- /* ??? Missing floating-point branches. */
+ /* Floating point branches. */
+
+ case 0x31: /* FBEQ */
+ if (fp_register_zero_p (rav))
+ goto branch_taken;
+ break;
+ case 0x36: /* FBGE */
+ if (fp_register_sign_bit (rav) == 0 || fp_register_zero_p (rav))
+ goto branch_taken;
+ break;
+ case 0x37: /* FBGT */
+ if (fp_register_sign_bit (rav) == 0 && ! fp_register_zero_p (rav))
+ goto branch_taken;
+ break;
+ case 0x33: /* FBLE */
+ if (fp_register_sign_bit (rav) == 1 || fp_register_zero_p (rav))
+ goto branch_taken;
+ break;
+ case 0x32: /* FBLT */
+ if (fp_register_sign_bit (rav) == 1 && ! fp_register_zero_p (rav))
+ goto branch_taken;
+ break;
+ case 0x35: /* FBNE */
+ if (! fp_register_zero_p (rav))
+ goto branch_taken;
+ break;
}
}
/* Lowest text address. This is used by heuristic_proc_start()
to decide when to stop looking. */
- tdep->vm_min_address = (CORE_ADDR) 0x120000000;
+ tdep->vm_min_address = (CORE_ADDR) 0x120000000LL;
tdep->dynamic_sigtramp_offset = NULL;
tdep->sigcontext_addr = NULL;
+ tdep->sc_pc_offset = 2 * 8;
+ tdep->sc_regs_offset = 4 * 8;
+ tdep->sc_fpregs_offset = tdep->sc_regs_offset + 32 * 8 + 8;
tdep->jb_pc = -1; /* longjmp support not enabled by default */
/* 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_deprecated_register_byte (gdbarch, alpha_register_byte);
+ set_gdbarch_register_type (gdbarch, alpha_register_type);
set_gdbarch_cannot_fetch_register (gdbarch, alpha_cannot_fetch_register);
set_gdbarch_cannot_store_register (gdbarch, alpha_cannot_store_register);
- set_gdbarch_register_convertible (gdbarch, alpha_register_convertible);
- set_gdbarch_register_convert_to_virtual (gdbarch,
- alpha_register_convert_to_virtual);
- set_gdbarch_register_convert_to_raw (gdbarch, alpha_register_convert_to_raw);
+ set_gdbarch_convert_register_p (gdbarch, alpha_convert_register_p);
+ set_gdbarch_register_to_value (gdbarch, alpha_register_to_value);
+ set_gdbarch_value_to_register (gdbarch, alpha_value_to_register);
+
+ 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,
- generic_frameless_function_invocation_not);
- set_gdbarch_use_struct_convention (gdbarch, alpha_use_struct_convention);
- set_gdbarch_deprecated_extract_return_value (gdbarch, alpha_extract_return_value);
- set_gdbarch_deprecated_store_struct_return (gdbarch, alpha_store_struct_return);
- set_gdbarch_deprecated_store_return_value (gdbarch, alpha_store_return_value);
- set_gdbarch_deprecated_extract_struct_value_address (gdbarch,
- alpha_extract_struct_value_address);
+ set_gdbarch_deprecated_use_struct_convention (gdbarch, always_use_struct_convention);
+ set_gdbarch_extract_return_value (gdbarch, alpha_extract_return_value);
+ set_gdbarch_store_return_value (gdbarch, alpha_store_return_value);
+ set_gdbarch_deprecated_extract_struct_value_address (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);
- set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
/* Return the unwound PC value. */
set_gdbarch_unwind_pc (gdbarch, alpha_unwind_pc);
set_gdbarch_breakpoint_from_pc (gdbarch, alpha_breakpoint_from_pc);
set_gdbarch_decr_pc_after_break (gdbarch, 4);
- set_gdbarch_function_start_offset (gdbarch, 0);
- set_gdbarch_frame_args_skip (gdbarch, 0);
-
/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
if (tdep->jb_pc >= 0)
set_gdbarch_get_longjmp_target (gdbarch, alpha_get_longjmp_target);
- frame_unwind_append_predicate (gdbarch, alpha_sigtramp_frame_p);
- frame_unwind_append_predicate (gdbarch, alpha_heuristic_frame_p);
+ frame_unwind_append_sniffer (gdbarch, alpha_sigtramp_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, alpha_heuristic_frame_sniffer);
frame_base_set_default (gdbarch, &alpha_heuristic_frame_base);
return gdbarch;
}
+void
+alpha_dwarf2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+ frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+}
+
+extern initialize_file_ftype _initialize_alpha_tdep; /* -Wmissing-prototypes */
+
void
_initialize_alpha_tdep (void)
{
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. */
/* We really would like to have both "0" and "unlimited" work, but
command.c doesn't deal with that. So make it a var_zinteger
because the user can always use "999999" or some such for unlimited. */
- c = add_set_cmd ("heuristic-fence-post", class_support, var_zinteger,
- (char *) &heuristic_fence_post,
- "\
-Set the distance searched for the start of a function.\n\
-If you are debugging a stripped executable, GDB needs to search through the\n\
-program for the start of a function. This command sets the distance of the\n\
-search. The only need to set it is when debugging a stripped executable.",
- &setlist);
/* We need to throw away the frame cache when we set this, since it
might change our ability to get backtraces. */
- set_cmd_sfunc (c, reinit_frame_cache_sfunc);
- add_show_from_set (c, &showlist);
+ add_setshow_zinteger_cmd ("heuristic-fence-post", class_support,
+ &heuristic_fence_post, _("\
+Set the distance searched for the start of a function."), _("\
+Show the distance searched for the start of a function."), _("\
+If you are debugging a stripped executable, GDB needs to search through the\n\
+program for the start of a function. This command sets the distance of the\n\
+search. The only need to set it is when debugging a stripped executable."),
+ reinit_frame_cache_sfunc,
+ NULL, /* FIXME: i18n: The distance searched for the start of a function is \"%d\". */
+ &setlist, &showlist);
}