/* Target-dependent code for SPARC.
- Copyright 2003, 2004 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 "dis-asm.h"
+#include "dwarf2-frame.h"
#include "floatformat.h"
#include "frame.h"
#include "frame-base.h"
/* The SPARC Floating-Point Quad-Precision format is similar to
big-endian IA-64 Quad-recision format. */
-#define floatformat_sparc_quad floatformat_ia64_quad_big
+#define floatformats_sparc_quad floatformats_ia64_quad
/* 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
#define X_IMM22(i) ((i) & 0x3fffff)
#define X_OP3(i) (((i) >> 19) & 0x3f)
#define X_RS1(i) (((i) >> 14) & 0x1f)
+#define X_RS2(i) ((i) & 0x1f)
#define X_I(i) (((i) >> 13) & 1)
/* Sign extension macros. */
#define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
unsigned long
sparc_fetch_instruction (CORE_ADDR pc)
{
- unsigned char buf[4];
+ gdb_byte buf[4];
unsigned long insn;
int i;
sparc_fetch_wcookie (void)
{
struct target_ops *ops = ¤t_target;
- char buf[8];
+ gdb_byte buf[8];
int len;
- len = target_read_partial (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8);
+ len = target_read (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8);
if (len == -1)
return 0;
}
\f
-/* 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;
-}
-\f
-
/* The functions on this page are intended to be used to classify
function arguments. */
/* Return the name of register REGNUM. */
static const char *
-sparc32_register_name (int regnum)
+sparc32_register_name (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= 0 && regnum < SPARC32_NUM_REGS)
return sparc32_register_names[regnum];
return NULL;
}
+\f
+
+/* Type for %psr. */
+struct type *sparc_psr_type;
+
+/* Type for %fsr. */
+struct type *sparc_fsr_type;
+
+/* Construct types for ISA-specific registers. */
+
+static void
+sparc_init_types (void)
+{
+ struct type *type;
+
+ type = init_flags_type ("builtin_type_sparc_psr", 4);
+ append_flags_type_flag (type, 5, "ET");
+ append_flags_type_flag (type, 6, "PS");
+ append_flags_type_flag (type, 7, "S");
+ append_flags_type_flag (type, 12, "EF");
+ append_flags_type_flag (type, 13, "EC");
+ sparc_psr_type = type;
+
+ type = init_flags_type ("builtin_type_sparc_fsr", 4);
+ 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");
+ sparc_fsr_type = type;
+}
/* Return the GDB type object for the "standard" data type of data in
register REGNUM. */
sparc32_register_type (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
- return builtin_type_float;
+ return builtin_type (gdbarch)->builtin_float;
if (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM)
- return builtin_type_double;
+ return builtin_type (gdbarch)->builtin_double;
if (regnum == SPARC_SP_REGNUM || regnum == SPARC_FP_REGNUM)
- return builtin_type_void_data_ptr;
+ return builtin_type (gdbarch)->builtin_data_ptr;
if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM)
- return builtin_type_void_func_ptr;
+ return builtin_type (gdbarch)->builtin_func_ptr;
+
+ if (regnum == SPARC32_PSR_REGNUM)
+ return sparc_psr_type;
+
+ if (regnum == SPARC32_FSR_REGNUM)
+ return sparc_fsr_type;
return builtin_type_int32;
}
static void
sparc32_pseudo_register_read (struct gdbarch *gdbarch,
struct regcache *regcache,
- int regnum, void *buf)
+ int regnum, gdb_byte *buf)
{
gdb_assert (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM);
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC32_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);
}
static void
sparc32_pseudo_register_write (struct gdbarch *gdbarch,
struct regcache *regcache,
- int regnum, const void *buf)
+ int regnum, const gdb_byte *buf)
{
gdb_assert (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM);
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC32_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);
}
\f
static CORE_ADDR
sparc32_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
- CORE_ADDR funcaddr, int using_gcc,
+ CORE_ADDR funcaddr,
struct value **args, int nargs,
struct type *value_type,
- CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+ struct regcache *regcache)
{
*bp_addr = sp - 4;
*real_pc = funcaddr;
- if (using_struct_return (value_type, using_gcc))
+ if (using_struct_return (NULL, value_type))
{
- char buf[4];
+ gdb_byte buf[4];
/* This is an UNIMP instruction. */
store_unsigned_integer (buf, 4, TYPE_LENGTH (value_type) & 0x1fff);
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]);
+ const bfd_byte *valbuf = value_contents (args[i]);
struct type *type = value_type (args[i]);
int len = TYPE_LENGTH (type);
if (struct_return)
{
- char buf[4];
+ gdb_byte buf[4];
store_unsigned_integer (buf, 4, struct_addr);
write_memory (sp, buf, 4);
*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 const gdb_byte *
+sparc_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc, int *len)
{
- static unsigned char break_insn[] = { 0x91, 0xd0, 0x20, 0x01 };
+ static const gdb_byte break_insn[] = { 0x91, 0xd0, 0x20, 0x01 };
*len = sizeof (break_insn);
return break_insn;
return cache;
}
+/* GCC generates several well-known sequences of instructions at the begining
+ of each function prologue when compiling with -fstack-check. If one of
+ such sequences starts at START_PC, then return the address of the
+ instruction immediately past this sequence. Otherwise, return START_PC. */
+
+static CORE_ADDR
+sparc_skip_stack_check (const CORE_ADDR start_pc)
+{
+ CORE_ADDR pc = start_pc;
+ unsigned long insn;
+ int offset_stack_checking_sequence = 0;
+
+ /* With GCC, all stack checking sequences begin with the same two
+ instructions. */
+
+ /* sethi <some immediate>,%g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 1))
+ return start_pc;
+
+ /* sub %sp, %g1, %g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 1 && X_RS1 (insn) == 14 && X_RS2 (insn) == 1))
+ return start_pc;
+
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+
+ /* First possible sequence:
+ [first two instructions above]
+ clr [%g1 - some immediate] */
+
+ /* clr [%g1 - some immediate] */
+ if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 0)
+ {
+ /* Valid stack-check sequence, return the new PC. */
+ return pc;
+ }
+
+ /* Second possible sequence: A small number of probes.
+ [first two instructions above]
+ clr [%g1]
+ add %g1, -<some immediate>, %g1
+ clr [%g1]
+ [repeat the two instructions above any (small) number of times]
+ clr [%g1 - some immediate] */
+
+ /* clr [%g1] */
+ else if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 0)
+ {
+ while (1)
+ {
+ /* add %g1, -<some immediate>, %g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 1))
+ break;
+
+ /* clr [%g1] */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 0 && X_RS1 (insn) == 1))
+ return start_pc;
+ }
+
+ /* clr [%g1 - some immediate] */
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 0))
+ return start_pc;
+
+ /* We found a valid stack-check sequence, return the new PC. */
+ return pc;
+ }
+
+ /* Third sequence: A probing loop.
+ [first two instructions above]
+ sethi <some immediate>, %g4
+ sub %g1, %g4, %g4
+ cmp %g1, %g4
+ be <disp>
+ add %g1, -<some immediate>, %g1
+ ba <disp>
+ clr [%g1]
+ clr [%g4 - some immediate] */
+
+ /* sethi <some immediate>, %g4 */
+ else if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4)
+ {
+ /* sub %g1, %g4, %g4 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 4 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4))
+ return start_pc;
+
+ /* cmp %g1, %g4 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x14 && !X_I(insn)
+ && X_RD (insn) == 0 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4))
+ return start_pc;
+
+ /* be <disp> */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 0 && X_COND (insn) == 0x1))
+ return start_pc;
+
+ /* add %g1, -<some immediate>, %g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 1))
+ return start_pc;
+
+ /* ba <disp> */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 0 && X_COND (insn) == 0x8))
+ return start_pc;
+
+ /* clr [%g1] */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 0 && X_RS1 (insn) == 1))
+ return start_pc;
+
+ /* clr [%g4 - some immediate] */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+ && X_RS1 (insn) == 4 && X_RD (insn) == 0))
+ return start_pc;
+
+ /* We found a valid stack-check sequence, return the new PC. */
+ return pc;
+ }
+
+ /* No stack check code in our prologue, return the start_pc. */
+ return start_pc;
+}
+
CORE_ADDR
-sparc_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
- struct sparc_frame_cache *cache)
+sparc_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
+ CORE_ADDR current_pc, struct sparc_frame_cache *cache)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
unsigned long insn;
int offset = 0;
int dest = -1;
+ pc = sparc_skip_stack_check (pc);
+
if (current_pc <= pc)
return current_pc;
}
static CORE_ADDR
-sparc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+sparc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- return frame_unwind_register_unsigned (next_frame, tdep->pc_regnum);
+ return frame_unwind_register_unsigned (this_frame, tdep->pc_regnum);
}
/* Return PC of first real instruction of the function starting at
START_PC. */
static CORE_ADDR
-sparc32_skip_prologue (CORE_ADDR start_pc)
+sparc32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
{
struct symtab_and_line sal;
CORE_ADDR func_start, func_end;
return sal.end;
}
- start_pc = sparc_analyze_prologue (start_pc, 0xffffffffUL, &cache);
+ start_pc = sparc_analyze_prologue (gdbarch, 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
/* Normal frames. */
struct sparc_frame_cache *
-sparc_frame_cache (struct frame_info *next_frame, void **this_cache)
+sparc_frame_cache (struct frame_info *this_frame, void **this_cache)
{
struct sparc_frame_cache *cache;
cache = sparc_alloc_frame_cache ();
*this_cache = cache;
- cache->pc = frame_func_unwind (next_frame);
+ cache->pc = get_frame_func (this_frame);
if (cache->pc != 0)
- {
- CORE_ADDR addr_in_block = frame_unwind_address_in_block (next_frame);
- sparc_analyze_prologue (cache->pc, addr_in_block, cache);
- }
+ sparc_analyze_prologue (get_frame_arch (this_frame), cache->pc,
+ get_frame_pc (this_frame), cache);
if (cache->frameless_p)
{
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);
+ get_frame_register_unsigned (this_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);
+ get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
}
+ if (cache->base & 1)
+ cache->base += BIAS;
+
return cache;
}
+static int
+sparc32_struct_return_from_sym (struct symbol *sym)
+{
+ struct type *type = check_typedef (SYMBOL_TYPE (sym));
+ enum type_code code = TYPE_CODE (type);
+
+ if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
+ {
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+ if (sparc_structure_or_union_p (type)
+ || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16))
+ return 1;
+ }
+
+ return 0;
+}
+
struct sparc_frame_cache *
-sparc32_frame_cache (struct frame_info *next_frame, void **this_cache)
+sparc32_frame_cache (struct frame_info *this_frame, void **this_cache)
{
struct sparc_frame_cache *cache;
struct symbol *sym;
if (*this_cache)
return *this_cache;
- cache = sparc_frame_cache (next_frame, this_cache);
+ cache = sparc_frame_cache (this_frame, this_cache);
sym = find_pc_function (cache->pc);
if (sym)
{
- struct type *type = check_typedef (SYMBOL_TYPE (sym));
- enum type_code code = TYPE_CODE (type);
-
- if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
- {
- type = check_typedef (TYPE_TARGET_TYPE (type));
- if (sparc_structure_or_union_p (type)
- || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16))
- cache->struct_return_p = 1;
- }
+ cache->struct_return_p = sparc32_struct_return_from_sym (sym);
}
else
{
CORE_ADDR pc;
int regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
- pc = frame_unwind_register_unsigned (next_frame, regnum) + 8;
+ pc = get_frame_register_unsigned (this_frame, regnum) + 8;
if (sparc_is_unimp_insn (pc))
cache->struct_return_p = 1;
}
}
static void
-sparc32_frame_this_id (struct frame_info *next_frame, void **this_cache,
+sparc32_frame_this_id (struct frame_info *this_frame, void **this_cache,
struct frame_id *this_id)
{
struct sparc_frame_cache *cache =
- sparc32_frame_cache (next_frame, this_cache);
+ sparc32_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
-sparc32_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 *
+sparc32_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
{
struct sparc_frame_cache *cache =
- sparc32_frame_cache (next_frame, this_cache);
+ sparc32_frame_cache (this_frame, this_cache);
if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM)
{
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (valuep)
- {
- CORE_ADDR pc = (regnum == SPARC32_NPC_REGNUM) ? 4 : 0;
+ CORE_ADDR pc = (regnum == SPARC32_NPC_REGNUM) ? 4 : 0;
- /* If this functions has a Structure, Union or
- Quad-Precision return value, we have to skip the UNIMP
- instruction that encodes the size of the structure. */
- if (cache->struct_return_p)
- pc += 4;
+ /* If this functions has a Structure, Union or Quad-Precision
+ return value, we have to skip the UNIMP instruction that encodes
+ the size of the structure. */
+ if (cache->struct_return_p)
+ pc += 4;
- regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
- pc += frame_unwind_register_unsigned (next_frame, regnum) + 8;
- store_unsigned_integer (valuep, 4, 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. */
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) * 4;
- ULONGEST i7;
-
- /* Read the value in from memory. */
- i7 = get_frame_memory_unsigned (next_frame, addr, 4);
- store_unsigned_integer (valuep, 4, i7 ^ wcookie);
- }
- return;
+ CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 4;
+ ULONGEST i7;
+
+ /* Read the value in from memory. */
+ i7 = get_frame_memory_unsigned (this_frame, addr, 4);
+ return frame_unwind_got_constant (this_frame, regnum, i7 ^ wcookie);
}
}
if (!cache->frameless_p
&& regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM)
{
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = cache->base + (regnum - SPARC_L0_REGNUM) * 4;
- *realnump = -1;
- if (valuep)
- {
- struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 4;
- /* 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
+ /* The previous frame's `out' registers are accessible as the
current frame's `in' registers. */
if (!cache->frameless_p
&& regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
regnum += (SPARC_I0_REGNUM - SPARC_O0_REGNUM);
- *optimizedp = 0;
- *lvalp = lval_register;
- *addrp = 0;
- *realnump = regnum;
- if (valuep)
- frame_unwind_register (next_frame, (*realnump), valuep);
+ return frame_unwind_got_register (this_frame, regnum, regnum);
}
static const struct frame_unwind sparc32_frame_unwind =
{
NORMAL_FRAME,
sparc32_frame_this_id,
- sparc32_frame_prev_register
+ sparc32_frame_prev_register,
+ NULL,
+ default_frame_sniffer
};
-
-static const struct frame_unwind *
-sparc32_frame_sniffer (struct frame_info *next_frame)
-{
- return &sparc32_frame_unwind;
-}
\f
static CORE_ADDR
-sparc32_frame_base_address (struct frame_info *next_frame, void **this_cache)
+sparc32_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
struct sparc_frame_cache *cache =
- sparc32_frame_cache (next_frame, this_cache);
+ sparc32_frame_cache (this_frame, this_cache);
return cache->base;
}
};
static struct frame_id
-sparc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+sparc_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
CORE_ADDR sp;
- sp = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
- return frame_id_build (sp, frame_pc_unwind (next_frame));
+ sp = get_frame_register_unsigned (this_frame, SPARC_SP_REGNUM);
+ if (sp & 1)
+ sp += BIAS;
+ return frame_id_build (sp, get_frame_pc (this_frame));
}
\f
-/* Extract from an array REGBUF containing the (raw) register state, a
- function return value of TYPE, and copy that into VALBUF. */
+/* Extract a function return value of TYPE from REGCACHE, and copy
+ that into VALBUF. */
static void
sparc32_extract_return_value (struct type *type, struct regcache *regcache,
- void *valbuf)
+ gdb_byte *valbuf)
{
int len = TYPE_LENGTH (type);
- char buf[8];
+ gdb_byte buf[8];
gdb_assert (!sparc_structure_or_union_p (type));
gdb_assert (!(sparc_floating_p (type) && len == 16));
}
}
-/* Write into the appropriate registers a function return value stored
- in VALBUF of type TYPE. */
+/* Store the function return value of type TYPE from VALBUF into
+ REGCACHE. */
static void
sparc32_store_return_value (struct type *type, struct regcache *regcache,
- const void *valbuf)
+ const gdb_byte *valbuf)
{
int len = TYPE_LENGTH (type);
- char buf[8];
+ gdb_byte buf[8];
gdb_assert (!sparc_structure_or_union_p (type));
gdb_assert (!(sparc_floating_p (type) && len == 16));
}
static enum return_value_convention
-sparc32_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, void *readbuf,
- const void *writebuf)
+sparc32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
+ /* The psABI says that "...every stack frame reserves the word at
+ %fp+64. If a function returns a structure, union, or
+ quad-precision value, this word should hold the address of the
+ object into which the return value should be copied." This
+ guarantees that we can always find the return value, not just
+ before the function returns. */
+
if (sparc_structure_or_union_p (type)
|| (sparc_floating_p (type) && TYPE_LENGTH (type) == 16))
- return RETURN_VALUE_STRUCT_CONVENTION;
+ {
+ if (readbuf)
+ {
+ ULONGEST sp;
+ CORE_ADDR addr;
+
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ addr = read_memory_unsigned_integer (sp + 64, 4);
+ read_memory (addr, readbuf, TYPE_LENGTH (type));
+ }
+
+ return RETURN_VALUE_ABI_PRESERVES_ADDRESS;
+ }
if (readbuf)
sparc32_extract_return_value (type, regcache, readbuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
-#if 0
-/* NOTE: cagney/2004-01-17: For the moment disable this method. The
- architecture and CORE-gdb will need new code (and a replacement for
- DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS) before this can be made to
- work robustly. Here is a possible function signature: */
-/* NOTE: cagney/2004-01-17: So far only the 32-bit SPARC ABI has been
- identifed as having a way to robustly recover the address of a
- struct-convention return-value (after the function has returned).
- For all other ABIs so far examined, the calling convention makes no
- guarenteed that the register containing the return-value will be
- preserved and hence that the return-value's address can be
- recovered. */
-/* 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 int
+sparc32_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
+{
+ return (sparc_structure_or_union_p (type)
+ || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16));
+}
-static CORE_ADDR
-sparc32_extract_struct_value_address (struct regcache *regcache)
+static int
+sparc32_dwarf2_struct_return_p (struct frame_info *this_frame)
{
- ULONGEST sp;
+ CORE_ADDR pc = get_frame_address_in_block (this_frame);
+ struct symbol *sym = find_pc_function (pc);
- regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
- return read_memory_unsigned_integer (sp + 64, 4);
+ if (sym)
+ return sparc32_struct_return_from_sym (sym);
+ return 0;
}
-#endif
-static int
-sparc32_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
+static void
+sparc32_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+ struct dwarf2_frame_state_reg *reg,
+ struct frame_info *this_frame)
{
- return (sparc_structure_or_union_p (type)
- || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16));
+ int off;
+
+ switch (regnum)
+ {
+ case SPARC_G0_REGNUM:
+ /* Since %g0 is always zero, there is no point in saving it, and
+ people will be inclined omit it from the CFI. Make sure we
+ don't warn about that. */
+ reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+ break;
+ case SPARC_SP_REGNUM:
+ reg->how = DWARF2_FRAME_REG_CFA;
+ break;
+ case SPARC32_PC_REGNUM:
+ case SPARC32_NPC_REGNUM:
+ reg->how = DWARF2_FRAME_REG_RA_OFFSET;
+ off = 8;
+ if (sparc32_dwarf2_struct_return_p (this_frame))
+ off += 4;
+ if (regnum == SPARC32_NPC_REGNUM)
+ off += 4;
+ reg->loc.offset = off;
+ break;
+ }
}
\f
software single-step mechanism. */
static CORE_ADDR
-sparc_analyze_control_transfer (CORE_ADDR pc, CORE_ADDR *npc)
+sparc_analyze_control_transfer (struct frame_info *frame,
+ CORE_ADDR pc, CORE_ADDR *npc)
{
unsigned long insn = sparc_fetch_instruction (pc);
int conditional_p = X_COND (insn) & 0x7;
branch_p = 1;
offset = 4 * X_DISP19 (insn);
}
+ else if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3a)
+ {
+ /* Trap instruction (TRAP). */
+ return gdbarch_tdep (get_frame_arch (frame))->step_trap (frame, insn);
+ }
/* FIXME: Handle DONE and RETRY instructions. */
- /* FIXME: Handle the Trap instruction. */
-
if (branch_p)
{
if (conditional_p)
return 0;
}
-void
-sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+static CORE_ADDR
+sparc_step_trap (struct frame_info *frame, unsigned long insn)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- static CORE_ADDR npc, nnpc;
- static char npc_save[4], nnpc_save[4];
-
- if (insert_breakpoints_p)
- {
- CORE_ADDR pc, orig_npc;
-
- pc = sparc_address_from_register (tdep->pc_regnum);
- orig_npc = npc = sparc_address_from_register (tdep->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, and that
- 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 (npc != 0)
- target_remove_breakpoint (npc, npc_save);
- if (nnpc != 0)
- target_remove_breakpoint (nnpc, nnpc_save);
- }
+ return 0;
}
-static void
-sparc_write_pc (CORE_ADDR pc, ptid_t ptid)
+int
+sparc_software_single_step (struct frame_info *frame)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch *arch = get_frame_arch (frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
+ CORE_ADDR npc, nnpc;
+
+ CORE_ADDR pc, orig_npc;
- write_register_pid (tdep->pc_regnum, pc, ptid);
- write_register_pid (tdep->npc_regnum, pc + 4, ptid);
+ pc = get_frame_register_unsigned (frame, tdep->pc_regnum);
+ orig_npc = npc = get_frame_register_unsigned (frame, tdep->npc_regnum);
+
+ /* Analyze the instruction at PC. */
+ nnpc = sparc_analyze_control_transfer (frame, pc, &npc);
+ if (npc != 0)
+ insert_single_step_breakpoint (npc);
+
+ if (nnpc != 0)
+ insert_single_step_breakpoint (nnpc);
+
+ /* Assert that we have set at least one breakpoint, and that
+ 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);
+
+ return 1;
}
-\f
-/* Unglobalize NAME. */
-char *
-sparc_stabs_unglobalize_name (char *name)
+static void
+sparc_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
- /* The Sun compilers (Sun ONE Studio, Forte Developer, Sun WorkShop,
- SunPRO) convert file static variables into global values, a
- process known as globalization. In order to do this, the
- compiler will create a unique prefix and prepend it to each file
- static variable. For static variables within a function, this
- globalization prefix is followed by the function name (nested
- static variables within a function are supposed to generate a
- warning message, and are left alone). The procedure is
- documented in the Stabs Interface Manual, which is distrubuted
- with the compilers, although version 4.0 of the manual seems to
- be incorrect in some places, at least for SPARC. The
- globalization prefix is encoded into an N_OPT stab, with the form
- "G=<prefix>". The globalization prefix always seems to start
- with a dollar sign '$'; a dot '.' is used as a seperator. So we
- simply strip everything up until the last dot. */
-
- if (name[0] == '$')
- {
- char *p = strrchr (name, '.');
- if (p)
- return p + 1;
- }
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
- return name;
+ regcache_cooked_write_unsigned (regcache, tdep->pc_regnum, pc);
+ regcache_cooked_write_unsigned (regcache, tdep->npc_regnum, pc + 4);
}
\f
tdep->fpregset = NULL;
tdep->sizeof_fpregset = 0;
tdep->plt_entry_size = 0;
+ tdep->step_trap = sparc_step_trap;
set_gdbarch_long_double_bit (gdbarch, 128);
- set_gdbarch_long_double_format (gdbarch, &floatformat_sparc_quad);
+ set_gdbarch_long_double_format (gdbarch, floatformats_sparc_quad);
set_gdbarch_num_regs (gdbarch, SPARC32_NUM_REGS);
set_gdbarch_register_name (gdbarch, sparc32_register_name);
set_gdbarch_software_single_step (gdbarch, sparc_software_single_step);
set_gdbarch_write_pc (gdbarch, sparc_write_pc);
- set_gdbarch_unwind_dummy_id (gdbarch, sparc_unwind_dummy_id);
+ set_gdbarch_dummy_id (gdbarch, sparc_dummy_id);
set_gdbarch_unwind_pc (gdbarch, sparc_unwind_pc);
frame_base_set_default (gdbarch, &sparc32_frame_base);
+ /* Hook in the DWARF CFI frame unwinder. */
+ dwarf2_frame_set_init_reg (gdbarch, sparc32_dwarf2_frame_init_reg);
+ /* FIXME: kettenis/20050423: Don't enable the unwinder until the
+ StackGhost issues have been resolved. */
+
/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
- frame_unwind_append_sniffer (gdbarch, sparc32_frame_sniffer);
+ frame_unwind_append_unwinder (gdbarch, &sparc32_frame_unwind);
/* If we have register sets, enable the generic core file support. */
if (tdep->gregset)
sparc_supply_rwindow (struct regcache *regcache, CORE_ADDR sp, int regnum)
{
int offset = 0;
- char buf[8];
+ gdb_byte buf[8];
int i;
if (sp & 1)
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);
}
}
/* 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 (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 64)
{
memset (buf, 0, 4);
offset = 4;
CORE_ADDR sp, int regnum)
{
int offset = 0;
- char buf[8];
+ gdb_byte buf[8];
int i;
if (sp & 1)
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);
}
}
sp &= 0xffffffffUL;
/* Only use the bottom half if we're in 64-bit mode. */
- if (gdbarch_ptr_bit (current_gdbarch) == 64)
+ if (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 64)
offset = 4;
for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
struct regcache *regcache,
int regnum, const void *gregs)
{
- const char *regs = gregs;
+ const gdb_byte *regs = gregs;
int i;
if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
const struct regcache *regcache,
int regnum, void *gregs)
{
- char *regs = gregs;
+ gdb_byte *regs = gregs;
int i;
if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
sparc32_supply_fpregset (struct regcache *regcache,
int regnum, const void *fpregs)
{
- const char *regs = fpregs;
+ const gdb_byte *regs = fpregs;
int i;
for (i = 0; i < 32; i++)
sparc32_collect_fpregset (const struct regcache *regcache,
int regnum, void *fpregs)
{
- char *regs = fpregs;
+ gdb_byte *regs = fpregs;
int i;
for (i = 0; i < 32; i++)
_initialize_sparc_tdep (void)
{
register_gdbarch_init (bfd_arch_sparc, sparc32_gdbarch_init);
+
+ /* Initialize the SPARC-specific register types. */
+ sparc_init_types();
}