/* Target-dependent code for UltraSPARC.
- Copyright 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005 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"
#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;
}
-/* UltraSPARC architecture specific information. */
-
-struct gdbarch_tdep
-{
- /* Offset of saved PC in jmp_buf. */
- int jb_pc_offset;
-};
-
/* Register information. */
struct sparc64_register_info
};
/* 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_info)
/* We provide the aliases %d0..%d62 and %q0..%q60 for the floating
registers as "psuedo" registers. */
};
/* 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_info)
/* Return the name of register 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
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
regcache_raw_write_unsigned (regcache, SPARC64_STATE_REGNUM, state);
}
}
-
-/* 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)
- {
- cache->frameless_p = 0;
- return pc + 4;
- }
-
- 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);
-}
-
/* Return PC of first real instruction of the function starting at
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 (start_pc, 0xffffffffffffffffULL, &cache);
}
/* Normal frames. */
-static struct sparc64_frame_cache *
+static struct sparc_frame_cache *
sparc64_frame_cache (struct frame_info *next_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 (next_frame, this_cache);
}
static void
sparc64_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
- struct sparc64_frame_cache *cache =
+ struct sparc_frame_cache *cache =
sparc64_frame_cache (next_frame, this_cache);
/* This marks the outermost frame. */
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 sparc64_frame_cache *cache =
+ struct sparc_frame_cache *cache =
sparc64_frame_cache (next_frame, this_cache);
if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
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 =
static CORE_ADDR
sparc64_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
- struct sparc64_frame_cache *cache =
+ struct sparc_frame_cache *cache =
sparc64_frame_cache (next_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)
/* 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))
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);
}
}
}
-/* 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 *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)
{
- 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)
+ switch (regnum)
{
- /* Branch on Integer Condition Codes (Bicc). */
- branch_p = 1;
- offset = 4 * X_DISP22 (insn);
- }
- else if (X_OP (insn) == 0 && X_OP2 (insn) == 1)
- {
- /* 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)
-{
- static CORE_ADDR npc, nnpc;
- static char npc_save[4], nnpc_save[4];
-
- if (insert_breakpoints_p)
- {
- CORE_ADDR pc;
-
- pc = sparc_address_from_register (SPARC64_PC_REGNUM);
- npc = sparc_address_from_register (SPARC64_NPC_REGNUM);
-
- /* 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)
+sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
- 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;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (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);
-
- 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);
-
- set_gdbarch_frame_args_skip (gdbarch, 8);
-
- set_gdbarch_print_insn (gdbarch, print_insn_sparc);
-
- set_gdbarch_software_single_step (gdbarch, sparc_software_single_step);
-
- set_gdbarch_unwind_dummy_id (gdbarch, sparc_unwind_dummy_id);
-
- set_gdbarch_unwind_pc (gdbarch, sparc64_unwind_pc);
+ /* 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);
+}
+\f
- /* Hook in ABI-specific overrides, if they have been registered. */
- gdbarch_init_osabi (info, gdbarch);
+/* Helper functions for dealing with register sets. */
- frame_unwind_append_sniffer (gdbarch, sparc64_frame_sniffer);
+#define TSTATE_CWP 0x000000000000001fULL
+#define TSTATE_ICC 0x0000000f00000000ULL
+#define TSTATE_XCC 0x000000f000000000ULL
- return gdbarch;
-}
-\f
-/* Helper functions for dealing with register windows. */
+#define PSR_S 0x00000080
+#define PSR_ICC 0x00f00000
+#define PSR_VERS 0x0f000000
+#define PSR_IMPL 0xf0000000
+#define PSR_V8PLUS 0xff000000
+#define PSR_XCC 0x000f0000
void
-sparc_supply_rwindow (CORE_ADDR sp, int regnum)
+sparc64_supply_gregset (const struct sparc_gregset *gregset,
+ struct regcache *regcache,
+ int regnum, const void *gregs)
{
- int offset = 0;
- char buf[8];
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+ const gdb_byte *regs = gregs;
int i;
- if (sp & 1)
+ if (sparc32)
{
- /* Registers are 64-bit. */
- sp += BIAS;
+ 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);
+ }
+
+ if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_PC_REGNUM,
+ regs + gregset->r_pc_offset + 4);
+
+ if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC32_NPC_REGNUM,
+ regs + gregset->r_npc_offset + 4);
- for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ if (regnum == SPARC32_Y_REGNUM || regnum == -1)
{
- if (regnum == i || regnum == -1)
- {
- target_read_memory (sp + ((i - SPARC_L0_REGNUM) * 8), buf, 8);
- supply_register (i, buf);
- }
+ int offset = gregset->r_y_offset + 8 - gregset->r_y_size;
+ regcache_raw_supply (regcache, SPARC32_Y_REGNUM, regs + offset);
}
}
else
{
- /* Registers are 32-bit. Toss any sign-extension of the stack
- pointer. */
- sp &= 0xffffffffUL;
+ if (regnum == SPARC64_STATE_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_STATE_REGNUM,
+ regs + gregset->r_tstate_offset);
- /* 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 == SPARC64_PC_REGNUM || regnum == -1)
+ regcache_raw_supply (regcache, SPARC64_PC_REGNUM,
+ regs + gregset->r_pc_offset);
+
+ 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)
{
- memset (buf, 0, 4);
- offset = 4;
+ 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);
}
- for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ 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);
+
+ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
+ {
+ 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;
+ }
+ }
+
+ 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)
+ {
+ ULONGEST sp;
+
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ sparc_supply_rwindow (regcache, sp, regnum);
+ }
+ else
+ {
+ int offset = gregset->r_l0_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
{
- target_read_memory (sp + ((i - SPARC_L0_REGNUM) * 4),
- buf + offset, 4);
- supply_register (i, buf);
+ if (regnum == i || regnum == -1)
+ regcache_raw_supply (regcache, i, regs + offset);
+ offset += 8;
}
}
}
}
void
-sparc_fill_rwindow (CORE_ADDR sp, int regnum)
+sparc64_collect_gregset (const struct sparc_gregset *gregset,
+ const struct regcache *regcache,
+ int regnum, void *gregs)
{
- int offset = 0;
- char buf[8];
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+ gdb_byte *regs = gregs;
int i;
- if (sp & 1)
+ if (sparc32)
{
- /* Registers are 64-bit. */
- sp += BIAS;
+ 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);
+ }
+
+ if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_PC_REGNUM,
+ regs + gregset->r_pc_offset + 4);
+
+ if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_NPC_REGNUM,
+ regs + gregset->r_npc_offset + 4);
- for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ if (regnum == SPARC32_Y_REGNUM || regnum == -1)
{
- if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i)
- {
- regcache_collect (i, buf);
- target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 8), buf, 8);
- }
+ 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. */
- sp &= 0xffffffffUL;
+ 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;
- /* Only use the bottom half if we're in 64-bit mode. */
- if (gdbarch_ptr_bit (current_gdbarch) == 64)
- 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;
+ }
+ }
- for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
+ 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)
{
- if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i)
+ int offset = gregset->r_l0_offset;
+
+ if (sparc32)
+ offset += 4;
+
+ for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
{
- regcache_collect (i, buf);
- target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 4),
- buf + offset, 4);
+ if (regnum == i || regnum == -1)
+ regcache_raw_collect (regcache, i, regs + offset);
+ offset += 8;
}
}
}
}
-\f
-/* Provide a prototype to silence -Wmissing-prototypes. */
-void _initialize_sparc64_tdep (void);
+void
+sparc64_supply_fpregset (struct regcache *regcache,
+ int regnum, const void *fpregs)
+{
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+ const gdb_byte *regs = fpregs;
+ int i;
+
+ 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));
+ }
+
+ if (sparc32)
+ {
+ 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++)
+ {
+ 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
-_initialize_sparc64_tdep (void)
+sparc64_collect_fpregset (const struct regcache *regcache,
+ int regnum, void *fpregs)
{
- register_gdbarch_init (bfd_arch_sparc, sparc64_gdbarch_init);
+ int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
+ gdb_byte *regs = fpregs;
+ int i;
+
+ 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));
+ }
+
+ if (sparc32)
+ {
+ if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, SPARC32_FSR_REGNUM,
+ regs + (32 * 4) + (16 * 8) + 4);
+ }
+ else
+ {
+ 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));
+ }
}