(sparc_address_from_register): New prototype.
(sparcnbsd_step_trap): New prototype.
* sparc-tdep.c (sparc_address_from_register): Make globally
visible.
(sparc_analyze_control_transfer): Change prototype to accept
`struct gdbarch *' as first argument. Allow for optional hnadling
for trap instructions.
(sparc_step_trap): New function.
(sparc_software_single_step): Adjust call to
sparc_analyze_control_trabsfer.
(sparc32_gdbarch_init): Initialize TDEP->step_trap.
* sparcnbsd-tdep.c (sparcnbsd_step_trap): New function.
(sparc32nbsd_init_abi): Set TDEP->step_trap.
* sparc64obsd-tdep.c (sparc64obsd_init_abi): Set TDEP->step_trap.
* sparc64nbsd-tdep.c (sparc64nbsd_init_abi): Set TDEP->step_trap.
2006-01-22 Mark Kettenis <kettenis@gnu.org>
+ * sparc-tdep.h (struct gdbarch_tdep): Add step_trap member.
+ (sparc_address_from_register): New prototype.
+ (sparcnbsd_step_trap): New prototype.
+ * sparc-tdep.c (sparc_address_from_register): Make globally
+ visible.
+ (sparc_analyze_control_transfer): Change prototype to accept
+ `struct gdbarch *' as first argument. Allow for optional hnadling
+ for trap instructions.
+ (sparc_step_trap): New function.
+ (sparc_software_single_step): Adjust call to
+ sparc_analyze_control_trabsfer.
+ (sparc32_gdbarch_init): Initialize TDEP->step_trap.
+ * sparcnbsd-tdep.c (sparcnbsd_step_trap): New function.
+ (sparc32nbsd_init_abi): Set TDEP->step_trap.
+ * sparc64obsd-tdep.c (sparc64obsd_init_abi): Set TDEP->step_trap.
+ * sparc64nbsd-tdep.c (sparc64nbsd_init_abi): Set TDEP->step_trap.
+
* sparc-tdep.c (sparc32_return_value): Convert to use
RETURN_VALUE_ABI_PRESERVES_ADDRESS instead of
RETURN_VALUE_STRUCT_CONVENTION.
/* Return the contents if register REGNUM as an address. */
-static CORE_ADDR
+CORE_ADDR
sparc_address_from_register (int regnum)
{
ULONGEST addr;
software single-step mechanism. */
static CORE_ADDR
-sparc_analyze_control_transfer (CORE_ADDR pc, CORE_ADDR *npc)
+sparc_analyze_control_transfer (struct gdbarch *arch,
+ 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 (arch)->step_trap (insn);
+ }
/* FIXME: Handle DONE and RETRY instructions. */
- /* FIXME: Handle the Trap instruction. */
-
if (branch_p)
{
if (conditional_p)
return 0;
}
+static CORE_ADDR
+sparc_step_trap (unsigned long insn)
+{
+ return 0;
+}
+
void
sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch *arch = current_gdbarch;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
static CORE_ADDR npc, nnpc;
static gdb_byte npc_save[4], nnpc_save[4];
orig_npc = npc = sparc_address_from_register (tdep->npc_regnum);
/* Analyze the instruction at PC. */
- nnpc = sparc_analyze_control_transfer (pc, &npc);
+ nnpc = sparc_analyze_control_transfer (arch, pc, &npc);
if (npc != 0)
target_insert_breakpoint (npc, npc_save);
if (nnpc != 0)
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);
/* Target-dependent code for SPARC.
- Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of GDB.
/* Size of an Procedure Linkage Table (PLT) entry, 0 if we shouldn't
treat the PLT special when doing prologue analysis. */
size_t plt_entry_size;
+
+ /* Alternative location for trap return. Used for single-stepping. */
+ CORE_ADDR (*step_trap) (unsigned long insn);
};
/* Register numbers of various important registers. */
/* Fetch the instruction at PC. */
extern unsigned long sparc_fetch_instruction (CORE_ADDR pc);
+/* Return the contents if register REGNUM as an address. */
+extern CORE_ADDR sparc_address_from_register (int regnum);
+
/* Fetch StackGhost Per-Process XOR cookie. */
extern ULONGEST sparc_fetch_wcookie (void);
/* Register offsets for NetBSD. */
extern const struct sparc_gregset sparc32nbsd_gregset;
+/* Return the address of a system call's alternative return
+ address. */
+extern CORE_ADDR sparcnbsd_step_trap (unsigned long insn);
+
extern void sparc32nbsd_elf_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch);
/* Target-dependent code for NetBSD/sparc64.
- Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Based on code contributed by Wasabi Systems, Inc.
This file is part of GDB.
tdep->fpregset = regset_alloc (gdbarch, sparc64nbsd_supply_fpregset, NULL);
tdep->sizeof_fpregset = 272;
+ /* Make sure we can single-step "new" syscalls. */
+ tdep->step_trap = sparcnbsd_step_trap;
+
frame_unwind_append_sniffer (gdbarch, sparc64nbsd_sigtramp_frame_sniffer);
sparc64_init_abi (info, gdbarch);
/* Target-dependent code for OpenBSD/sparc64.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GDB.
tdep->gregset = regset_alloc (gdbarch, sparc64obsd_supply_gregset, NULL);
tdep->sizeof_gregset = 832;
+ /* Make sure we can single-step "new" syscalls. */
+ tdep->step_trap = sparcnbsd_step_trap;
+
frame_unwind_append_sniffer (gdbarch, sparc64obsd_sigtramp_frame_sniffer);
sparc64_init_abi (info, gdbarch);
/* Target-dependent code for NetBSD/sparc.
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
Contributed by Wasabi Systems, Inc.
This file is part of GDB.
#include "sparc-tdep.h"
#include "nbsd-tdep.h"
+/* Macros to extract fields from SPARC instructions. */
+#define X_RS1(i) (((i) >> 14) & 0x1f)
+#define X_RS2(i) ((i) & 0x1f)
+#define X_I(i) (((i) >> 13) & 1)
+
const struct sparc_gregset sparc32nbsd_gregset =
{
0 * 4, /* %psr */
return NULL;
}
\f
+/* Return the address of a system call's alternative return
+ address. */
+
+CORE_ADDR
+sparcnbsd_step_trap (unsigned long insn)
+{
+ if ((X_I (insn) == 0 && X_RS1 (insn) == 0 && X_RS2 (insn) == 0)
+ || (X_I (insn) == 1 && X_RS1 (insn) == 0 && (insn & 0x7f) == 0))
+ {
+ /* "New" system call. */
+ ULONGEST number;
+
+ regcache_cooked_read_unsigned (current_regcache,
+ SPARC_G1_REGNUM, &number);
+
+ if (number & 0x400)
+ return sparc_address_from_register (SPARC_G2_REGNUM);
+ if (number & 0x800)
+ return sparc_address_from_register (SPARC_G7_REGNUM);
+ }
+
+ return 0;
+}
+\f
static void
sparc32nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->fpregset = regset_alloc (gdbarch, sparc32nbsd_supply_fpregset, NULL);
tdep->sizeof_fpregset = 33 * 4;
+ /* Make sure we can single-step "new" syscalls. */
+ tdep->step_trap = sparcnbsd_step_trap;
+
frame_unwind_append_sniffer (gdbarch, sparc32nbsd_sigtramp_frame_sniffer);
}