/* Target-dependent code for UltraSPARC.
- Copyright 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
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. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "arch-utils.h"
+#include "dwarf2-frame.h"
#include "floatformat.h"
#include "frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "gdbcore.h"
#include "gdbtypes.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "objfiles.h"
#include "osabi.h"
#include "regcache.h"
#include "target.h"
/* Please use the sparc32_-prefix for 32-bit specific code, the
sparc64_-prefix for 64-bit specific code and the sparc_-prefix for
code can handle both. */
-
-/* The stack pointer is offset from the stack frame by a BIAS of 2047
- (0x7ff) for 64-bit code. BIAS is likely to be defined on SPARC
- hosts, so undefine it first. */
-#undef BIAS
-#define BIAS 2047
-
-/* Macros to extract fields from SPARC instructions. */
-#define X_OP(i) (((i) >> 30) & 0x3)
-#define X_A(i) (((i) >> 29) & 1)
-#define X_COND(i) (((i) >> 25) & 0xf)
-#define X_OP2(i) (((i) >> 22) & 0x7)
-#define X_IMM22(i) ((i) & 0x3fffff)
-#define X_OP3(i) (((i) >> 19) & 0x3f)
-/* Sign extension macros. */
-#define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
-#define X_DISP19(i) ((((i) & 0x7ffff) ^ 0x40000) - 0x40000)
-
-/* Fetch the instruction at PC. Instructions are always big-endian
- even if the processor operates in little-endian mode. */
-
-static unsigned long
-sparc_fetch_instruction (CORE_ADDR pc)
-{
- unsigned char buf[4];
- unsigned long insn;
- int i;
-
- read_memory (pc, buf, sizeof (buf));
-
- insn = 0;
- for (i = 0; i < sizeof (buf); i++)
- insn = (insn << 8) | buf[i];
- return insn;
-}
\f
/* 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
-/* UltraSPARC architecture specific information. */
+/* Type for %pstate. */
+struct type *sparc64_pstate_type;
-struct gdbarch_tdep
-{
- /* Offset of saved PC in jmp_buf. */
- int jb_pc_offset;
-};
+/* Type for %fsr. */
+struct type *sparc64_fsr_type;
-/* Register information. */
+/* Type for %fprs. */
+struct type *sparc64_fprs_type;
-struct sparc64_register_info
-{
- char *name;
- struct type **type;
-};
+/* Construct types for ISA-specific registers. */
-static struct sparc64_register_info sparc64_register_info[] =
+static void
+sparc64_init_types (void)
{
- { "g0", &builtin_type_int64 },
- { "g1", &builtin_type_int64 },
- { "g2", &builtin_type_int64 },
- { "g3", &builtin_type_int64 },
- { "g4", &builtin_type_int64 },
- { "g5", &builtin_type_int64 },
- { "g6", &builtin_type_int64 },
- { "g7", &builtin_type_int64 },
-
- { "o0", &builtin_type_int64 },
- { "o1", &builtin_type_int64 },
- { "o2", &builtin_type_int64 },
- { "o3", &builtin_type_int64 },
- { "o4", &builtin_type_int64 },
- { "o5", &builtin_type_int64 },
- { "sp", &builtin_type_void_data_ptr },
- { "o7", &builtin_type_int64 },
-
- { "l0", &builtin_type_int64 },
- { "l1", &builtin_type_int64 },
- { "l2", &builtin_type_int64 },
- { "l3", &builtin_type_int64 },
- { "l4", &builtin_type_int64 },
- { "l5", &builtin_type_int64 },
- { "l6", &builtin_type_int64 },
- { "l7", &builtin_type_int64 },
-
- { "i0", &builtin_type_int64 },
- { "i1", &builtin_type_int64 },
- { "i2", &builtin_type_int64 },
- { "i3", &builtin_type_int64 },
- { "i4", &builtin_type_int64 },
- { "i5", &builtin_type_int64 },
- { "fp", &builtin_type_void_data_ptr },
- { "i7", &builtin_type_int64 },
-
- { "f0", &builtin_type_float },
- { "f1", &builtin_type_float },
- { "f2", &builtin_type_float },
- { "f3", &builtin_type_float },
- { "f4", &builtin_type_float },
- { "f5", &builtin_type_float },
- { "f6", &builtin_type_float },
- { "f7", &builtin_type_float },
- { "f8", &builtin_type_float },
- { "f9", &builtin_type_float },
- { "f10", &builtin_type_float },
- { "f11", &builtin_type_float },
- { "f12", &builtin_type_float },
- { "f13", &builtin_type_float },
- { "f14", &builtin_type_float },
- { "f15", &builtin_type_float },
- { "f16", &builtin_type_float },
- { "f17", &builtin_type_float },
- { "f18", &builtin_type_float },
- { "f19", &builtin_type_float },
- { "f20", &builtin_type_float },
- { "f21", &builtin_type_float },
- { "f22", &builtin_type_float },
- { "f23", &builtin_type_float },
- { "f24", &builtin_type_float },
- { "f25", &builtin_type_float },
- { "f26", &builtin_type_float },
- { "f27", &builtin_type_float },
- { "f28", &builtin_type_float },
- { "f29", &builtin_type_float },
- { "f30", &builtin_type_float },
- { "f31", &builtin_type_float },
- { "f32", &builtin_type_double },
- { "f34", &builtin_type_double },
- { "f36", &builtin_type_double },
- { "f38", &builtin_type_double },
- { "f40", &builtin_type_double },
- { "f42", &builtin_type_double },
- { "f44", &builtin_type_double },
- { "f46", &builtin_type_double },
- { "f48", &builtin_type_double },
- { "f50", &builtin_type_double },
- { "f52", &builtin_type_double },
- { "f54", &builtin_type_double },
- { "f56", &builtin_type_double },
- { "f58", &builtin_type_double },
- { "f60", &builtin_type_double },
- { "f62", &builtin_type_double },
-
- { "pc", &builtin_type_void_func_ptr },
- { "npc", &builtin_type_void_func_ptr },
-
- /* This raw register contains the contents of %cwp, %pstate, %asi
- and %ccr as laid out in a %tstate register. */
- { NULL, &builtin_type_int64 },
+ 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;
+}
- { "fsr", &builtin_type_int64 },
- { "fprs", &builtin_type_int64 },
+/* Register information. */
- /* "Although Y is a 64-bit register, its high-order 32 bits are
- reserved and always read as 0." */
- { "y", &builtin_type_int64 }
+static const char *sparc64_register_names[] =
+{
+ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
+ "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
+ "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
+ "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
+
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",
+ "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
+
+ "pc", "npc",
+
+ /* FIXME: Give "state" a name until we start using register groups. */
+ "state",
+ "fsr",
+ "fprs",
+ "y",
};
/* Total number of registers. */
-#define SPARC64_NUM_REGS \
- (sizeof (sparc64_register_info) / sizeof (sparc64_register_info[0]))
+#define SPARC64_NUM_REGS ARRAY_SIZE (sparc64_register_names)
/* We provide the aliases %d0..%d62 and %q0..%q60 for the floating
registers as "psuedo" registers. */
-static struct sparc64_register_info sparc64_pseudo_register_info[] =
+static const char *sparc64_pseudo_register_names[] =
{
- { "cwp", &builtin_type_int64 },
- { "pstate", &builtin_type_int64 },
- { "asi", &builtin_type_int64 },
- { "ccr", &builtin_type_int64 },
-
- { "d0", &builtin_type_double },
- { "d2", &builtin_type_double },
- { "d4", &builtin_type_double },
- { "d6", &builtin_type_double },
- { "d8", &builtin_type_double },
- { "d10", &builtin_type_double },
- { "d12", &builtin_type_double },
- { "d14", &builtin_type_double },
- { "d16", &builtin_type_double },
- { "d18", &builtin_type_double },
- { "d20", &builtin_type_double },
- { "d22", &builtin_type_double },
- { "d24", &builtin_type_double },
- { "d26", &builtin_type_double },
- { "d28", &builtin_type_double },
- { "d30", &builtin_type_double },
- { "d32", &builtin_type_double },
- { "d34", &builtin_type_double },
- { "d36", &builtin_type_double },
- { "d38", &builtin_type_double },
- { "d40", &builtin_type_double },
- { "d42", &builtin_type_double },
- { "d44", &builtin_type_double },
- { "d46", &builtin_type_double },
- { "d48", &builtin_type_double },
- { "d50", &builtin_type_double },
- { "d52", &builtin_type_double },
- { "d54", &builtin_type_double },
- { "d56", &builtin_type_double },
- { "d58", &builtin_type_double },
- { "d60", &builtin_type_double },
- { "d62", &builtin_type_double },
-
- { "q0", &builtin_type_long_double },
- { "q4", &builtin_type_long_double },
- { "q8", &builtin_type_long_double },
- { "q12", &builtin_type_long_double },
- { "q16", &builtin_type_long_double },
- { "q20", &builtin_type_long_double },
- { "q24", &builtin_type_long_double },
- { "q28", &builtin_type_long_double },
- { "q32", &builtin_type_long_double },
- { "q36", &builtin_type_long_double },
- { "q40", &builtin_type_long_double },
- { "q44", &builtin_type_long_double },
- { "q48", &builtin_type_long_double },
- { "q52", &builtin_type_long_double },
- { "q56", &builtin_type_long_double },
- { "q60", &builtin_type_long_double }
+ "cwp", "pstate", "asi", "ccr",
+
+ "d0", "d2", "d4", "d6", "d8", "d10", "d12", "d14",
+ "d16", "d18", "d20", "d22", "d24", "d26", "d28", "d30",
+ "d32", "d34", "d36", "d38", "d40", "d42", "d44", "d46",
+ "d48", "d50", "d52", "d54", "d56", "d58", "d60", "d62",
+
+ "q0", "q4", "q8", "q12", "q16", "q20", "q24", "q28",
+ "q32", "q36", "q40", "q44", "q48", "q52", "q56", "q60",
};
/* Total number of pseudo registers. */
-#define SPARC64_NUM_PSEUDO_REGS \
- (sizeof (sparc64_pseudo_register_info) \
- / sizeof (sparc64_pseudo_register_info[0]))
+#define SPARC64_NUM_PSEUDO_REGS ARRAY_SIZE (sparc64_pseudo_register_names)
/* Return the name of register REGNUM. */
static const char *
-sparc64_register_name (int regnum)
+sparc64_register_name (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= 0 && regnum < SPARC64_NUM_REGS)
- return sparc64_register_info[regnum].name;
+ return sparc64_register_names[regnum];
if (regnum >= SPARC64_NUM_REGS
&& regnum < SPARC64_NUM_REGS + SPARC64_NUM_PSEUDO_REGS)
- return sparc64_pseudo_register_info[regnum - SPARC64_NUM_REGS].name;
+ return sparc64_pseudo_register_names[regnum - SPARC64_NUM_REGS];
return NULL;
}
static struct type *
sparc64_register_type (struct gdbarch *gdbarch, int regnum)
{
- if (regnum >= SPARC64_NUM_REGS
- && regnum < SPARC64_NUM_REGS + SPARC64_NUM_PSEUDO_REGS)
- return *sparc64_pseudo_register_info[regnum - SPARC64_NUM_REGS].type;
-
- gdb_assert (regnum >= 0 && regnum < SPARC64_NUM_REGS);
- return *sparc64_register_info[regnum].type;
+ /* Raw registers. */
+
+ if (regnum == SPARC_SP_REGNUM || regnum == SPARC_FP_REGNUM)
+ return builtin_type (gdbarch)->builtin_data_ptr;
+ if (regnum >= SPARC_G0_REGNUM && regnum <= SPARC_I7_REGNUM)
+ return builtin_type_int64;
+ if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
+ return builtin_type (gdbarch)->builtin_float;
+ if (regnum >= SPARC64_F32_REGNUM && regnum <= SPARC64_F62_REGNUM)
+ return builtin_type (gdbarch)->builtin_double;
+ if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ /* This raw register contains the contents of %cwp, %pstate, %asi
+ and %ccr as laid out in a %tstate register. */
+ if (regnum == SPARC64_STATE_REGNUM)
+ return builtin_type_int64;
+ if (regnum == SPARC64_FSR_REGNUM)
+ return sparc64_fsr_type;
+ if (regnum == SPARC64_FPRS_REGNUM)
+ return sparc64_fprs_type;
+ /* "Although Y is a 64-bit register, its high-order 32 bits are
+ reserved and always read as 0." */
+ if (regnum == SPARC64_Y_REGNUM)
+ return builtin_type_int64;
+
+ /* Pseudo registers. */
+
+ if (regnum == SPARC64_CWP_REGNUM)
+ return builtin_type_int64;
+ if (regnum == SPARC64_PSTATE_REGNUM)
+ return sparc64_pstate_type;
+ if (regnum == SPARC64_ASI_REGNUM)
+ return builtin_type_int64;
+ if (regnum == SPARC64_CCR_REGNUM)
+ return builtin_type_int64;
+ if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D62_REGNUM)
+ return builtin_type (gdbarch)->builtin_double;
+ if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q60_REGNUM)
+ return builtin_type (gdbarch)->builtin_long_double;
+
+ internal_error (__FILE__, __LINE__, _("invalid regnum"));
}
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
regcache_raw_read_unsigned (regcache, SPARC64_STATE_REGNUM, &state);
switch (regnum)
{
- SPARC64_CWP_REGNUM:
+ case SPARC64_CWP_REGNUM:
state = (state >> 0) & ((1 << 5) - 1);
break;
- SPARC64_PSTATE_REGNUM:
+ case SPARC64_PSTATE_REGNUM:
state = (state >> 8) & ((1 << 12) - 1);
break;
- SPARC64_ASI_REGNUM:
+ case SPARC64_ASI_REGNUM:
state = (state >> 24) & ((1 << 8) - 1);
break;
- SPARC64_CCR_REGNUM:
+ case SPARC64_CCR_REGNUM:
state = (state >> 32) & ((1 << 8) - 1);
break;
}
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);
}
-}
-
-/* Use the program counter to determine the contents and size of a
- breakpoint instruction. Return a pointer to a string of bytes that
- encode a breakpoint instruction, store the length of the string in
- *LEN and optionally adjust *PC to point to the correct memory
- location for inserting the breakpoint. */
-
-static const unsigned char *
-sparc_breakpoint_from_pc (CORE_ADDR *pc, int *len)
-{
- static unsigned char break_insn[] = { 0x91, 0xd0, 0x20, 0x01 };
-
- *len = sizeof (break_insn);
- return break_insn;
-}
-\f
-
-struct sparc64_frame_cache
-{
- /* Base address. */
- CORE_ADDR base;
- CORE_ADDR pc;
-
- /* Do we have a frame? */
- int frameless_p;
-};
-
-/* Allocate and initialize a frame cache. */
-
-static struct sparc64_frame_cache *
-sparc64_alloc_frame_cache (void)
-{
- struct sparc64_frame_cache *cache;
- int i;
-
- cache = FRAME_OBSTACK_ZALLOC (struct sparc64_frame_cache);
-
- /* Base address. */
- cache->base = 0;
- cache->pc = 0;
-
- /* Frameless until proven otherwise. */
- cache->frameless_p = 1;
-
- return cache;
-}
-
-static CORE_ADDR
-sparc64_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
- struct sparc64_frame_cache *cache)
-{
- unsigned long insn;
-
- if (current_pc <= pc)
- return current_pc;
-
- /* Check whether the function starts with a SAVE instruction. */
- insn = sparc_fetch_instruction (pc);
- if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3c)
+ else if (regnum == SPARC64_CWP_REGNUM
+ || regnum == SPARC64_PSTATE_REGNUM
+ || regnum == SPARC64_ASI_REGNUM
+ || regnum == SPARC64_CCR_REGNUM)
{
- cache->frameless_p = 0;
- return pc + 4;
- }
+ ULONGEST state, bits;
- return pc;
-}
-
-static CORE_ADDR
-sparc64_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- return frame_unwind_register_unsigned (next_frame, SPARC64_PC_REGNUM);
+ regcache_raw_read_unsigned (regcache, SPARC64_STATE_REGNUM, &state);
+ bits = extract_unsigned_integer (buf, 8);
+ switch (regnum)
+ {
+ case SPARC64_CWP_REGNUM:
+ state |= ((bits & ((1 << 5) - 1)) << 0);
+ break;
+ case SPARC64_PSTATE_REGNUM:
+ state |= ((bits & ((1 << 12) - 1)) << 8);
+ break;
+ case SPARC64_ASI_REGNUM:
+ state |= ((bits & ((1 << 8) - 1)) << 24);
+ break;
+ case SPARC64_CCR_REGNUM:
+ state |= ((bits & ((1 << 8) - 1)) << 32);
+ break;
+ }
+ regcache_raw_write_unsigned (regcache, SPARC64_STATE_REGNUM, state);
+ }
}
+\f
/* Return PC of first real instruction of the function starting at
START_PC. */
static CORE_ADDR
-sparc64_skip_prologue (CORE_ADDR start_pc)
+sparc64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
{
struct symtab_and_line sal;
CORE_ADDR func_start, func_end;
- struct sparc64_frame_cache cache;
+ struct sparc_frame_cache cache;
/* This is the preferred method, find the end of the prologue by
using the debugging information. */
return sal.end;
}
- return sparc64_analyze_prologue (start_pc, 0xffffffffffffffffUL, &cache);
+ return sparc_analyze_prologue (gdbarch, start_pc, 0xffffffffffffffffULL,
+ &cache);
}
/* Normal frames. */
-static struct sparc64_frame_cache *
-sparc64_frame_cache (struct frame_info *next_frame, void **this_cache)
+static struct sparc_frame_cache *
+sparc64_frame_cache (struct frame_info *this_frame, void **this_cache)
{
- struct sparc64_frame_cache *cache;
-
- if (*this_cache)
- return *this_cache;
-
- cache = sparc64_alloc_frame_cache ();
- *this_cache = cache;
-
- /* In priciple, for normal frames, %fp (%i6) holds the frame
- pointer, which holds the base address for the current stack
- frame. */
-
- cache->base = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
- if (cache->base == 0)
- return cache;
-
- cache->pc = frame_func_unwind (next_frame);
- if (cache->pc != 0)
- sparc64_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
-
- if (cache->frameless_p)
- {
- /* We didn't find a valid frame, which means that CACHE->base
- currently holds the frame pointer for our calling frame. */
- cache->base = frame_unwind_register_unsigned (next_frame,
- SPARC_SP_REGNUM);
- }
-
- return cache;
+ return sparc_frame_cache (this_frame, this_cache);
}
static void
-sparc64_frame_this_id (struct frame_info *next_frame, void **this_cache,
+sparc64_frame_this_id (struct frame_info *this_frame, void **this_cache,
struct frame_id *this_id)
{
- struct sparc64_frame_cache *cache =
- sparc64_frame_cache (next_frame, this_cache);
+ struct sparc_frame_cache *cache =
+ sparc64_frame_cache (this_frame, this_cache);
/* This marks the outermost frame. */
if (cache->base == 0)
(*this_id) = frame_id_build (cache->base, cache->pc);
}
-static void
-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)
+static struct value *
+sparc64_frame_prev_register (struct frame_info *this_frame, void **this_cache,
+ int regnum)
{
- struct sparc64_frame_cache *cache =
- sparc64_frame_cache (next_frame, this_cache);
+ struct sparc_frame_cache *cache =
+ sparc64_frame_cache (this_frame, this_cache);
if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
{
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (valuep)
- {
- CORE_ADDR pc = (regnum == SPARC64_NPC_REGNUM) ? 4 : 0;
+ CORE_ADDR pc = (regnum == SPARC64_NPC_REGNUM) ? 4 : 0;
- regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
- pc += frame_unwind_register_unsigned (next_frame, regnum) + 8;
- store_unsigned_integer (valuep, 8, pc);
- }
- return;
+ regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
+ pc += get_frame_register_unsigned (this_frame, regnum) + 8;
+ return frame_unwind_got_constant (this_frame, regnum, pc);
}
+ /* Handle StackGhost. */
+ {
+ ULONGEST wcookie = sparc_fetch_wcookie ();
+
+ if (wcookie != 0 && !cache->frameless_p && regnum == SPARC_I7_REGNUM)
+ {
+ CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 8;
+ ULONGEST i7;
+
+ /* Read the value in from memory. */
+ i7 = get_frame_memory_unsigned (this_frame, addr, 8);
+ return frame_unwind_got_constant (this_frame, regnum, i7 ^ wcookie);
+ }
+ }
+
/* The previous frame's `local' and `in' registers have been saved
in the register save area. */
if (!cache->frameless_p
&& regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM)
{
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = cache->base + BIAS + (regnum - SPARC_L0_REGNUM) * 8;
- *realnump = -1;
- if (valuep)
- {
- struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 8;
- /* Read the value in from memory. */
- read_memory (*addrp, valuep, register_size (gdbarch, regnum));
- }
- return;
+ return frame_unwind_got_memory (this_frame, regnum, addr);
}
/* The previous frame's `out' registers are accessable as the
&& 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);
+ return frame_unwind_got_register (this_frame, regnum, regnum);
}
static const struct frame_unwind sparc64_frame_unwind =
{
NORMAL_FRAME,
sparc64_frame_this_id,
- sparc64_frame_prev_register
+ sparc64_frame_prev_register,
+ NULL,
+ default_frame_sniffer
};
-
-static const struct frame_unwind *
-sparc64_frame_sniffer (struct frame_info *next_frame)
-{
- return &sparc64_frame_unwind;
-}
\f
static CORE_ADDR
-sparc64_frame_base_address (struct frame_info *next_frame, void **this_cache)
+sparc64_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
- struct sparc64_frame_cache *cache =
- sparc64_frame_cache (next_frame, this_cache);
+ struct sparc_frame_cache *cache =
+ sparc64_frame_cache (this_frame, this_cache);
- /* ??? Should we take BIAS into account here? */
return cache->base;
}
sparc64_frame_base_address,
sparc64_frame_base_address
};
-
-static struct frame_id
-sparc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- CORE_ADDR sp;
-
- sp = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
- return frame_id_build (sp, frame_pc_unwind (next_frame));
-}
\f
/* Check whether TYPE must be 16-byte aligned. */
int i;
for (i = 0; i < TYPE_NFIELDS (type); i++)
- if (sparc64_16_byte_align_p (TYPE_FIELD_TYPE (type, i)))
- return 1;
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+
+ if (sparc64_16_byte_align_p (subtype))
+ return 1;
+ }
}
return 0;
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);
int i;
for (i = 0; i < TYPE_NFIELDS (type); i++)
- sparc64_store_floating_fields (regcache, TYPE_FIELD_TYPE (type, i),
- valbuf, element,
- bitpos + TYPE_FIELD_BITPOS (type, i));
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int subpos = bitpos + TYPE_FIELD_BITPOS (type, i);
+
+ 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))
{
int i;
for (i = 0; i < TYPE_NFIELDS (type); i++)
- sparc64_extract_floating_fields (regcache, TYPE_FIELD_TYPE (type, i),
- valbuf,
- bitpos + TYPE_FIELD_BITPOS (type, i));
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int subpos = bitpos + TYPE_FIELD_BITPOS (type, i);
+
+ sparc64_extract_floating_fields (regcache, subtype, valbuf, subpos);
+ }
}
}
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)
sp -= 16 * 8;
/* Stack should be 16-byte aligned at this point. */
- gdb_assert (sp % 16 == 0);
+ gdb_assert ((sp + BIAS) % 16 == 0);
/* 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))
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 * 4);
+ regcache_cooked_write (regcache, SPARC_O0_REGNUM + i, buf + i * 8);
if (TYPE_CODE (type) != TYPE_CODE_UNION)
sparc64_store_floating_fields (regcache, type, buf, 0, 0);
}
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. */
}
}
-/* Extract from REGCACHE, which contains the (raw) register state, the
- address in which a function should return its structure value, as a
- CORE_ADDR. */
-
-static CORE_ADDR
-sparc_extract_struct_value_address (struct regcache *regcache)
+static enum return_value_convention
+sparc64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
- ULONGEST addr;
+ if (TYPE_LENGTH (type) > 32)
+ return RETURN_VALUE_STRUCT_CONVENTION;
- regcache_cooked_read_unsigned (regcache, SPARC_O0_REGNUM, &addr);
- return addr;
-}
+ if (readbuf)
+ sparc64_extract_return_value (type, regcache, readbuf);
+ if (writebuf)
+ sparc64_store_return_value (type, regcache, writebuf);
-static int
-sparc64_use_struct_convention (int gcc_p, struct type *type)
-{
- /* Structure and union types up to 32 bytes in size are returned in
- registers. */
- return (TYPE_LENGTH (type) > 32);
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
-
\f
-/* The SPARC Architecture doesn't have hardware single-step support,
- and most operating systems don't implement it either, so we provide
- software single-step mechanism. */
-static CORE_ADDR
-sparc_analyze_control_transfer (CORE_ADDR pc, CORE_ADDR *npc)
+static void
+sparc64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+ struct dwarf2_frame_state_reg *reg,
+ struct frame_info *this_frame)
{
- unsigned long insn = sparc_fetch_instruction (pc);
- int conditional_p = X_COND (insn) & 0x7;
- int branch_p = 0;
- long offset = 0; /* Must be signed for sign-extend. */
-
- if (X_OP (insn) == 0 && X_OP2 (insn) == 3 && (insn & 0x1000000) == 0)
- {
- /* Branch on Integer Register with Prediction (BPr). */
- branch_p = 1;
- conditional_p = 1;
- }
- else if (X_OP (insn) == 0 && X_OP2 (insn) == 6)
- {
- /* Branch on Floating-Point Condition Codes (FBfcc). */
- branch_p = 1;
- offset = 4 * X_DISP22 (insn);
- }
- else if (X_OP (insn) == 0 && X_OP2 (insn) == 5)
- {
- /* Branch on Floating-Point Condition Codes with Prediction
- (FBPfcc). */
- branch_p = 1;
- offset = 4 * X_DISP19 (insn);
- }
- else if (X_OP (insn) == 0 && X_OP2 (insn) == 2)
- {
- /* Branch on Integer Condition Codes (Bicc). */
- branch_p = 1;
- offset = 4 * X_DISP22 (insn);
- }
- else if (X_OP (insn) == 0 && X_OP2 (insn) == 1)
+ switch (regnum)
{
- /* Branch on Integer Condition Codes with Prediction (BPcc). */
- branch_p = 1;
- offset = 4 * X_DISP19 (insn);
- }
-
- /* FIXME: Handle DONE and RETRY instructions. */
-
- /* FIXME: Handle the Trap instruction. */
-
- if (branch_p)
- {
- if (conditional_p)
- {
- /* For conditional branches, return nPC + 4 iff the annul
- bit is 1. */
- return (X_A (insn) ? *npc + 4 : 0);
- }
- else
- {
- /* For unconditional branches, return the target if its
- specified condition is "always" and return nPC + 4 if the
- condition is "never". If the annul bit is 1, set *NPC to
- zero. */
- if (X_COND (insn) == 0x0)
- pc = *npc, offset = 4;
- if (X_A (insn))
- *npc = 0;
-
- gdb_assert (offset != 0);
- return pc + offset;
- }
+ 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;
}
-
- return 0;
}
void
-sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
- static CORE_ADDR npc, nnpc;
- static char npc_save[4], nnpc_save[4];
-
- if (insert_breakpoints_p)
- {
- CORE_ADDR pc;
-
- gdb_assert (npc == 0);
- gdb_assert (nnpc == 0);
-
- pc = sparc_address_from_register (SPARC64_PC_REGNUM);
- npc = sparc_address_from_register (SPARC64_NPC_REGNUM);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- /* Analyze the instruction at PC. */
- nnpc = sparc_analyze_control_transfer (pc, &npc);
- if (npc != 0)
- target_insert_breakpoint (npc, npc_save);
- if (nnpc != 0)
- target_insert_breakpoint (nnpc, nnpc_save);
-
- /* Assert that we have set at least one breakpoint. */
- gdb_assert (npc != 0 || nnpc != 0);
- }
- else
- {
- if (npc != 0)
- target_remove_breakpoint (npc, npc_save);
- if (nnpc != 0)
- target_remove_breakpoint (nnpc, nnpc_save);
-
- npc = 0;
- nnpc = 0;
- }
-}
-\f
-
-static struct gdbarch *
-sparc64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
-{
- struct gdbarch_tdep *tdep;
- struct gdbarch *gdbarch;
-
- /* If there is already a candidate, use it. */
- arches = gdbarch_list_lookup_by_info (arches, &info);
- if (arches != NULL)
- return arches->gdbarch;
-
- /* Allocate space for the new architecture. */
- tdep = XMALLOC (struct gdbarch_tdep);
- gdbarch = gdbarch_alloc (&info, tdep);
+ tdep->pc_regnum = SPARC64_PC_REGNUM;
+ tdep->npc_regnum = SPARC64_NPC_REGNUM;
+ /* This is what all the fuss is about. */
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_ptr_bit (gdbarch, 64);
- set_gdbarch_long_double_bit (gdbarch, 128);
set_gdbarch_num_regs (gdbarch, SPARC64_NUM_REGS);
set_gdbarch_register_name (gdbarch, sparc64_register_name);
set_gdbarch_pseudo_register_write (gdbarch, sparc64_pseudo_register_write);
/* Register numbers of various important registers. */
- set_gdbarch_sp_regnum (gdbarch, SPARC_SP_REGNUM); /* %sp */
set_gdbarch_pc_regnum (gdbarch, SPARC64_PC_REGNUM); /* %pc */
- set_gdbarch_npc_regnum (gdbarch, SPARC64_NPC_REGNUM);
- set_gdbarch_fp0_regnum (gdbarch, SPARC_F0_REGNUM); /* %f0 */
/* Call dummy code. */
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+ set_gdbarch_push_dummy_code (gdbarch, NULL);
set_gdbarch_push_dummy_call (gdbarch, sparc64_push_dummy_call);
- set_gdbarch_extract_return_value (gdbarch, sparc64_extract_return_value);
- set_gdbarch_store_return_value (gdbarch, sparc64_store_return_value);
- set_gdbarch_extract_struct_value_address
- (gdbarch, sparc_extract_struct_value_address);
- set_gdbarch_use_struct_convention (gdbarch, sparc64_use_struct_convention);
+ set_gdbarch_return_value (gdbarch, sparc64_return_value);
+ set_gdbarch_stabs_argument_has_addr
+ (gdbarch, default_stabs_argument_has_addr);
set_gdbarch_skip_prologue (gdbarch, sparc64_skip_prologue);
- /* Stack grows downward. */
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ /* 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. */
- set_gdbarch_breakpoint_from_pc (gdbarch, sparc_breakpoint_from_pc);
- set_gdbarch_decr_pc_after_break (gdbarch, 0);
- set_gdbarch_function_start_offset (gdbarch, 0);
+ frame_unwind_append_unwinder (gdbarch, &sparc64_frame_unwind);
+ frame_base_set_default (gdbarch, &sparc64_frame_base);
+}
+\f
- set_gdbarch_frame_args_skip (gdbarch, 8);
+/* Helper functions for dealing with register sets. */
- set_gdbarch_print_insn (gdbarch, print_insn_sparc);
+#define TSTATE_CWP 0x000000000000001fULL
+#define TSTATE_ICC 0x0000000f00000000ULL
+#define TSTATE_XCC 0x000000f000000000ULL
- set_gdbarch_software_single_step (gdbarch, sparc_software_single_step);
+#define PSR_S 0x00000080
+#define PSR_ICC 0x00f00000
+#define PSR_VERS 0x0f000000
+#define PSR_IMPL 0xf0000000
+#define PSR_V8PLUS 0xff000000
+#define PSR_XCC 0x000f0000
- set_gdbarch_unwind_dummy_id (gdbarch, sparc_unwind_dummy_id);
+void
+sparc64_supply_gregset (const struct sparc_gregset *gregset,
+ struct regcache *regcache,
+ int regnum, const void *gregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 32);
+ const gdb_byte *regs = gregs;
+ int i;
- set_gdbarch_unwind_pc (gdbarch, sparc64_unwind_pc);
+ if (sparc32)
+ {
+ if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
+ {
+ int offset = gregset->r_tstate_offset;
+ ULONGEST tstate, psr;
+ gdb_byte buf[4];
+
+ tstate = extract_unsigned_integer (regs + offset, 8);
+ psr = ((tstate & TSTATE_CWP) | PSR_S | ((tstate & TSTATE_ICC) >> 12)
+ | ((tstate & TSTATE_XCC) >> 20) | PSR_V8PLUS);
+ store_unsigned_integer (buf, 4, psr);
+ regcache_raw_supply (regcache, SPARC32_PSR_REGNUM, buf);
+ }
- frame_base_set_default (gdbarch, &sparc64_frame_base);
+ if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_PC_REGNUM,
+ regs + gregset->r_pc_offset + 4);
- /* Hook in ABI-specific overrides, if they have been registered. */
- gdbarch_init_osabi (info, gdbarch);
+ if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_NPC_REGNUM,
+ regs + gregset->r_npc_offset + 4);
- frame_unwind_append_sniffer (gdbarch, sparc64_frame_sniffer);
+ if (regnum == SPARC32_Y_REGNUM || regnum == -1)
+ {
+ int offset = gregset->r_y_offset + 8 - gregset->r_y_size;
+ regcache_raw_supply (regcache, SPARC32_Y_REGNUM, regs + offset);
+ }
+ }
+ else
+ {
+ if (regnum == SPARC64_STATE_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_STATE_REGNUM,
+ regs + gregset->r_tstate_offset);
- return gdbarch;
-}
-\f
-/* Helper functions for dealing with register windows. */
+ if (regnum == SPARC64_PC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_PC_REGNUM,
+ regs + gregset->r_pc_offset);
-static void
-sparc_supply_rwindow (CORE_ADDR sp, int regnum)
-{
- int offset = 0;
- char buf[8];
- int i;
+ if (regnum == SPARC64_NPC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_NPC_REGNUM,
+ regs + gregset->r_npc_offset);
+
+ if (regnum == SPARC64_Y_REGNUM || regnum == -1)
+ {
+ gdb_byte buf[8];
+
+ memset (buf, 0, 8);
+ memcpy (buf + 8 - gregset->r_y_size,
+ regs + gregset->r_y_offset, gregset->r_y_size);
+ regcache_raw_supply (regcache, SPARC64_Y_REGNUM, buf);
+ }
+
+ if ((regnum == SPARC64_FPRS_REGNUM || regnum == -1)
+ && gregset->r_fprs_offset != -1)
+ regcache_raw_supply (regcache, SPARC64_FPRS_REGNUM,
+ regs + gregset->r_fprs_offset);
+ }
+
+ if (regnum == SPARC_G0_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC_G0_REGNUM, NULL);
- /* Clear out the top half of the temporary buffer, and put the
- register value in the bottom half if we're in 64-bit mode. */
- if (gdbarch_ptr_bit (current_gdbarch) == 64)
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
{
- memset (buf, 0, 4);
- offset = 4;
+ int offset = gregset->r_g1_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_supply (regcache, i, regs + offset);
+ offset += 8;
+ }
}
- for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ if ((regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM) || regnum == -1)
{
- if (regnum == i || regnum == -1)
+ /* Not all of the register set variants include Locals and
+ Inputs. For those that don't, we read them off the stack. */
+ if (gregset->r_l0_offset == -1)
+ {
+ ULONGEST sp;
+
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ sparc_supply_rwindow (regcache, sp, regnum);
+ }
+ else
{
- target_read_memory (sp + ((i - SPARC_L0_REGNUM) * 4),
- buf + offset, 4);
- supply_register (i, buf);
+ int offset = gregset->r_l0_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_supply (regcache, i, regs + offset);
+ offset += 8;
+ }
}
}
}
void
-sparc64_supply_rwindow (CORE_ADDR sp, int regnum)
+sparc64_collect_gregset (const struct sparc_gregset *gregset,
+ const struct regcache *regcache,
+ int regnum, void *gregs)
{
- if (sp & 1)
+ int sparc32 = (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 32);
+ gdb_byte *regs = gregs;
+ int i;
+
+ if (sparc32)
{
- char buf[8];
- int i;
+ if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
+ {
+ int offset = gregset->r_tstate_offset;
+ ULONGEST tstate, psr;
+ gdb_byte buf[8];
+
+ tstate = extract_unsigned_integer (regs + offset, 8);
+ regcache_raw_collect (regcache, SPARC32_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 4);
+ tstate |= (psr & PSR_ICC) << 12;
+ if ((psr & (PSR_VERS | PSR_IMPL)) == PSR_V8PLUS)
+ tstate |= (psr & PSR_XCC) << 20;
+ store_unsigned_integer (buf, 8, tstate);
+ memcpy (regs + offset, buf, 8);
+ }
- /* Registers are 64-bit. */
- sp += BIAS;
+ if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_PC_REGNUM,
+ regs + gregset->r_pc_offset + 4);
- for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_NPC_REGNUM,
+ regs + gregset->r_npc_offset + 4);
+
+ if (regnum == SPARC32_Y_REGNUM || regnum == -1)
{
- if (regnum == i || regnum == -1)
- {
- target_read_memory (sp + ((i - SPARC_L0_REGNUM) * 8),
- buf, sizeof (buf));
- supply_register (i, buf);
- }
+ int offset = gregset->r_y_offset + 8 - gregset->r_y_size;
+ regcache_raw_collect (regcache, SPARC32_Y_REGNUM, regs + offset);
}
}
else
{
- /* Registers are 32-bit. Toss any sign-extension of the stack
- pointer. */
- sparc_supply_rwindow (sp & 0xffffffffUL, regnum);
+ if (regnum == SPARC64_STATE_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_STATE_REGNUM,
+ regs + gregset->r_tstate_offset);
+
+ if (regnum == SPARC64_PC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_PC_REGNUM,
+ regs + gregset->r_pc_offset);
+
+ if (regnum == SPARC64_NPC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_NPC_REGNUM,
+ regs + gregset->r_npc_offset);
+
+ if (regnum == SPARC64_Y_REGNUM || regnum == -1)
+ {
+ gdb_byte buf[8];
+
+ regcache_raw_collect (regcache, SPARC64_Y_REGNUM, buf);
+ memcpy (regs + gregset->r_y_offset,
+ buf + 8 - gregset->r_y_size, gregset->r_y_size);
+ }
+
+ if ((regnum == SPARC64_FPRS_REGNUM || regnum == -1)
+ && gregset->r_fprs_offset != -1)
+ regcache_raw_collect (regcache, SPARC64_FPRS_REGNUM,
+ regs + gregset->r_fprs_offset);
+
+ }
+
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
+ {
+ int offset = gregset->r_g1_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ /* %g0 is always zero. */
+ for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_collect (regcache, i, regs + offset);
+ offset += 8;
+ }
+ }
+
+ if ((regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM) || regnum == -1)
+ {
+ /* Not all of the register set variants include Locals and
+ Inputs. For those that don't, we read them off the stack. */
+ if (gregset->r_l0_offset != -1)
+ {
+ int offset = gregset->r_l0_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ {
+ if (regnum == i || regnum == -1)
+ regcache_raw_collect (regcache, i, regs + offset);
+ offset += 8;
+ }
+ }
}
}
-static void
-sparc_fill_rwindow (CORE_ADDR sp, int regnum)
+void
+sparc64_supply_fpregset (struct regcache *regcache,
+ int regnum, const void *fpregs)
{
- int offset = 0;
- char buf[8];
+ int sparc32 = (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 32);
+ const gdb_byte *regs = fpregs;
int i;
- /* Only use the bottom half if we're in 64-bit mode. */
- if (gdbarch_ptr_bit (current_gdbarch) == 64)
- offset = 4;
+ for (i = 0; i < 32; i++)
+ {
+ if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
+ regcache_raw_supply (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+ }
- for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ if (sparc32)
{
- if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i)
+ if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_FSR_REGNUM,
+ regs + (32 * 4) + (16 * 8) + 4);
+ }
+ else
+ {
+ for (i = 0; i < 16; i++)
{
- regcache_collect (i, buf);
- target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 4), buf, 4);
+ if (regnum == (SPARC64_F32_REGNUM + i) || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_F32_REGNUM + i,
+ regs + (32 * 4) + (i * 8));
}
+
+ if (regnum == SPARC64_FSR_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_FSR_REGNUM,
+ regs + (32 * 4) + (16 * 8));
}
}
void
-sparc64_fill_rwindow (CORE_ADDR sp, int regnum)
+sparc64_collect_fpregset (const struct regcache *regcache,
+ int regnum, void *fpregs)
{
- if (sp & 1)
- {
- char buf[8];
- int i;
+ int sparc32 = (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 32);
+ gdb_byte *regs = fpregs;
+ int i;
- /* Registers are 64-bit. */
- sp += BIAS;
+ for (i = 0; i < 32; i++)
+ {
+ if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
+ regcache_raw_collect (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+ }
- for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
- {
- if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i)
- {
- regcache_collect (i, buf);
- target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 8),
- buf, sizeof (buf));
- }
- }
+ if (sparc32)
+ {
+ if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_FSR_REGNUM,
+ regs + (32 * 4) + (16 * 8) + 4);
}
else
{
- /* Registers are 32-bit. Toss any sign-extension of the stack
- pointer. */
- sparc_fill_rwindow (sp & 0xffffffffUL, regnum);
+ for (i = 0; i < 16; i++)
+ {
+ if (regnum == (SPARC64_F32_REGNUM + i) || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_F32_REGNUM + i,
+ regs + (32 * 4) + (i * 8));
+ }
+
+ if (regnum == SPARC64_FSR_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC64_FSR_REGNUM,
+ regs + (32 * 4) + (16 * 8));
}
}
-\f
+
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_sparc64_tdep (void);
void
_initialize_sparc64_tdep (void)
{
- register_gdbarch_init (bfd_arch_sparc, sparc64_gdbarch_init);
+ /* Initialize the UltraSPARC-specific register types. */
+ sparc64_init_types();
}