/* Target-dependent code for UltraSPARC.
- Copyright 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "arch-utils.h"
+#include "dwarf2-frame.h"
#include "floatformat.h"
#include "frame.h"
#include "frame-base.h"
/* The functions on this page are intended to be used to classify
function arguments. */
-/* Return the contents if register REGNUM as an address. */
-
-static CORE_ADDR
-sparc_address_from_register (int regnum)
-{
- ULONGEST addr;
-
- regcache_cooked_read_unsigned (current_regcache, regnum, &addr);
- return addr;
-}
-
/* Check whether TYPE is "Integral or Pointer". */
static int
return 0;
}
+\f
+
+/* Type for %pstate. */
+struct type *sparc64_pstate_type;
+
+/* Type for %fsr. */
+struct type *sparc64_fsr_type;
+
+/* Type for %fprs. */
+struct type *sparc64_fprs_type;
+
+/* Construct types for ISA-specific registers. */
+
+static void
+sparc64_init_types (void)
+{
+ struct type *type;
+
+ type = init_flags_type ("builtin_type_sparc64_pstate", 8);
+ append_flags_type_flag (type, 0, "AG");
+ append_flags_type_flag (type, 1, "IE");
+ append_flags_type_flag (type, 2, "PRIV");
+ append_flags_type_flag (type, 3, "AM");
+ append_flags_type_flag (type, 4, "PEF");
+ append_flags_type_flag (type, 5, "RED");
+ append_flags_type_flag (type, 8, "TLE");
+ append_flags_type_flag (type, 9, "CLE");
+ append_flags_type_flag (type, 10, "PID0");
+ append_flags_type_flag (type, 11, "PID1");
+ sparc64_pstate_type = type;
+
+ type = init_flags_type ("builtin_type_sparc64_fsr", 8);
+ append_flags_type_flag (type, 0, "NXA");
+ append_flags_type_flag (type, 1, "DZA");
+ append_flags_type_flag (type, 2, "UFA");
+ append_flags_type_flag (type, 3, "OFA");
+ append_flags_type_flag (type, 4, "NVA");
+ append_flags_type_flag (type, 5, "NXC");
+ append_flags_type_flag (type, 6, "DZC");
+ append_flags_type_flag (type, 7, "UFC");
+ append_flags_type_flag (type, 8, "OFC");
+ append_flags_type_flag (type, 9, "NVC");
+ append_flags_type_flag (type, 22, "NS");
+ append_flags_type_flag (type, 23, "NXM");
+ append_flags_type_flag (type, 24, "DZM");
+ append_flags_type_flag (type, 25, "UFM");
+ append_flags_type_flag (type, 26, "OFM");
+ append_flags_type_flag (type, 27, "NVM");
+ sparc64_fsr_type = type;
+
+ type = init_flags_type ("builtin_type_sparc64_fprs", 8);
+ append_flags_type_flag (type, 0, "DL");
+ append_flags_type_flag (type, 1, "DU");
+ append_flags_type_flag (type, 2, "FEF");
+ sparc64_fprs_type = type;
+}
/* Register information. */
/* FIXME: Give it a name until we start using register groups. */
{ "state", &builtin_type_int64 },
- { "fsr", &builtin_type_int64 },
- { "fprs", &builtin_type_int64 },
+ { "fsr", &sparc64_fsr_type },
+ { "fprs", &sparc64_fprs_type },
/* "Although Y is a 64-bit register, its high-order 32 bits are
reserved and always read as 0." */
static struct sparc64_register_info sparc64_pseudo_register_info[] =
{
{ "cwp", &builtin_type_int64 },
- { "pstate", &builtin_type_int64 },
+ { "pstate", &sparc64_pstate_type },
{ "asi", &builtin_type_int64 },
{ "ccr", &builtin_type_int64 },
static void
sparc64_pseudo_register_read (struct gdbarch *gdbarch,
struct regcache *regcache,
- int regnum, void *buf)
+ int regnum, gdb_byte *buf)
{
gdb_assert (regnum >= SPARC64_NUM_REGS);
{
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC64_D0_REGNUM);
regcache_raw_read (regcache, regnum, buf);
- regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 4);
+ regcache_raw_read (regcache, regnum + 1, buf + 4);
}
else if (regnum >= SPARC64_D32_REGNUM && regnum <= SPARC64_D62_REGNUM)
{
{
regnum = SPARC_F0_REGNUM + 4 * (regnum - SPARC64_Q0_REGNUM);
regcache_raw_read (regcache, regnum, buf);
- regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 4);
- regcache_raw_read (regcache, regnum + 2, ((char *)buf) + 8);
- regcache_raw_read (regcache, regnum + 3, ((char *)buf) + 12);
+ regcache_raw_read (regcache, regnum + 1, buf + 4);
+ regcache_raw_read (regcache, regnum + 2, buf + 8);
+ regcache_raw_read (regcache, regnum + 3, buf + 12);
}
else if (regnum >= SPARC64_Q32_REGNUM && regnum <= SPARC64_Q60_REGNUM)
{
regnum = SPARC64_F32_REGNUM + 2 * (regnum - SPARC64_Q32_REGNUM);
regcache_raw_read (regcache, regnum, buf);
- regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 8);
+ regcache_raw_read (regcache, regnum + 1, buf + 8);
}
else if (regnum == SPARC64_CWP_REGNUM
|| regnum == SPARC64_PSTATE_REGNUM
static void
sparc64_pseudo_register_write (struct gdbarch *gdbarch,
struct regcache *regcache,
- int regnum, const void *buf)
+ int regnum, const gdb_byte *buf)
{
gdb_assert (regnum >= SPARC64_NUM_REGS);
{
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC64_D0_REGNUM);
regcache_raw_write (regcache, regnum, buf);
- regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 4);
+ regcache_raw_write (regcache, regnum + 1, buf + 4);
}
else if (regnum >= SPARC64_D32_REGNUM && regnum <= SPARC64_D62_REGNUM)
{
{
regnum = SPARC_F0_REGNUM + 4 * (regnum - SPARC64_Q0_REGNUM);
regcache_raw_write (regcache, regnum, buf);
- regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 4);
- regcache_raw_write (regcache, regnum + 2, ((const char *)buf) + 8);
- regcache_raw_write (regcache, regnum + 3, ((const char *)buf) + 12);
+ regcache_raw_write (regcache, regnum + 1, buf + 4);
+ regcache_raw_write (regcache, regnum + 2, buf + 8);
+ regcache_raw_write (regcache, regnum + 3, buf + 12);
}
else if (regnum >= SPARC64_Q32_REGNUM && regnum <= SPARC64_Q60_REGNUM)
{
regnum = SPARC64_F32_REGNUM + 2 * (regnum - SPARC64_Q32_REGNUM);
regcache_raw_write (regcache, regnum, buf);
- regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 8);
+ regcache_raw_write (regcache, regnum + 1, buf + 8);
}
else if (regnum == SPARC64_CWP_REGNUM
|| regnum == SPARC64_PSTATE_REGNUM
sparc64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ int *realnump, gdb_byte *valuep)
{
struct sparc_frame_cache *cache =
sparc64_frame_cache (next_frame, this_cache);
return;
}
+ /* Handle StackGhost. */
+ {
+ ULONGEST wcookie = sparc_fetch_wcookie ();
+
+ if (wcookie != 0 && !cache->frameless_p && regnum == SPARC_I7_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 8;
+ ULONGEST i7;
+
+ /* Read the value in from memory. */
+ i7 = get_frame_memory_unsigned (next_frame, addr, 8);
+ store_unsigned_integer (valuep, 8, i7 ^ wcookie);
+ }
+ return;
+ }
+ }
+
/* The previous frame's `local' and `in' registers have been saved
in the register save area. */
if (!cache->frameless_p
{
*optimizedp = 0;
*lvalp = lval_memory;
- *addrp = cache->base + BIAS + (regnum - SPARC_L0_REGNUM) * 8;
+ *addrp = cache->base + (regnum - SPARC_L0_REGNUM) * 8;
*realnump = -1;
if (valuep)
{
&& regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
regnum += (SPARC_I0_REGNUM - SPARC_O0_REGNUM);
- frame_register_unwind (next_frame, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ *optimizedp = 0;
+ *lvalp = lval_register;
+ *addrp = 0;
+ *realnump = regnum;
+ if (valuep)
+ frame_unwind_register (next_frame, regnum, valuep);
}
static const struct frame_unwind sparc64_frame_unwind =
struct sparc_frame_cache *cache =
sparc64_frame_cache (next_frame, this_cache);
- /* ??? Should we take BIAS into account here? */
return cache->base;
}
static void
sparc64_store_floating_fields (struct regcache *regcache, struct type *type,
- char *valbuf, int element, int bitpos)
+ const gdb_byte *valbuf, int element, int bitpos)
{
gdb_assert (element < 16);
sparc64_store_floating_fields (regcache, subtype, valbuf,
element, subpos);
}
+
+ /* GCC has an interesting bug. If TYPE is a structure that has
+ a single `float' member, GCC doesn't treat it as a structure
+ at all, but rather as an ordinary `float' argument. This
+ argument will be stored in %f1, as required by the psABI.
+ However, as a member of a structure the psABI requires it to
+ be stored in %f0. This bug is present in GCC 3.3.2, but
+ probably in older releases to. To appease GCC, if a
+ structure has only a single `float' member, we store its
+ value in %f1 too (we already have stored in %f0). */
+ if (TYPE_NFIELDS (type) == 1)
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, 0));
+
+ if (sparc64_floating_p (subtype) && TYPE_LENGTH (subtype) == 4)
+ regcache_cooked_write (regcache, SPARC_F1_REGNUM, valbuf);
+ }
}
}
static void
sparc64_extract_floating_fields (struct regcache *regcache, struct type *type,
- char *valbuf, int bitpos)
+ gdb_byte *valbuf, int bitpos)
{
if (sparc64_floating_p (type))
{
for (i = 0; i < nargs; i++)
{
- struct type *type = VALUE_TYPE (args[i]);
+ struct type *type = value_type (args[i]);
int len = TYPE_LENGTH (type);
if (sparc64_structure_or_union_p (type))
a problem. */
sp &= ~0xf;
- write_memory (sp, VALUE_CONTENTS (args[i]), len);
+ write_memory (sp, value_contents (args[i]), len);
args[i] = value_from_pointer (lookup_pointer_type (type), sp);
num_elements++;
}
for (i = 0; i < nargs; i++)
{
- char *valbuf = VALUE_CONTENTS (args[i]);
- struct type *type = VALUE_TYPE (args[i]);
+ const gdb_byte *valbuf = value_contents (args[i]);
+ struct type *type = value_type (args[i]);
int len = TYPE_LENGTH (type);
int regnum = -1;
- char buf[16];
+ gdb_byte buf[16];
if (sparc64_structure_or_union_p (type))
{
undefined." Even though the psABI says that "the
left half is undefined", set it to zero here. */
memset (buf, 0, 4);
- valbuf = memcpy (buf + 4, valbuf, 4);
+ memcpy (buf + 4, valbuf, 4);
+ valbuf = buf;
len = 8;
if (element < 16)
- regnum = SPARC64_D0_REGNUM;
+ regnum = SPARC64_D0_REGNUM + element;
}
}
else
gdb_assert (element < 6);
regnum = SPARC_O0_REGNUM + element;
regcache_cooked_write (regcache, regnum, valbuf);
- regcache_cooked_write (regcache, regnum + 1, valbuf);
+ regcache_cooked_write (regcache, regnum + 1, valbuf + 8);
}
}
- /* Always store the argument in memeory. */
+ /* Always store the argument in memory. */
write_memory (sp + element * 8, valbuf, len);
element += ((len + 7) / 8);
}
}
static CORE_ADDR
-sparc64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+sparc64_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)
/* Finally, update the stack pointer. */
regcache_cooked_write_unsigned (regcache, SPARC_SP_REGNUM, sp);
- return sp;
+ return sp + BIAS;
}
\f
static void
sparc64_extract_return_value (struct type *type, struct regcache *regcache,
- void *valbuf)
+ gdb_byte *valbuf)
{
int len = TYPE_LENGTH (type);
- char buf[32];
+ gdb_byte buf[32];
int i;
if (sparc64_structure_or_union_p (type))
regcache_cooked_read (regcache, SPARC_F0_REGNUM + i, buf + i * 4);
memcpy (valbuf, buf, len);
}
+ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ /* Small arrays are returned the same way as small structures. */
+ gdb_assert (len <= 32);
+
+ for (i = 0; i < ((len + 7) / 8); i++)
+ regcache_cooked_read (regcache, SPARC_O0_REGNUM + i, buf + i * 8);
+ memcpy (valbuf, buf, len);
+ }
else
{
/* Integral and pointer return values. */
static void
sparc64_store_return_value (struct type *type, struct regcache *regcache,
- const void *valbuf)
+ const gdb_byte *valbuf)
{
int len = TYPE_LENGTH (type);
- char buf[16];
+ gdb_byte buf[16];
int i;
if (sparc64_structure_or_union_p (type))
for (i = 0; i < len / 4; i++)
regcache_cooked_write (regcache, SPARC_F0_REGNUM + i, buf + i * 4);
}
+ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ /* Small arrays are returned the same way as small structures. */
+ gdb_assert (len <= 32);
+
+ memset (buf, 0, sizeof (buf));
+ memcpy (buf, valbuf, len);
+ for (i = 0; i < ((len + 7) / 8); i++)
+ regcache_cooked_write (regcache, SPARC_O0_REGNUM + i, buf + i * 8);
+ }
else
{
/* Integral and pointer return values. */
static enum return_value_convention
sparc64_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, void *readbuf,
- const void *writebuf)
+ struct regcache *regcache, gdb_byte *readbuf,
+ const gdb_byte *writebuf)
{
if (TYPE_LENGTH (type) > 32)
return RETURN_VALUE_STRUCT_CONVENTION;
}
\f
+static void
+sparc64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+ struct dwarf2_frame_state_reg *reg,
+ struct frame_info *next_frame)
+{
+ switch (regnum)
+ {
+ case SPARC_G0_REGNUM:
+ /* Since %g0 is always zero, there is no point in saving it, and
+ people will be inclined omit it from the CFI. Make sure we
+ don't warn about that. */
+ reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+ break;
+ case SPARC_SP_REGNUM:
+ reg->how = DWARF2_FRAME_REG_CFA;
+ break;
+ case SPARC64_PC_REGNUM:
+ reg->how = DWARF2_FRAME_REG_RA_OFFSET;
+ reg->loc.offset = 8;
+ break;
+ case SPARC64_NPC_REGNUM:
+ reg->how = DWARF2_FRAME_REG_RA_OFFSET;
+ reg->loc.offset = 12;
+ break;
+ }
+}
+
void
sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_push_dummy_call (gdbarch, sparc64_push_dummy_call);
set_gdbarch_return_value (gdbarch, sparc64_return_value);
- set_gdbarch_return_value_on_stack
- (gdbarch, generic_return_value_on_stack_not);
set_gdbarch_stabs_argument_has_addr
(gdbarch, default_stabs_argument_has_addr);
set_gdbarch_skip_prologue (gdbarch, sparc64_skip_prologue);
+ /* Hook in the DWARF CFI frame unwinder. */
+ dwarf2_frame_set_init_reg (gdbarch, sparc64_dwarf2_frame_init_reg);
+ /* FIXME: kettenis/20050423: Don't enable the unwinder until the
+ StackGhost issues have been resolved. */
+
frame_unwind_append_sniffer (gdbarch, sparc64_frame_sniffer);
frame_base_set_default (gdbarch, &sparc64_frame_base);
}
int regnum, const void *gregs)
{
int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
- const char *regs = gregs;
+ const gdb_byte *regs = gregs;
int i;
if (sparc32)
{
int offset = gregset->r_tstate_offset;
ULONGEST tstate, psr;
- char buf[4];
+ gdb_byte buf[4];
tstate = extract_unsigned_integer (regs + offset, 8);
psr = ((tstate & TSTATE_CWP) | PSR_S | ((tstate & TSTATE_ICC) >> 12)
if (regnum == SPARC64_Y_REGNUM || regnum == -1)
{
- char buf[8];
+ gdb_byte buf[8];
memset (buf, 0, 8);
memcpy (buf + 8 - gregset->r_y_size,
int regnum, void *gregs)
{
int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
- char *regs = gregs;
+ gdb_byte *regs = gregs;
int i;
if (sparc32)
{
int offset = gregset->r_tstate_offset;
ULONGEST tstate, psr;
- char buf[8];
+ gdb_byte buf[8];
tstate = extract_unsigned_integer (regs + offset, 8);
regcache_raw_collect (regcache, SPARC32_PSR_REGNUM, buf);
if (regnum == SPARC64_Y_REGNUM || regnum == -1)
{
- char buf[8];
+ gdb_byte buf[8];
regcache_raw_collect (regcache, SPARC64_Y_REGNUM, buf);
memcpy (regs + gregset->r_y_offset,
int regnum, const void *fpregs)
{
int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
- const char *regs = fpregs;
+ const gdb_byte *regs = fpregs;
int i;
for (i = 0; i < 32; i++)
int regnum, void *fpregs)
{
int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
- char *regs = fpregs;
+ gdb_byte *regs = fpregs;
int i;
for (i = 0; i < 32; i++)
regs + (32 * 4) + (16 * 8));
}
}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_sparc64_tdep (void);
+
+void
+_initialize_sparc64_tdep (void)
+{
+ /* Initialize the UltraSPARC-specific register types. */
+ sparc64_init_types();
+}