/* Target-dependent code for SPARC.
- Copyright 2003, 2004 Free Software Foundation, Inc.
+ Copyright 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GDB.
struct regset;
-/* This file implements the The SPARC 32-bit ABI as defined by the
- section "Low-Level System Information" of the SPARC Compliance
- Definition (SCD) 2.4.1, which is the 32-bit System V psABI for
- SPARC. The SCD lists changes with respect to the origional 32-bit
- psABI as defined in the "System V ABI, SPARC Processor
- Supplement".
+/* This file implements the SPARC 32-bit ABI as defined by the section
+ "Low-Level System Information" of the SPARC Compliance Definition
+ (SCD) 2.4.1, which is the 32-bit System V psABI for SPARC. The SCD
+ lists changes with respect to the original 32-bit psABI as defined
+ in the "System V ABI, SPARC Processor Supplement".
Note that if we talk about SunOS, we mean SunOS 4.x, which was
BSD-based, which is sometimes (retroactively?) referred to as
#define X_OP2(i) (((i) >> 22) & 0x7)
#define X_IMM22(i) ((i) & 0x3fffff)
#define X_OP3(i) (((i) >> 19) & 0x3f)
+#define X_RS1(i) (((i) >> 14) & 0x1f)
#define X_I(i) (((i) >> 13) & 1)
/* Sign extension macros. */
#define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
#define X_DISP19(i) ((((i) & 0x7ffff) ^ 0x40000) - 0x40000)
+#define X_SIMM13(i) ((((i) & 0x1fff) ^ 0x1000) - 0x1000)
/* Fetch the instruction at PC. Instructions are always big-endian
even if the processor operates in little-endian mode. */
}
\f
+/* Return non-zero if the instruction corresponding to PC is an "unimp"
+ instruction. */
+
+static int
+sparc_is_unimp_insn (CORE_ADDR pc)
+{
+ const unsigned long insn = sparc_fetch_instruction (pc);
+
+ return ((insn & 0xc1c00000) == 0);
+}
+
/* OpenBSD/sparc includes StackGhost, which according to the author's
website http://stackghost.cerias.purdue.edu "... transparently and
automatically protects applications' stack frames; more
static int
sparc_integral_or_pointer_p (const struct type *type)
{
+ int len = TYPE_LENGTH (type);
+
switch (TYPE_CODE (type))
{
case TYPE_CODE_INT:
case TYPE_CODE_CHAR:
case TYPE_CODE_ENUM:
case TYPE_CODE_RANGE:
- {
- /* We have byte, half-word, word and extended-word/doubleword
- integral types. The doubleword is an extension to the
- origional 32-bit ABI by the SCD 2.4.x. */
- int len = TYPE_LENGTH (type);
- return (len == 1 || len == 2 || len == 4 || len == 8);
- }
- return 1;
+ /* We have byte, half-word, word and extended-word/doubleword
+ integral types. The doubleword is an extension to the
+ original 32-bit ABI by the SCD 2.4.x. */
+ return (len == 1 || len == 2 || len == 4 || len == 8);
case TYPE_CODE_PTR:
case TYPE_CODE_REF:
- {
- /* Allow either 32-bit or 64-bit pointers. */
- int len = TYPE_LENGTH (type);
- return (len == 4 || len == 8);
- }
- return 1;
+ /* Allow either 32-bit or 64-bit pointers. */
+ return (len == 4 || len == 8);
default:
break;
}
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 (sparc_structure_or_union_p (type)
correct, and wasting a few bytes shouldn't be a problem. */
sp &= ~0x7;
- 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 bfd_byte *valbuf = value_contents (args[i]);
+ struct type *type = value_type (args[i]);
int len = TYPE_LENGTH (type);
gdb_assert (len == 4 || len == 8);
}
static CORE_ADDR
-sparc32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+sparc32_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)
return sal.end;
}
- return sparc_analyze_prologue (start_pc, 0xffffffffUL, &cache);
+ start_pc = sparc_analyze_prologue (start_pc, 0xffffffffUL, &cache);
+
+ /* The psABI says that "Although the first 6 words of arguments
+ reside in registers, the standard stack frame reserves space for
+ them.". It also suggests that a function may use that space to
+ "write incoming arguments 0 to 5" into that space, and that's
+ indeed what GCC seems to be doing. In that case GCC will
+ generate debug information that points to the stack slots instead
+ of the registers, so we should consider the instructions that
+ write out these incoming arguments onto the stack. Of course we
+ only need to do this if we have a stack frame. */
+
+ while (!cache.frameless_p)
+ {
+ unsigned long insn = sparc_fetch_instruction (start_pc);
+
+ /* Recognize instructions that store incoming arguments in
+ %i0...%i5 into the corresponding stack slot. */
+ if (X_OP (insn) == 3 && (X_OP3 (insn) & 0x3c) == 0x04 && X_I (insn)
+ && (X_RD (insn) >= 24 && X_RD (insn) <= 29) && X_RS1 (insn) == 30
+ && X_SIMM13 (insn) == 68 + (X_RD (insn) - 24) * 4)
+ {
+ start_pc += 4;
+ continue;
+ }
+
+ break;
+ }
+
+ return start_pc;
}
/* Normal frames. */
cache = sparc_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)
{
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);
+ /* This function is frameless, so %fp (%i6) holds the frame
+ pointer for our calling frame. Use %sp (%o6) as this frame's
+ base address. */
+ cache->base =
+ frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
}
+ else
+ {
+ /* For normal frames, %fp (%i6) holds the frame pointer, the
+ base address for the current stack frame. */
+ cache->base =
+ frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
+ }
+
+ if (cache->base & 1)
+ cache->base += BIAS;
return cache;
}
cache->struct_return_p = 1;
}
}
+ else
+ {
+ /* There is no debugging information for this function to
+ help us determine whether this function returns a struct
+ or not. So we rely on another heuristic which is to check
+ the instruction at the return address and see if this is
+ an "unimp" instruction. If it is, then it is a struct-return
+ function. */
+ CORE_ADDR pc;
+ int regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
+
+ pc = frame_unwind_register_unsigned (next_frame, regnum) + 8;
+ if (sparc_is_unimp_insn (pc))
+ cache->struct_return_p = 1;
+ }
return cache;
}
&& 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, (*realnump), valuep);
}
static const struct frame_unwind sparc32_frame_unwind =
CORE_ADDR sp;
sp = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
+ if (sp & 1)
+ sp += BIAS;
return frame_id_build (sp, frame_pc_unwind (next_frame));
}
\f
if (insert_breakpoints_p)
{
- CORE_ADDR pc;
+ CORE_ADDR pc, orig_npc;
pc = sparc_address_from_register (tdep->pc_regnum);
- npc = sparc_address_from_register (tdep->npc_regnum);
+ orig_npc = npc = sparc_address_from_register (tdep->npc_regnum);
/* Analyze the instruction at PC. */
nnpc = sparc_analyze_control_transfer (pc, &npc);
target_insert_breakpoint (nnpc, nnpc_save);
/* Assert that we have set at least one breakpoint, and that
- they're not set at the same spot. */
- gdb_assert (npc != 0 || nnpc != 0);
- gdb_assert (nnpc != npc);
+ they're not set at the same spot - unless we're going
+ from here straight to NULL, i.e. a call or jump to 0. */
+ gdb_assert (npc != 0 || nnpc != 0 || orig_npc == 0);
+ gdb_assert (nnpc != npc || orig_npc == 0);
}
else
{
if (regnum == i || regnum == -1)
{
target_read_memory (sp + ((i - SPARC_L0_REGNUM) * 8), buf, 8);
+
+ /* Handle StackGhost. */
+ if (i == SPARC_I7_REGNUM)
+ {
+ ULONGEST wcookie = sparc_fetch_wcookie ();
+ ULONGEST i7 = extract_unsigned_integer (buf + offset, 8);
+
+ store_unsigned_integer (buf + offset, 8, i7 ^ wcookie);
+ }
+
regcache_raw_supply (regcache, i, buf);
}
}
if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i)
{
regcache_raw_collect (regcache, i, buf);
+
+ /* Handle StackGhost. */
+ if (i == SPARC_I7_REGNUM)
+ {
+ ULONGEST wcookie = sparc_fetch_wcookie ();
+ ULONGEST i7 = extract_unsigned_integer (buf + offset, 8);
+
+ store_unsigned_integer (buf, 8, i7 ^ wcookie);
+ }
+
target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 8), buf, 8);
}
}