--- /dev/null
+/* Remote debugging interface for SPARC64 Simulator.
+ Copyright 1992 Free Software Foundation, Inc.
+ Contributed by Cygnus Support. Hacked from Steve Chamberlain's Z8000 work
+ 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 "inferior.h"
+#include "wait.h"
+#include "value.h"
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <errno.h>
+#include "terminal.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "sp64sim.h"
+
+/* Naming conventions:
+
+ simif_xxx are internal objects that describe top level interfaces to the
+ simulator (simif for SIMulator InterFace).
+
+ sim_xxx are external counterparts to the simif_xxx objects that must be
+ provided by the simulator. */
+
+/* Forward data declarations */
+extern struct target_ops simif_ops;
+
+int simif_verbose = 0; /* available to the simulator to use */
+
+static int program_loaded = 0;
+
+static void dump_mem ();
+
+static void
+simif_fetch_register (regno)
+int regno;
+{
+ if (regno == -1)
+ {
+ if (simif_verbose)
+ printf_filtered ("simif_fetch_register: %d\n", regno);
+ for (regno = 0; regno < 16; regno++)
+ simif_fetch_register (regno);
+ }
+ else
+ {
+ char buf[MAX_REGISTER_RAW_SIZE];
+
+ sim_fetch_register (regno, buf);
+ supply_register (regno, buf);
+ if (simif_verbose)
+ {
+ printf_filtered ("simif_fetch_register: %d", regno);
+ dump_mem (buf, sizeof (REGISTER_TYPE));
+ }
+ }
+}
+
+static void
+simif_store_register (regno)
+int regno;
+{
+ if (regno == -1)
+ {
+ if (simif_verbose)
+ printf_filtered ("simif_store_register: %d\n", regno);
+ for (regno = 0; regno < 16; regno++)
+ simif_store_register (regno);
+ }
+ else
+ {
+ char value[sizeof (REGISTER_TYPE)];
+
+ read_register_gen (regno, value);
+ SWAP_TARGET_AND_HOST (value, sizeof (REGISTER_TYPE));
+ sim_store_register (regno, value);
+ if (simif_verbose)
+ {
+ printf_filtered ("simif_store_register: %d", regno);
+ dump_mem (value, sizeof (REGISTER_TYPE));
+ }
+ }
+}
+
+static void
+simif_kill (arg,from_tty)
+char *arg;
+int from_tty;
+{
+ if (simif_verbose)
+ printf_filtered ("simif_kill: arg \"%s\"\n", arg);
+
+ sim_kill (); /* close fd's, remove mappings */
+ inferior_pid = 0;
+}
+
+/* Download a file specified in 'args', to the sim. */
+
+static void
+simif_load (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ bfd *abfd;
+
+ if (simif_verbose)
+ printf_filtered ("simif_load: args \"%s\"\n", args);
+
+ inferior_pid = 0;
+ program_loaded = 0;
+ /* FIXME: a.out should be a config parm and/or an arg. */
+ abfd = bfd_openr (args,"a.out-sunos-big");
+
+ if (!abfd)
+ error ("Unable to open file %s.", args);
+
+ if (bfd_check_format (abfd, bfd_object) ==0)
+ error ("File is not an object file.");
+
+ if (sim_load (abfd, args) != 0)
+ return;
+
+ program_loaded = 1;
+
+ /* It is sim_load()'s job to set this. */
+ /*sim_set_pc (abfd->start_address); - can't do 'cus we use RMTVaddr */
+}
+
+/* This is called not only when we first attach, but also when the
+ user types "run" after having attached. */
+
+static void
+simif_create_inferior (exec_file, args, env)
+ char *exec_file;
+ char *args;
+ char **env;
+{
+ int len,entry_pt;
+ char *arg_buf,**argv;
+
+ if (! program_loaded)
+ error ("No program loaded.");
+
+ if (simif_verbose)
+ printf_filtered ("simif_create_inferior: exec_file \"%s\", args \"%s\"\n",
+ exec_file, args);
+
+ if (exec_file == 0 || exec_bfd == 0)
+ error ("No exec file specified.");
+
+ entry_pt = (int) bfd_get_start_address (exec_bfd);
+
+ simif_kill (NULL, NULL);
+ remove_breakpoints ();
+ init_wait_for_inferior ();
+
+ len = 5 + strlen (exec_file) + 1 + strlen (args) + 1 + /*slop*/ 10;
+ arg_buf = (char *) alloca (len);
+ arg_buf[0] = '\0';
+ strcat (arg_buf, exec_file);
+ strcat (arg_buf, " ");
+ strcat (arg_buf, args);
+ argv = buildargv (arg_buf);
+ make_cleanup (freeargv, (char *) argv);
+ sim_set_args (argv, env);
+
+ inferior_pid = 42;
+ insert_breakpoints (); /* Needed to get correct instruction in cache */
+ proceed (entry_pt, -1, 0);
+}
+
+/* Called when selecting the simulator. EG: (gdb) target sim name.
+ NAME unused at present. */
+
+static void
+simif_open (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ if (simif_verbose)
+ printf_filtered ("simif_open: name \"%s\"\n", name);
+
+ if (sim_init (name) != 0)
+ {
+ error ("Unable to initialize simulator (insufficient memory?).");
+ return;
+ }
+
+ push_target (&simif_ops);
+ target_fetch_registers (-1);
+
+ printf_filtered ("Connected to the simulator.\n");
+}
+
+/* Close out all files and local state before this target loses control. */
+
+static void
+simif_close (quitting)
+ int quitting;
+{
+ if (simif_verbose)
+ printf_filtered ("simif_close: quitting %d\n", quitting);
+
+ program_loaded = 0;
+
+ /* FIXME: Need to call sim_close() to close all files and
+ delete all mappings. */
+}
+
+/* Terminate the open connection to the remote debugger.
+ Use this when you want to detach and do something else
+ with your gdb. */
+
+static void
+simif_detach (args,from_tty)
+ char *args;
+ int from_tty;
+{
+ if (simif_verbose)
+ printf_filtered ("simif_detach: args \"%s\"\n", args);
+
+ pop_target (); /* calls simif_close to do the real work */
+ if (from_tty)
+ printf_filtered ("Ending simulator %s debugging\n", target_shortname);
+}
+
+/* Tell the remote machine to resume. */
+/* FIXME: What are A and B? */
+
+static void
+simif_resume (a,b)
+{
+ if (simif_verbose)
+ printf_filtered ("simif_resume: %d/%d\n", a, b);
+
+ sim_resume (a, b);
+}
+
+/* Wait until the remote machine stops, then return,
+ storing status in STATUS just as `wait' would. */
+
+static int
+simif_wait (status)
+ WAITTYPE *status;
+{
+ if (simif_verbose)
+ printf_filtered ("simif_wait: ");
+#if 1
+ *status = sim_stop_signal ();
+#else
+ WSETSTOP (*status, sim_stop_signal ());
+#endif
+ if (simif_verbose)
+ printf_filtered ("status %d\n", *status);
+ return 0;
+}
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that registers contains all the registers from the program being
+ debugged. */
+
+static void
+simif_prepare_to_store ()
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+static int
+simif_xfer_inferior_memory (memaddr, myaddr, len, write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+ struct target_ops *target; /* ignored */
+{
+ if (simif_verbose)
+ {
+ printf_filtered ("simif_xfer_inferior_memory: myaddr 0x%x, memaddr 0x%x, len %d, write %d\n",
+ myaddr, memaddr, len, write);
+ if (simif_verbose && write)
+ dump_mem(myaddr, len);
+ }
+
+ if (! program_loaded)
+ error ("No program loaded.");
+
+ if (write)
+ {
+ len = sim_write (memaddr, myaddr, len);
+ }
+ else
+ {
+ len = sim_read (memaddr, myaddr, len);
+ if (simif_verbose && len > 0)
+ dump_mem(myaddr, len);
+ }
+ return len;
+}
+
+static void
+simif_files_info ()
+{
+ char *file = "nothing";
+
+ if (exec_bfd)
+ file = bfd_get_filename (exec_bfd);
+
+ if (simif_verbose)
+ printf_filtered ("simif_files_info: file \"%s\"\n", file);
+
+ if (exec_bfd)
+ printf_filtered ("\tAttached to %s running program %s\n",
+ target_shortname, file);
+}
+
+/* Clear the sims notion of what the break points are */
+static void
+simif_mourn ()
+{
+ if (simif_verbose)
+ printf_filtered ("simif_mourn:\n");
+
+ remove_breakpoints ();
+ generic_mourn_inferior ();
+}
+
+/* Define the target subroutine names */
+
+struct target_ops simif_ops =
+{
+ "sim", "SPARC64 Simulator",
+ "Use the SPARC64 Simulator",
+ simif_open, simif_close,
+ 0, simif_detach, simif_resume, simif_wait, /* attach */
+ simif_fetch_register, simif_store_register,
+ simif_prepare_to_store,
+ simif_xfer_inferior_memory,
+ simif_files_info,
+ 0, 0, /* Breakpoints */
+ 0, 0, 0, 0, 0, /* Terminal handling */
+ simif_kill, /* FIXME, kill */
+ simif_load,
+ 0, /* lookup_symbol */
+ simif_create_inferior, /* create_inferior */
+ simif_mourn, /* mourn_inferior FIXME */
+ 0, /* can_run */
+ 0, /* notice_signals */
+ process_stratum, 0, /* next */
+ 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */
+ 0, 0, /* Section pointers */
+ OPS_MAGIC, /* Always the last thing */
+};
+
+static void
+simif_snoop ()
+{
+ simif_verbose = ! simif_verbose;
+ if (simif_verbose)
+ printf_filtered ("Snoop enabled\n");
+ else
+ printf_filtered ("Snoop disabled\n");
+
+}
+
+/***********************************************************************/
+
+void
+_initialize_remote_sim ()
+{
+ add_target (&simif_ops);
+ add_com ("snoop", class_obscure, simif_snoop,
+ "Show what commands are going to the simulator");
+}
+
+static void
+dump_mem (buf, len)
+ char *buf;
+ int len;
+{
+ if (len <= 8)
+ {
+ if (len == 8 || len == 4)
+ {
+ long l[2];
+ memcpy (l, buf, len);
+ printf_filtered ("\t0x%x", l[0]);
+ printf_filtered (len == 8 ? " 0x%x\n" : "\n", l[1]);
+ }
+ else
+ {
+ int i;
+ printf_filtered ("\t");
+ for (i = 0; i < len; i++)
+ printf_filtered ("0x%x ", buf[i]);
+ printf_filtered ("\n");
+ }
+ }
+}
--- /dev/null
+/* 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;
+ }
+}
+\f
+/* 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;
+}