aboutsummaryrefslogtreecommitdiff
path: root/gdb/sp64-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/sp64-tdep.c')
-rw-r--r--gdb/sp64-tdep.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/gdb/sp64-tdep.c b/gdb/sp64-tdep.c
new file mode 100644
index 0000000..d202e25
--- /dev/null
+++ b/gdb/sp64-tdep.c
@@ -0,0 +1,314 @@
+/* Target-dependent code for the SPARC 64 for GDB, the GNU debugger.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Contributed by Doug Evans (dje@cygnus.com).
+
+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
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "obstack.h"
+#include "target.h"
+#include "ieee-float.h"
+
+/*#include "symfile.h" /* for objfiles.h */
+/*#include "objfiles.h" /* for find_pc_section */
+
+/* This file contains replacements and additions to sparc-tdep.c only.
+ Some of this code has been written for a day when we can merge at least
+ some of this with sparc-tdep.c. Macro TARGET_SPARC64 exists to allow some
+ code to potentially be used by both. */
+
+#define TARGET_SPARC64 1 /* later make a config parm or some such */
+
+/* From infrun.c */
+extern int stop_after_trap;
+
+/* Branches with prediction are treated like their non-predicting cousins. */
+/* FIXME: What about floating point branches? */
+
+typedef enum
+{
+ Error, not_branch, bicc, bicca, ba, baa, ticc, ta, done_retry
+} branch_type;
+
+/* Simulate single-step ptrace call for sun4. Code written by Gary
+ Beihl (beihl@mcc.com). */
+
+/* npc4 and next_pc describe the situation at the time that the
+ step-breakpoint was set, not necessary the current value of NPC_REGNUM. */
+static CORE_ADDR next_pc, npc4, target;
+static int brknpc4, brktrg;
+typedef char binsn_quantum[BREAKPOINT_MAX];
+static binsn_quantum break_mem[3];
+
+/* Non-zero if we just simulated a single-step ptrace call. This is
+ needed because we cannot remove the breakpoints in the inferior
+ process until after the `wait' in `wait_for_inferior'. Used for
+ sun4. */
+
+int one_stepped;
+
+/* sparc64_single_step() is called just before we want to resume the inferior,
+ if we want to single-step it but there is no hardware or kernel single-step
+ support (as on all SPARCs). We find all the possible targets of the
+ coming instruction and breakpoint them.
+
+ single_step is also called just after the inferior stops. If we had
+ set up a simulated single-step, we undo our damage. */
+
+/* FIXME: When the code is releasable, sparc's single step could become this
+ one, removing the duplication. */
+
+void
+sparc64_single_step (ignore)
+ int ignore; /* pid, but we don't need it */
+{
+ branch_type br, isbranch();
+ CORE_ADDR pc;
+ long pc_instruction;
+
+ if (!one_stepped)
+ {
+ /* Always set breakpoint for NPC. */
+ next_pc = read_register (NPC_REGNUM);
+ npc4 = next_pc + 4; /* branch not taken */
+
+ target_insert_breakpoint (next_pc, break_mem[0]);
+ /* printf ("set break at %x\n",next_pc); */
+
+ pc = read_register (PC_REGNUM);
+ pc_instruction = read_memory_integer (pc, sizeof(pc_instruction));
+ br = isbranch (pc_instruction, pc, &target);
+ brknpc4 = brktrg = 0;
+
+ if (br == bicca)
+ {
+ /* Conditional annulled branch will either end up at
+ npc (if taken) or at npc+4 (if not taken).
+ Trap npc+4. */
+ brknpc4 = 1;
+ target_insert_breakpoint (npc4, break_mem[1]);
+ }
+ else if ((br == baa && target != next_pc)
+ || (TARGET_SPARC64 && br == done_retry))
+ {
+ /* Unconditional annulled branch will always end up at
+ the target. */
+ brktrg = 1;
+ target_insert_breakpoint (target, break_mem[2]);
+ }
+
+ /* We are ready to let it go */
+ one_stepped = 1;
+ return;
+ }
+ else
+ {
+ /* Remove breakpoints */
+ target_remove_breakpoint (next_pc, break_mem[0]);
+
+ if (brknpc4)
+ target_remove_breakpoint (npc4, break_mem[1]);
+
+ if (brktrg)
+ target_remove_breakpoint (target, break_mem[2]);
+
+ one_stepped = 0;
+ }
+}
+
+/* FIXME: sparc64_frame_chain() is temporary. sparc_frame_chain() can
+ be fixed to support both of us. */
+
+#define FRAME_SAVED_L0 0 /* Byte offset from SP */
+#define FRAME_SAVED_I0 (8*REGISTER_RAW_SIZE (0)) /* Byte offset from SP */
+
+CORE_ADDR
+sparc64_frame_chain (thisframe)
+ FRAME thisframe;
+{
+ REGISTER_TYPE retval;
+ int err;
+ CORE_ADDR addr;
+
+ addr = thisframe->frame + FRAME_SAVED_I0 +
+ REGISTER_RAW_SIZE (0) * (FP_REGNUM - I0_REGNUM);
+ err = target_read_memory (addr, (char *) &retval, sizeof (REGISTER_TYPE));
+ if (err)
+ return 0;
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+}
+
+CORE_ADDR
+sparc64_extract_struct_value_address (regbuf)
+ char regbuf[REGISTER_BYTES];
+{
+ CORE_ADDR addr;
+
+ /* FIXME: We assume a non-leaf function. */
+ addr = read_register (I0_REGNUM);
+ return addr;
+}
+
+/* Find the pc saved in frame FRAME. */
+/* FIXME: This function can be removed when sparc_frame_saved_pc
+ handles us too. */
+
+CORE_ADDR
+sparc64_frame_saved_pc (frame)
+ FRAME frame;
+{
+ int err;
+ REGISTER_TYPE retval;
+ CORE_ADDR addr,prev_pc;
+
+ if (get_current_frame () == frame) /* FIXME, debug check. Remove >=gdb-4.6 */
+ {
+ if (read_register (SP_REGNUM) != frame->bottom) abort();
+ }
+
+ addr = frame->bottom + FRAME_SAVED_I0 +
+ REGISTER_RAW_SIZE (0) * (I7_REGNUM - I0_REGNUM);
+ err = target_read_memory (addr, (char *) &retval, sizeof (REGISTER_TYPE));
+ if (err)
+ return 0;
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+
+ /* CORE_ADDR isn't always the same size as REGISTER_TYPE, so convert. */
+
+ prev_pc = (CORE_ADDR) retval;
+ return PC_ADJUST (prev_pc);
+}
+
+/* Check instruction at ADDR to see if it is an annulled branch or other
+ instruction whose npc isn't pc+4 (eg: trap, done, retry).
+ All other instructions will go to NPC or will trap.
+ Set *TARGET if we find a candidate branch; set to zero if not. */
+
+branch_type
+isbranch (instruction, addr, target)
+ long instruction;
+ CORE_ADDR addr, *target;
+{
+ branch_type val = not_branch;
+ long int offset; /* Must be signed for sign-extend. */
+ union
+ {
+ unsigned long int code;
+ struct
+ {
+ unsigned int op:2;
+ unsigned int a:1;
+ unsigned int cond:4;
+ unsigned int op2:3;
+ unsigned int disp22:22;
+ } b;
+ struct
+ {
+ unsigned int op:2;
+ unsigned int a:1;
+ unsigned int cond:4;
+ unsigned int op2:3;
+ unsigned int cc:2;
+ unsigned int p:1;
+ unsigned int disp19:19;
+ } bp;
+ struct
+ {
+ unsigned int op:2;
+ unsigned int a:1;
+ unsigned int zero:1;
+ unsigned int rcond:3;
+ unsigned int op2:3;
+ unsigned int disp16hi:2;
+ unsigned int p:1;
+ unsigned int rs1:5;
+ unsigned int disp16lo:14;
+ } bpr;
+ struct
+ {
+ unsigned int op:2;
+ unsigned int fcn:5;
+ unsigned int op3:6;
+ unsigned int reserved:19;
+ } dr;
+ } insn;
+
+ *target = 0;
+ insn.code = instruction;
+
+ if (insn.b.op == 0
+ && (insn.b.op2 == 1 || insn.b.op2 == 2 || insn.b.op2 ==3
+ || insn.b.op2 == 5 || insn.b.op2 == 6))
+ {
+ if (insn.b.cond == 8)
+ val = insn.b.a ? baa : ba;
+ else
+ val = insn.b.a ? bicca : bicc;
+ switch (insn.b.op2)
+ {
+ case 1: /* bpcc */
+ offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13);
+ break;
+ case 2: /* bicc */
+ offset = 4 * ((int) (insn.b.disp22 << 10) >> 10);
+ break;
+ case 3: /* bpr */
+ offset = 4 * ((int) ((insn.bpr.disp16hi << 10)
+ || (insn.bpr.disp16lo << 18)) >> 13);
+ break;
+ case 5: /* fbpfcc */
+ offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13);
+ break;
+ case 6: /* fbfcc */
+ offset = 4 * ((int) (insn.b.disp22 << 10) >> 10);
+ break;
+ }
+ *target = addr + offset;
+ }
+ else if (insn.dr.op == 2 && insn.dr.op3 == 62)
+ {
+ if (insn.dr.fcn == 0)
+ {
+ /* done */
+ *target = read_register (TNPC_REGNUM);
+ val = done_retry;
+ }
+ else if (insn.dr.fcn == 1)
+ {
+ /* retry */
+ *target = read_register (TPC_REGNUM);
+ val = done_retry;
+ }
+ }
+
+ return val;
+}
+
+/* We try to support 32 bit and 64 bit pointers.
+ We are called when the Shade target is selected by shadeif.c. */
+
+int target_ptr_bit = 64; /* default */
+
+void
+set_target_ptr_bit(ptr_bit)
+ int ptr_bit;
+{
+ target_ptr_bit = ptr_bit;
+}