/* Target-dependent code for SPARC.
- Copyright (C) 2003-2014 Free Software Foundation, Inc.
+ Copyright (C) 2003-2015 Free Software Foundation, Inc.
This file is part of GDB.
#include "target.h"
#include "value.h"
-#include "gdb_assert.h"
-#include <string.h>
-
#include "sparc-tdep.h"
#include "sparc-ravenscar-thread.h"
#define X_DISP19(i) ((((i) & 0x7ffff) ^ 0x40000) - 0x40000)
#define X_DISP10(i) ((((((i) >> 11) && 0x300) | (((i) >> 5) & 0xff)) ^ 0x200) - 0x200)
#define X_SIMM13(i) ((((i) & 0x1fff) ^ 0x1000) - 0x1000)
+/* Macros to identify some instructions. */
+/* RETURN (RETT in V8) */
+#define X_RETTURN(i) ((X_OP (i) == 0x2) && (X_OP3 (i) == 0x39))
/* Fetch the instruction at PC. Instructions are always big-endian
even if the processor operates in little-endian mode. */
regcache_raw_write (regcache, regnum + 1, buf + 4);
}
\f
+/* Implement the stack_frame_destroyed_p gdbarch method. */
+
+int
+sparc_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ /* This function must return true if we are one instruction after an
+ instruction that destroyed the stack frame of the current
+ function. The SPARC instructions used to restore the callers
+ stack frame are RESTORE and RETURN/RETT.
+
+ Of these RETURN/RETT is a branch instruction and thus we return
+ true if we are in its delay slot.
+
+ RESTORE is almost always found in the delay slot of a branch
+ instruction that transfers control to the caller, such as JMPL.
+ Thus the next instruction is in the caller frame and we don't
+ need to do anything about it. */
+
+ unsigned int insn = sparc_fetch_instruction (pc - 4);
+
+ return X_RETTURN (insn);
+}
+\f
static CORE_ADDR
sparc32_frame_align (struct gdbarch *gdbarch, CORE_ADDR address)
}
\f
-/* Return the appropriate register set for the core section identified
- by SECT_NAME and SECT_SIZE. */
+/* Iterate over core file register note sections. */
-static const struct regset *
-sparc_regset_from_core_section (struct gdbarch *gdbarch,
- const char *sect_name, size_t sect_size)
+static void
+sparc_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (strcmp (sect_name, ".reg") == 0 && sect_size >= tdep->sizeof_gregset)
- return tdep->gregset;
-
- if (strcmp (sect_name, ".reg2") == 0 && sect_size >= tdep->sizeof_fpregset)
- return tdep->fpregset;
-
- return NULL;
+ cb (".reg", tdep->sizeof_gregset, tdep->gregset, NULL, cb_data);
+ cb (".reg2", tdep->sizeof_fpregset, tdep->fpregset, NULL, cb_data);
}
\f
/* If we have register sets, enable the generic core file support. */
if (tdep->gregset)
- set_gdbarch_regset_from_core_section (gdbarch,
- sparc_regset_from_core_section);
+ set_gdbarch_iterate_over_regset_sections
+ (gdbarch, sparc_iterate_over_regset_sections);
register_sparc_ravenscar_ops (gdbarch);
/* Helper functions for dealing with register sets. */
void
-sparc32_supply_gregset (const struct sparc_gregset *gregset,
+sparc32_supply_gregset (const struct sparc_gregmap *gregmap,
struct regcache *regcache,
int regnum, const void *gregs)
{
if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
regcache_raw_supply (regcache, SPARC32_PSR_REGNUM,
- regs + gregset->r_psr_offset);
+ regs + gregmap->r_psr_offset);
if (regnum == SPARC32_PC_REGNUM || regnum == -1)
regcache_raw_supply (regcache, SPARC32_PC_REGNUM,
- regs + gregset->r_pc_offset);
+ regs + gregmap->r_pc_offset);
if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
regcache_raw_supply (regcache, SPARC32_NPC_REGNUM,
- regs + gregset->r_npc_offset);
+ regs + gregmap->r_npc_offset);
if (regnum == SPARC32_Y_REGNUM || regnum == -1)
regcache_raw_supply (regcache, SPARC32_Y_REGNUM,
- regs + gregset->r_y_offset);
+ regs + gregmap->r_y_offset);
if (regnum == SPARC_G0_REGNUM || regnum == -1)
regcache_raw_supply (regcache, SPARC_G0_REGNUM, &zero);
if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
{
- int offset = gregset->r_g1_offset;
+ int offset = gregmap->r_g1_offset;
for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
{
{
/* 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 (gregmap->r_l0_offset == -1)
{
ULONGEST sp;
}
else
{
- int offset = gregset->r_l0_offset;
+ int offset = gregmap->r_l0_offset;
for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
{
}
void
-sparc32_collect_gregset (const struct sparc_gregset *gregset,
+sparc32_collect_gregset (const struct sparc_gregmap *gregmap,
const struct regcache *regcache,
int regnum, void *gregs)
{
if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
regcache_raw_collect (regcache, SPARC32_PSR_REGNUM,
- regs + gregset->r_psr_offset);
+ regs + gregmap->r_psr_offset);
if (regnum == SPARC32_PC_REGNUM || regnum == -1)
regcache_raw_collect (regcache, SPARC32_PC_REGNUM,
- regs + gregset->r_pc_offset);
+ regs + gregmap->r_pc_offset);
if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
regcache_raw_collect (regcache, SPARC32_NPC_REGNUM,
- regs + gregset->r_npc_offset);
+ regs + gregmap->r_npc_offset);
if (regnum == SPARC32_Y_REGNUM || regnum == -1)
regcache_raw_collect (regcache, SPARC32_Y_REGNUM,
- regs + gregset->r_y_offset);
+ regs + gregmap->r_y_offset);
if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
{
- int offset = gregset->r_g1_offset;
+ int offset = gregmap->r_g1_offset;
/* %g0 is always zero. */
for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
{
/* 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 (gregmap->r_l0_offset != -1)
{
- int offset = gregset->r_l0_offset;
+ int offset = gregmap->r_l0_offset;
for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
{
}
void
-sparc32_supply_fpregset (const struct sparc_fpregset *fpregset,
+sparc32_supply_fpregset (const struct sparc_fpregmap *fpregmap,
struct regcache *regcache,
int regnum, const void *fpregs)
{
{
if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
regcache_raw_supply (regcache, SPARC_F0_REGNUM + i,
- regs + fpregset->r_f0_offset + (i * 4));
+ regs + fpregmap->r_f0_offset + (i * 4));
}
if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
regcache_raw_supply (regcache, SPARC32_FSR_REGNUM,
- regs + fpregset->r_fsr_offset);
+ regs + fpregmap->r_fsr_offset);
}
void
-sparc32_collect_fpregset (const struct sparc_fpregset *fpregset,
+sparc32_collect_fpregset (const struct sparc_fpregmap *fpregmap,
const struct regcache *regcache,
int regnum, void *fpregs)
{
{
if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
regcache_raw_collect (regcache, SPARC_F0_REGNUM + i,
- regs + fpregset->r_f0_offset + (i * 4));
+ regs + fpregmap->r_f0_offset + (i * 4));
}
if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
regcache_raw_collect (regcache, SPARC32_FSR_REGNUM,
- regs + fpregset->r_fsr_offset);
+ regs + fpregmap->r_fsr_offset);
}
\f
/* SunOS 4. */
/* From <machine/reg.h>. */
-const struct sparc_gregset sparc32_sunos4_gregset =
+const struct sparc_gregmap sparc32_sunos4_gregmap =
{
0 * 4, /* %psr */
1 * 4, /* %pc */
-1 /* %l0 */
};
-const struct sparc_fpregset sparc32_sunos4_fpregset =
+const struct sparc_fpregmap sparc32_sunos4_fpregmap =
{
0 * 4, /* %f0 */
33 * 4, /* %fsr */
};
-const struct sparc_fpregset sparc32_bsd_fpregset =
+const struct sparc_fpregmap sparc32_bsd_fpregmap =
{
0 * 4, /* %f0 */
32 * 4, /* %fsr */