aboutsummaryrefslogtreecommitdiff
path: root/gdb/remote-est.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/remote-est.c')
-rw-r--r--gdb/remote-est.c589
1 files changed, 589 insertions, 0 deletions
diff --git a/gdb/remote-est.c b/gdb/remote-est.c
new file mode 100644
index 0000000..1fbdfac
--- /dev/null
+++ b/gdb/remote-est.c
@@ -0,0 +1,589 @@
+/* Remote debugging interface for EST-300 ICE, for GDB
+ Copyright 1994 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+ Written by Steve Chamberlain for Cygnus Support.
+
+ 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 "command.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "wait.h"
+#include <varargs.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include "serial.h"
+#include "remote-utils.h"
+
+
+static void expect_char PARAMS ((int));
+
+
+static void
+write_and_expect (x)
+char *x;
+{
+ sr_write_cr (x);
+ sr_expect (x);
+}
+
+static void
+expect_char (want)
+ int want;
+{
+ int c = sr_readchar ();
+ while (c != want)
+ c = sr_readchar ();
+}
+
+
+static void
+expect_prompt ()
+{
+ expect_char ('>');
+}
+
+static int
+get_hex_digit (ch)
+ int ch;
+{
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ else if (ch >= 'A' && ch <= 'F')
+ return ch - 'A' + 10;
+ else if (ch >= 'a' && ch <= 'f')
+ return ch - 'a' + 10;
+ return -1;
+}
+
+static int
+get_hex (start)
+ int *start;
+{
+ int value = get_hex_digit (*start);
+ int try;
+
+ *start = sr_readchar ();
+ while ((try = get_hex_digit (*start)) >= 0)
+ {
+ value <<= 4;
+ value += try;
+ *start = sr_readchar ();
+ }
+ return value;
+}
+
+/* Tell the remote machine to resume. */
+
+static void
+est_resume (pid, step, sig)
+ int pid, step, sig;
+{
+ write_and_expect (step ? ".SI" : ".GO");
+}
+
+/* A reg dump looks like
+ D0 = 00000000 D1 = 00000000 D2 = 00000000 D3 = 00000000
+ D4 = 00000000 D5 = 00000000 D6 = 00000000 D7 = 00000000
+ A0 = 00000000 A1 = 00000000 A2 = 00000000 A3 = 00000000
+ A4 = 00000000 A5 = 00000000 A6 = 00000000 A7 = 001104FE
+ USP = 00110400 SSP*= 001104FE PC = 00229BBC SR = 2000
+ VBR = 00110000 SFC = 0005 DFC = 0005
+
+or
+
+00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00001234 00000000 001104FE 00110400 001104FE 00229BBC 2000 00110000 0005 0005
+*/
+
+static int
+target_to_gdb_rn (rn)
+ int rn;
+{
+ if (rn < 16)
+ return rn;
+ if (rn == 18)
+ return PC_REGNUM;
+ if (rn == 19)
+ return PS_REGNUM;
+ return -1;
+}
+
+
+static void est_fetch_register ();
+static void
+est_fetch_registers ()
+{
+ int regno;
+ unsigned long val;
+ int c;
+ int target_rn;
+ char buf[4];
+ write_and_expect (".DR");
+ buf[0] = 0;
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+ for (regno = 0; regno < NUM_REGS; regno++)
+ supply_register (regno, buf);
+
+ c = sr_readchar ();
+ for (target_rn = 0; target_rn < 23; target_rn++)
+ {
+ unsigned long val;
+ while (!isdigit (c) && !isalpha (c))
+ c = sr_readchar ();
+
+ while (isdigit (c) || (c >= 'A' && c <= 'F'))
+ {
+ val <<= 4;
+ if (isdigit (c))
+ val = val + c - '0';
+ else
+ val = val + c - 'A' + 10;
+ c = sr_readchar ();
+ }
+
+ regno = target_to_gdb_rn (target_rn);
+ if (regno >= 0)
+ {
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val >> 0;
+ supply_register (regno, buf);
+ }
+ }
+ expect_prompt();
+}
+
+/* Fetch register REGNO, or all registers if REGNO is -1.
+ Returns errno value. */
+
+static
+void
+est_fetch_register (regno)
+ int regno;
+{
+ est_fetch_registers ();
+}
+
+/* Store the remote registers from the contents of the block REGS. */
+
+static void est_store_register ();
+static void
+est_store_registers ()
+{
+ int regno;
+
+ for (regno = 0; regno < 18; regno++)
+ est_store_register (regno);
+ registers_changed ();
+}
+
+/* Store register REGNO, or all if REGNO == 0.
+ Return errno value. */
+static void
+est_store_register (regno)
+ int regno;
+{
+ char buf[20];
+ if (regno == -1)
+ {
+ est_store_registers ();
+ return;
+ }
+
+ if (regno < 8)
+ sprintf (buf, ".SR D%d %x", regno, read_register (regno));
+ else if (regno < 16)
+ sprintf (buf, ".SR A%d %x", regno - 8, read_register (regno));
+ else if (regno == PC_REGNUM)
+ sprintf (buf, ".SR PC %x", read_register (regno));
+ else if (regno == PS_REGNUM)
+ sprintf (buf, ".SR SR %x", read_register (regno));
+ else
+ return;
+ write_and_expect (buf);
+ expect_prompt ();
+}
+
+/* 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
+int
+stickbyte (where, what)
+ char *where;
+ unsigned int what;
+{
+ static CONST char digs[] = "0123456789ABCDEF";
+ where[0] = digs[(what >> 4) & 0xf];
+ where[1] = digs[(what & 0xf) & 0xf];
+ return what;
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+ to inferior's memory at MEMADDR. Returns length moved. */
+
+static int
+est_write_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ unsigned char *myaddr;
+ int len;
+{
+ int i;
+#define maxstride 128
+ int stride;
+
+ write_and_expect (".DL");
+ expect_char ('+');
+ for (i = 0; i < len; i += stride)
+ {
+ char compose[maxstride * 2 + 50];
+ int address = i + memaddr;
+ int j;
+ int check_sum;
+ int where = 0;
+ int alen;
+ stride = len - i;
+ if (stride > maxstride)
+ stride = maxstride;
+
+ compose[where++] = 'S';
+ check_sum = 0;
+ if (address >= 0xffffff)
+ {
+ alen = 4;
+ }
+ else if (address >= 0xffff)
+ {
+ alen = 3;
+ }
+ else
+ alen = 2;
+ compose[where++] = alen - 1 + '0'; /* insert type */
+ check_sum += stickbyte (compose + where, alen + stride + 1); /* Insert length */
+ where += 2;
+ while (alen > 0)
+ {
+ alen--;
+ check_sum += stickbyte (compose + where, address >> (8 * (alen)));
+ where += 2;
+ }
+
+ for (j = 0; j < stride; j++)
+ {
+ check_sum += stickbyte (compose + where, myaddr[i + j]);
+ where += 2;
+ }
+
+ stickbyte (compose + where, ~check_sum);
+
+ where += 2;
+ compose[where++] = 0;
+
+ sr_write_cr (compose);
+ while (sr_readchar () != '+')
+ sr_write_cr (compose);
+ }
+
+ /* Send the trailer record */
+ sr_write_cr ("S70500000000FA");
+ expect_prompt ();
+ return len;
+}
+
+
+
+/*
+
+ The dump memory command generates output which looks like:
+
+
+.dmb 0 100
+4E 56 FF FC 4E 71 42 AE FF FC 72 09 B2 AE FF FC NV..NqB...r.....
+6C 02 60 12 2F 2E FF FC 4E B9 00 00 00 2A 58 4F l.`./...N....*XO
+52 AE FF FC 60 E4 4E 5E 4E 75 4E 56 00 00 20 2E R...`.N^NuNV.. .
+00 08 D1 B9 00 00 00 00 4E 5E 4E 75 06 46 40 54 ........N^Nu.F@T
+04 45 44 4C 54 45 40 56 42 F4 04 64 24 45 05 05 .EDLTE@VB..d$E..
+00 6D 04 46 00 45 4C 05 04 46 04 4C 44 CD 00 65 .m.F.EL..F.LD..e
+40 45 44 55 45 45 45 46 04 44 44 40 05 4D 00 44 @EDUEEEF.DD@.M.D
+
+*/
+
+static int
+est_read_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ unsigned char *myaddr;
+ int len;
+{
+ int count;
+ int c;
+ char buf[20];
+ /* Starting address of this pass. */
+
+ if (((memaddr - 1) + len) < memaddr)
+ {
+ errno = EIO;
+ return 0;
+ }
+
+ sprintf (buf, ".dmb %x %x", memaddr, len);
+ write_and_expect (buf);
+ count = 0;
+
+ c = sr_readchar ();
+
+ while (count < len)
+ {
+ while (!isdigit (c) && !isalpha (c)) {
+ if (c == '!')
+ {
+ expect_prompt();
+ errno =EIO;
+ return 0;
+
+ }
+ c = sr_readchar ();
+ }
+ myaddr[count++] = get_hex (&c);
+ c = sr_readchar ();
+ if (c == ' ')
+ {
+ c = sr_readchar ();
+ if (c == ' ')
+ while (c != '\r')
+ c = sr_readchar ();
+ }
+ }
+
+ expect_prompt ();
+
+
+ return len;
+}
+
+static int
+est_xfer_inferior_memory (memaddr, myaddr, len, write, target)
+ CORE_ADDR memaddr;
+ unsigned char *myaddr;
+ int len;
+ int write;
+ struct target_ops *target; /* ignored */
+{
+ if (write)
+ {
+ return est_write_memory (memaddr, myaddr, len);
+ }
+ else
+ {
+ return est_read_memory (memaddr, myaddr, len);
+ }
+}
+
+
+#define MAX_DEBUG_BREAKPOINTS 100
+
+extern int memory_breakpoint_size;
+static CORE_ADDR breakaddr[MAX_DEBUG_BREAKPOINTS] =
+{0};
+
+int
+est_clear_all_breakpoints ()
+{
+ int i;
+ for (i = 0; i < MAX_DEBUG_BREAKPOINTS; i++)
+ {
+ breakaddr[i] = 0;
+ }
+
+ if (sr_is_open ())
+ {
+ write_and_expect (".RB");
+ expect_prompt ();
+ }
+ return 0;
+}
+
+static int
+est_insert_breakpoint (addr, shadow)
+ CORE_ADDR addr;
+ unsigned char *shadow;
+{
+ int i;
+
+ for (i = 0; i <= MAX_DEBUG_BREAKPOINTS; i++)
+ if (breakaddr[i] == 0)
+ {
+ char buf[20];
+ breakaddr[i] = addr;
+ sprintf (buf, ".SB %x", addr);
+ write_and_expect (buf);
+ expect_prompt ();
+ return 0;
+ }
+ error ("Too many breakpoints ( > %d) for the est\n", MAX_DEBUG_BREAKPOINTS);
+ return 1;
+}
+
+static int
+est_remove_breakpoint (addr, shadow)
+ CORE_ADDR addr;
+ unsigned char *shadow;
+{
+ int i;
+
+ for (i = 0; i < MAX_DEBUG_BREAKPOINTS; i++)
+ if (breakaddr[i] == addr)
+ {
+ char buf[20];
+ breakaddr[i] = 0;
+ sprintf (buf, ".RB %x", addr);
+ write_and_expect (buf);
+ expect_prompt ();
+ return 0;
+ }
+
+ error ("Can't find breakpoint associated with 0x%x\n", addr);
+ return 1;
+}
+
+
+/* Wait until the remote machine stops, then return,
+ storing status in STATUS just as `wait' would. */
+
+static int
+est_wait (pid, status)
+ int pid;
+ struct target_waitstatus *status;
+{
+ int c = sr_readchar ();
+ while (c != '!')
+ c = sr_readchar ();
+ /* What sort of stop */
+ c = sr_readchar ();
+ status->kind = TARGET_WAITKIND_STOPPED;
+ switch (c)
+ {
+ case 'E':
+ status->value.sig = TARGET_SIGNAL_BUS;
+ break;
+ /* Address error */
+ case 'A':
+ status->value.sig = TARGET_SIGNAL_BUS;
+ break;
+ /* Break */
+ case 'B':
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+ }
+ expect_prompt ();
+ return 0;
+}
+
+void
+est_checkin ()
+{
+ write_and_expect (".in");
+ gr_expect_prompt ();
+}
+
+extern struct gr_settings est_settings;
+
+static void
+est_open (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ gr_open (args, from_tty, &est_settings);
+}
+
+/* Define the target subroutine names */
+
+struct target_ops est_ops =
+{
+ "est",
+ "Remote EST-300 target",
+ "Use a remote EST-300 ICE connected by a serial line,\n\
+or a network connection.\n\
+Arguments are the name of the device for the serial line,\n\
+the speed to connect at in bits per second.\n\
+eg\n\
+target est /dev/ttya 9600\n\
+target est foobar",
+ est_open,
+ gr_close,
+ 0,
+ gr_detach,
+ est_resume,
+ est_wait,
+ est_fetch_register,
+ est_store_register,
+ gr_prepare_to_store,
+ est_xfer_inferior_memory,
+ gr_files_info,
+ est_insert_breakpoint,
+ est_remove_breakpoint, /* Breakpoints */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* Terminal handling */
+ gr_kill,
+ gr_load_image, /* load */
+ 0, /* lookup_symbol */
+ gr_create_inferior,
+ gr_mourn,
+ 0, /* can_run */
+ 0, /* notice_signals */
+ 0, /* to_stop */
+ 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 struct gr_settings est_settings =
+{
+ NULL, /* dcache */
+ ">", /* prompt */
+ &est_ops, /* ops */
+ est_clear_all_breakpoints,
+ est_read_memory, /* readfunc */
+ est_write_memory, /* writefunc */
+ est_checkin, /* checkin */
+};
+
+void
+_initialize_remote_est ()
+{
+ add_target (&est_ops);
+}