* configure.in (--enable-netrom): New configuration option.
authorStan Shebs <shebs@codesourcery.com>
Wed, 3 May 1995 01:43:27 +0000 (01:43 +0000)
committerStan Shebs <shebs@codesourcery.com>
Wed, 3 May 1995 01:43:27 +0000 (01:43 +0000)
* Makefile.in (REMOTE_OBS): Rename from REMOTE_O, append
value of NETROM_OBS.
(NETROM_OBS): New variable.
* remote-nrom.c: New file, NetROM target support.
* config/a29k/a29k-udi.mt, config/i960/vxworks960.mt: Use
REMOTE_OBS instead of REMOTE_O.
start-sanitize-arc
* config/arc/arc.mt: Ditto.
end-sanitize-arc

gdb/config/a29k/a29k-udi.mt
gdb/config/arc/arc.mt
gdb/config/i960/vxworks960.mt
gdb/configure.in
gdb/remote-nrom.c [new file with mode: 0644]

index d0cac1a26587cf8fd01cfa48b404280aa08920a8..6d5d27b701dd99319bf33d5cb7f4785da96b0fa2 100644 (file)
@@ -3,6 +3,6 @@ TDEPFILES= a29k-tdep.o remote-udi.o udip2soc.o udr.o udi2go32.o
 TM_FILE= tm-a29k.h
 
 # Disable standard remote support.
-REMOTE_O=
+REMOTE_OBS=
 
 MT_CFLAGS = $(HOST_IPC)
index 6b2dc12a15de84192d8c255f2c4c3625520c18e9..6a8379b1927642b5097be806679c34182aeaee15 100644 (file)
@@ -1,5 +1,7 @@
 # Target: arc processor
 TDEPFILES= arc-tdep.o remote-arc.o 
 TM_FILE= tm-arc.h
-REMOTE_O=dcache.o remote-utils.o
+
+REMOTE_OBS= dcache.o remote-utils.o
+
 SER_HARDWIRE= ser-go32-para.o
index 6501f4a91bd137858c2d3de7b07475c96ac2b537..3623804b78c77722153cb5cee902aaa6c1608b3e 100644 (file)
@@ -1,8 +1,10 @@
 # Target: VxWorks running on an Intel 960
 TDEPFILES= i960-tdep.o remote-vx.o remote-vx960.o xdr_ld.o xdr_ptrace.o xdr_rdb.o
 TM_FILE= tm-vx960.h
+
 # Define this for the vx-share routines, which don't see param.h.
 MT_CFLAGS= -DI80960
+
 # Don't use remote.o; it doesn't compile (and won't work) due to lack of
 # BREAKPOINT.
-REMOTE_O=dcache.o remote-utils.o 
+REMOTE_OBS= dcache.o remote-utils.o 
index 52cebd8ba663a1b4a22985c8fb9245a5269fe422..cf76597745d634fc2d8a7939e892bdf6d8e35aeb 100644 (file)
@@ -466,6 +466,14 @@ ENABLE_CLIBS = $(TCL) $(TK) $(X11_LIB_SWITCHES) $(X11_LIBS) -lm
 fi
 # end-sanitize-gdbtk
 
+if [ "${enable_netrom}" = "yes" ] ; then
+       sed -e '/# End of host and/i\
+\
+NETROM_OBS = remote-nrom.o\
+' < Makefile > Makefile.tem
+       mv -f Makefile.tem Makefile
+fi
+
 sed -e '/^TM_FILE[     ]*=/s,^TM_FILE[         ]*=[    ]*,&config/'"${gdb_target_cpu}"'/,
 /^XM_FILE[     ]*=/s,^XM_FILE[         ]*=[    ]*,&config/'"${gdb_host_cpu}"'/,
 /^NAT_FILE[    ]*=/s,^NAT_FILE[        ]*=[    ]*,&config/'"${gdb_host_cpu}"'/,' <Makefile >Makefile.tmp
diff --git a/gdb/remote-nrom.c b/gdb/remote-nrom.c
new file mode 100644 (file)
index 0000000..1699d4c
--- /dev/null
@@ -0,0 +1,1356 @@
+/* Remote debugging with the XLNT Designs, Inc (XDI) NetROM.
+   Copyright 1990, 1991, 1992, 1995 Free Software Foundation, Inc.
+   Contributed by:
+        Roger Moyers 
+        XLNT Designs, Inc.
+        15050 Avenue of Science, Suite 106
+        San Diego, CA  92128
+        (619)487-9320
+        roger@xlnt.com
+   Adapted from work done at Cygnus Support in remote-nindy.c,
+   later merged in by Stan Shebs at Cygnus.
+
+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 "gdbcmd.h"
+#include <string.h>
+#include "inferior.h"
+#include "wait.h"
+#include "value.h"
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <stropts.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#include "terminal.h"
+#include "target.h"
+#include "gdbcore.h"
+
+/* Packet header found on every packet sent to/from GDB.  */
+
+typedef struct gpkthdr {
+  unsigned char csum;          /* Check sum */
+  unsigned char seq_num;       /* Sequence number */
+  unsigned short len;          /* Number of bytes in packet */
+  unsigned char cmd;           /* GDB command */
+  unsigned char pad[3];
+  unsigned long addr;          /* Address if needed */
+  unsigned long datalen;       /* # of bytes to read/write */
+} GPKTHDR;
+
+#define GDB_START_DELIMITER '['
+#define GDB_END_DELIMITER ']'
+
+/* GDB requests. */
+
+#define GDB_QUERY_CMD   0x01
+#define GDB_STATUS      0x02
+#define GDB_READ_REGS   0x03
+#define GDB_WRITE_REGS  0x04
+#define GDB_READ_MEM    0x05
+#define GDB_WRITE_MEM   0x06
+#define GDB_CONTINUE    0x07
+#define GDB_STEP        0x08
+
+/* Responses.  */
+
+#define GDB_ACK            0x11
+#define GDB_NACK           0x12
+#define GDB_READ_REG_RESP  0x13
+#define GDB_READ_MEM_RESP  0x14
+#define GDB_WRITE_REG_RESP 0x15
+#define GDB_WRITE_MEM_RESP 0x16
+
+#define GDB_BP_TRAP     "05"
+#define GDB_BUSERR_TRAP "10"
+#define GDB_ILLOP_TRAP  "40"
+
+#define GDB_ACK_VALUE   "OK"
+
+/* Default ports used to talk with the NetROM.  */
+
+#define DEFAULT_NETROM_TARGET_PORT  1235
+#define DEFAULT_NETROM_LOAD_PORT    1236
+#define DEFAULT_NETROM_CONTROL_PORT 1237
+
+#define UC(b) (((long)b)&0xff)
+
+#define NROM_BUF_SIZE  2048
+#define MAX_SEND_ATTEMPTS 10
+#define READ_BUF_SIZE  2048
+
+/* Definitions for filetype.  */
+
+#define BINARY_FTYPE 0
+#define MOTO_SREC 1
+#define INTEL_HEX 2
+
+#if 0 /* for debugging, if anyone cares */
+static char *GCMDTYPE[] = {
+  "ZERO",
+  "GDB_QUERY",
+  "GDB_STATUS",
+  "GDB_READ_REGS",
+  "GDB_WRITE_REGS",
+  "GDB_READ_MEM",
+  "GDB_WRITE_MEM",
+  "GDB_CONTINUE",
+  "GDB_STEP",
+  "CMD9",
+  "CMDA",
+  "CMDB",
+  "CMDC",
+  "CMDD",
+  "CMDE",
+  "CMDF",
+  "RESP0",
+  "GDB_ACK",
+  "GDB_NACK",
+  "GDB_READ_REG_RESP",
+  "GDB_READ_MEM_RESP",
+  "GDB_WRITE_REG_RESP",
+  "GDB_WRITE_MEM_RESP"
+};
+#endif
+
+static void nrom_attach PARAMS ((char *, int));
+
+static int  nrom_can_run PARAMS ((void));
+
+static void nrom_close PARAMS ((int));
+
+static void nrom_create_inferior PARAMS ((char *, char *, char **));
+
+static void nrom_detach PARAMS ((char *, int));
+
+static void nrom_fetch_registers PARAMS ((int));
+
+static void nrom_files_info PARAMS ((struct target_ops *));
+
+static void nrom_kill PARAMS ((void));
+
+static void nrom_load PARAMS ((char *, int));
+
+static void nrom_mourn PARAMS ((void));
+
+static void nrom_open PARAMS ((char *,int));
+
+static void nrom_resume PARAMS ((int, int, enum target_signal));
+
+static void nrom_prepare_to_store PARAMS ((void));
+
+static void nrom_store_registers PARAMS ((int));
+
+static int nrom_wait PARAMS ((int pid, struct target_waitstatus *status));
+
+static int nrom_xfer_inferior_memory PARAMS ((CORE_ADDR, char *, int, int,
+                                              struct target_ops *));
+
+static int nrom_write_inferior_memory PARAMS ((CORE_ADDR, char *, int));
+
+static int nrom_read_inferior_memory PARAMS ((CORE_ADDR, char *, int));
+
+/* New commands.  */
+
+static void nrom_set_target_port PARAMS ((char *, int));
+
+static void nrom_set_control_port PARAMS ((char *, int));
+
+static void nrom_set_load_port PARAMS ((char *, int));
+
+static void nrom_set_ipaddr PARAMS ((char *, int));
+
+static void nrom_set_filetype PARAMS ((char *, int));
+
+static void nrom_show_status PARAMS ((char *, int));
+
+static void nrom_passthru PARAMS ((char *, int));
+
+/* Packet functions.  */
+
+static void build_pkt PARAMS ((int, unsigned char *, long, 
+                              unsigned char *, unsigned long, unsigned long,
+                              int));
+
+static int compute_csum PARAMS ((unsigned char *, int));
+
+#if 0
+static void dump_pkt PARAMS ((GPKTHDR *, unsigned char *));
+#endif
+
+static int get_seq_number PARAMS ((void));
+
+static char *hex2mem PARAMS ((char *, char *, int));
+
+static char *mem2hex PARAMS ((char *, char *, int));
+
+static void nrom_send PARAMS ((int, char *, int, long, long, char *));
+
+static void send_query_cmd PARAMS ((void));
+
+static int send_pkt PARAMS ((int, char *, int, long, int));
+
+static int read_pkt PARAMS ((char *));
+
+static void send_query_cmd PARAMS ((void));
+
+static int tohex PARAMS ((int));
+
+static int parse_pkt PARAMS ((unsigned char *, GPKTHDR *, char *));
+
+static int writen PARAMS ((int, char *, int));
+
+/* Private globals. */
+
+/* We talk to the NetROM over these sockets.  */
+
+static int nrom_load_sock = -1;
+static int nrom_targ_sock = -1;
+static int nrom_ctrl_sock = -1;
+
+/* For binding to the socket we ned a sockaddr_in structure.  */
+
+static struct sockaddr_in nrom_sin;
+
+/* The IP Address of the NetROM is needed so we know who to talk to.  */
+
+static unsigned long nrom_ipaddr = 0;
+
+static int load_port = DEFAULT_NETROM_LOAD_PORT;
+static int target_port = DEFAULT_NETROM_TARGET_PORT;
+static int control_port = DEFAULT_NETROM_CONTROL_PORT;
+
+static int nrom_filetype = BINARY_FTYPE;
+
+static unsigned char host_seq_num = 0;
+
+static char hexchars[] = "0123456789abcdef";
+
+static char freadbuf[READ_BUF_SIZE];
+
+static char readbuf[NROM_BUF_SIZE];
+static int bufdata = 0;
+static int bufindex = 0;
+
+static char workbuf[NROM_BUF_SIZE];
+static char sendbuf[NROM_BUF_SIZE];
+
+/* Forward data declaration. */
+
+extern struct target_ops nrom_ops;
+
+/* This routine builds a packet to send to gdb running on the host.  */
+
+static void
+build_pkt (cmd, data, datalen, pkt, addr, len, seq)
+     int cmd;
+     unsigned char *data;
+     long datalen;
+     unsigned char *pkt;
+     unsigned long addr;
+     unsigned long len;
+     int seq;
+{
+  GPKTHDR phdr;
+  char *dptr;
+  char *pktptr;
+  unsigned char csum;
+  int plen;
+  
+  phdr.csum = 0;
+  phdr.len = sizeof(GPKTHDR) + datalen;
+  phdr.seq_num = seq;
+  phdr.cmd = cmd;
+  phdr.pad[0] = phdr.pad[1] = phdr.pad[2] = 0;
+  phdr.addr = addr;
+  phdr.datalen = len;
+  /* Convert packet header to ASCII.  */
+  dptr = mem2hex ((char *) &phdr, pkt, sizeof(GPKTHDR));
+
+  /* Calculate pkt length now that it is converted.  */
+  plen = (int) ((unsigned long)dptr - (unsigned long)pkt) + datalen;
+  /* Put data in packet.  */
+  if (datalen > 0)
+    memcpy (dptr, data, datalen);
+
+  /* Compute checksum.  For computing checksum we skip first two bytes
+     since this is where the checksum will go.  */
+  pktptr = pkt + 2;
+  csum = compute_csum (pktptr, plen - 2);
+  *pkt++ = hexchars[csum >> 4];
+  *pkt++ = hexchars[csum % 16];
+  dptr += datalen;
+  *dptr = '\0';
+}
+
+static int
+compute_csum (data, len)
+     unsigned char *data;
+     int len;
+{
+  unsigned char csum;
+
+  csum = 0;
+  while (len > 0)
+    {
+      csum += *data++;
+      --len;
+    }
+  return csum;
+}
+
+#if 0 /* for debugging, if anyone cares */
+static void
+dump_pkt (hdr, data)
+     GPKTHDR *hdr;
+     unsigned char *data;
+{
+  int i;
+
+  printf_filtered ("PACKET: csum = %x,seq = %d,len = %d\n",hdr->csum,hdr->seq_num,
+        hdr->len);
+
+  printf_filtered ("cmd = %s,addr = %x, datalen = %d\n", GCMDTYPE[hdr->cmd],
+        hdr->addr,hdr->datalen);
+  if (hdr->datalen)
+    {
+      for (i = 0; i < hdr->datalen * 2; i++)
+       printf_filtered ("%x",data[i]);
+      printf_filtered ("\n");
+    }
+}
+#endif
+
+static int
+get_seq_number()
+{
+  return host_seq_num++;
+}
+
+int 
+hex (ch)
+     int ch;
+{
+  if ((ch >= 'a') && (ch <= 'f'))
+    return (ch - 'a' + 10);
+  if((ch >= 'A') && (ch <= 'F'))
+    return ((ch - 'A') + 10);
+  if ((ch >= '0') && (ch <= '9'))
+    return (ch - '0');
+  return 0;
+}
+
+/* Convert the hex array pointed to by buf into binary to be placed in mem
+   return a pointer to the character AFTER the last byte written.  */
+
+static char*
+hex2mem(buf, mem, count)
+     char* buf;
+     char* mem;
+     int   count;
+{
+  int i;
+  unsigned char ch;
+
+  for (i = 0; i < count; i++)
+    {
+      ch = hex(*buf++) << 4;
+      ch = ch + hex(*buf++);
+      *mem++ = ch;
+    }
+  return mem;
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf
+   return a pointer to the last char put in buf (null) */
+
+static char *
+mem2hex (mem, buf, count)
+     char* mem;
+     char* buf;
+     int   count;
+{
+  int i;
+  unsigned char ch;
+
+  for (i = 0; i < count; i++)
+    {
+      ch = *mem++;
+      *buf++ = hexchars[ch >> 4];
+      *buf++ = hexchars[ch % 16];
+    }
+  *buf = 0;
+  return buf;
+}
+
+static int
+nrom_control_send (s, nbytes)
+     char *s;
+     int nbytes;
+{
+  long len;
+  char buf[10];
+
+  /* clear leading characters */
+  /* FIXME: The ioctl uses here seem bogus to me. -sts */
+  len = 1;
+  while (len > 0)
+    {
+      if (ioctl (nrom_ctrl_sock, FIONREAD, &len) < 0)
+       {
+         perror ("nrom_control_send ioctl");
+         return (-1);
+       }
+      if (len > 0)
+       {
+         if (read (nrom_ctrl_sock, buf, 1) < 0)
+           {
+             perror ("nrom_control_send read");
+             return (-1);
+           }
+       }
+    }
+
+  if (remote_debug)
+    printf_filtered ("nrom_control_send: sending '%s' (%d bytes) to NetROM\n",
+                    s, nbytes);
+
+  if (writen (nrom_ctrl_sock, s, nbytes) < 0)
+    {
+      perror ("nrom_control_send");
+      return (-1);
+    }
+
+  /* clear trailing characters */
+  len = 1;
+  while (len > 0)
+    {
+      if (ioctl (nrom_ctrl_sock, FIONREAD, &len) < 0)
+       {
+         perror ("nrom_control_send ioctl");
+         return (-1);
+       }
+      if (len > 0)
+       {
+         if (read (nrom_ctrl_sock, buf, 1) < 0)
+           {
+             perror ("nrom_control_send read");
+             return (-1);
+           }
+       }
+    }
+  return 0;
+}
+
+static void
+nrom_kill ()
+{
+}
+
+/* Download a file specified in ARGS to the netROM.  */
+
+static void
+nrom_load (args, fromtty)
+     char *args;
+     int fromtty;
+{
+  int fd, rd_amt, fsize;
+  struct sockaddr_in sin;
+  bfd *pbfd;
+  asection *section;
+  char *downloadstring = "download 0\n";
+
+  /* Tell the netrom to get ready to download. */
+  if (nrom_control_send (downloadstring, strlen (downloadstring)) < 0)
+    error ("nrom_load: control_send() of `%s' failed", downloadstring);
+
+  /* Wait for the download daemon to start up. */
+  sleep (1);
+
+  nrom_load_sock = socket (AF_INET, SOCK_STREAM, 0);
+  if (nrom_load_sock == -1)
+    error ("Could not create download socket, error %d", errno);
+
+  memset (&sin, 0, sizeof(struct sockaddr_in));
+  sin.sin_family = AF_INET;
+  sin.sin_port = htons (load_port);
+  sin.sin_addr.s_addr = htonl (nrom_ipaddr);
+
+  if (connect (nrom_load_sock, &sin, sizeof(sin)) == -1)
+    error ("Connect failed, error %d", errno);
+
+  pbfd = bfd_openr (args, 0);
+
+  if (pbfd)
+    {
+      if (!bfd_check_format (pbfd, bfd_object)) 
+       error ("\"%s\": not in executable format: %s",
+              args, bfd_errmsg (bfd_get_error ()));
+
+      for (section = pbfd->sections; section; section = section->next) 
+       {
+         if (bfd_get_section_flags (pbfd, section) & SEC_ALLOC)
+           {
+             bfd_vma section_address;
+             unsigned long section_size;
+             const char *section_name;
+
+             section_name = bfd_get_section_name (pbfd, section);
+             section_address = bfd_get_section_vma (pbfd, section);
+             section_size = bfd_section_size (pbfd, section);
+
+             if (bfd_get_section_flags (pbfd, section) & SEC_LOAD)
+               {
+                 file_ptr fptr;
+
+                 printf_filtered ("[Loading section %s at %x (%d bytes)]\n",
+                                  section_name, section_address,
+                                  section_size);
+
+                 fptr = 0;
+
+                 while (section_size > 0)
+                   {
+                     char buffer[1024];
+                     int count;
+                     
+                     count = min (section_size, 1024);
+
+                     bfd_get_section_contents (pbfd, section, buffer, fptr,
+                                               count);
+
+                     writen (nrom_load_sock, buffer, count);
+                     section_address += count;
+                     fptr += count;
+                     section_size -= count;
+                   }
+               }
+             else                      /* BSS and such */
+               {
+                 printf_filtered ("[section %s: not loading]\n",
+                                  section_name);
+               }
+           }
+       }
+    }
+  else
+    error ("\"%s\": Could not open", args);
+
+  close (nrom_load_sock);
+}
+
+/* This is called not only when we first attach, but also when the
+   user types "run" after having attached.  */
+
+static void
+nrom_create_inferior (execfile, args, env)
+     char *execfile;
+     char *args;
+     char **env;
+{
+}
+
+/* Open a connection to the remote NetROM devices.  */
+
+static void
+nrom_open (name, from_tty)
+     char *name;
+     int from_tty;
+{
+  int errn;
+
+  if (name)
+    nrom_set_ipaddr (name, from_tty);
+  else if (nrom_ipaddr == 0)
+    error (
+"To open a NetROM connection, you must specify the hostname\n\
+or IP address of the NetROM device you wish to use.");
+
+  push_target (&nrom_ops);
+
+  /* Create the socket used for talking with the target. */
+  nrom_targ_sock = socket (AF_INET, SOCK_STREAM, 0);
+
+  /* Bind the socket.  */
+  nrom_sin.sin_family = AF_INET;
+  nrom_sin.sin_port = htons (target_port);
+  nrom_sin.sin_addr.S_un.S_addr = htonl (nrom_ipaddr);
+
+  /* Connect to the remote host.  */
+  if (connect (nrom_targ_sock, &nrom_sin, sizeof(nrom_sin)) == -1)
+      error ("Connect failed, error %d", errno);
+
+  /* Create the socket used for talking with the debugger services.  */
+  nrom_ctrl_sock = socket (AF_INET, SOCK_STREAM, 0);
+
+  /* Bind the socket.  */
+  nrom_sin.sin_family = AF_INET;
+  nrom_sin.sin_port = htons (control_port);
+  nrom_sin.sin_addr.S_un.S_addr = htonl (nrom_ipaddr);
+
+  /* Connect to the remote host. */
+  if (connect (nrom_ctrl_sock, &nrom_sin, sizeof(nrom_sin)) == -1)
+    {
+      errn = errno;
+      close (nrom_targ_sock);
+      error ("Connect control_socket failed, error %d", errn);
+    }
+
+  if (from_tty)
+    {
+      unsigned char *i;
+
+      printf_filtered ("Connected to NetROM device \"%s\"", name);
+      i = (unsigned char *) &nrom_ipaddr;
+      printf_filtered (" (%d.%d.%d.%d)\n",
+                      UC(i[0]), UC(i[1]), UC(i[2]), UC(i[3]));
+    }
+}
+
+static int
+nrom_can_run ()
+{
+  return 1;
+}
+
+/* Close out all files and local state before this target loses control. */
+
+static void
+nrom_close (quitting)
+     int quitting;
+{
+}
+
+/* Attach to the target that is already loaded and possibly running */
+
+static void
+nrom_attach (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  int nwaiting;
+  char buf[10];
+
+  if (from_tty)
+    printf_filtered ("Attaching to NetROM\n");
+
+  /* clear any pending data on the socket */
+  printf_filtered ("Waiting for pending data to arrive... ");
+  fflush(stdout);
+  sleep(1);
+  printf_filtered ("that's long enough!\n");
+  while (1)
+    {
+      if (ioctl(nrom_targ_sock, FIONREAD, &nwaiting) != 0)
+       {
+         /* couldn't determine data left */
+         perror("nrom_attach: ioctl FIONREAD");
+         break;
+       }
+      else if (nwaiting > 0)
+       {
+         /* flush incoming data */
+         while (nwaiting != 0)
+           {
+             if (read (nrom_targ_sock, buf, 1) < 0)
+               {
+                 perror("nrom_attach: read");
+                 exit(1);
+               }
+             if (remote_debug > 2)
+               putc(buf[0], stdout);
+             nwaiting--;
+           }
+       } 
+      else 
+       {
+         /* no more data */
+         break;
+       }
+    }
+  printf_filtered ("Pending data removed\n");
+
+  /* We will get a task spawn event immediately.  */
+  send_query_cmd ();
+  target_has_execution = 1;
+/*
+  start_remote();
+*/
+}
+
+/* Terminate the open connection to the remote debugger.  Use this
+   when you want to detach and do something else with your gdb.  */
+
+static void
+nrom_detach (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  pop_target ();
+  if (from_tty)
+    printf_filtered ("Ending remote debugging\n");
+}
+/* Tell the remote machine to resume.  */
+
+static void
+nrom_prepare_to_store()
+{
+}
+
+static void
+nrom_resume (pid, step, siggnal)
+     int pid, step;
+     enum target_signal siggnal;
+{
+  if (step)
+    send_pkt (GDB_STEP, NULL, 0, 0, 0);
+  else
+    send_pkt (GDB_CONTINUE, NULL, 0, 0, 0);
+}
+
+/* Wait until the remote machine stops, then return,
+   storing status in STATUS just as `wait' would.  */
+
+static int
+nrom_wait (pid, status)
+     int pid;
+     struct target_waitstatus *status;
+{
+  static char pkt[NROM_BUF_SIZE], inbuf[NROM_BUF_SIZE];
+  GPKTHDR phdr;
+
+  status->kind = TARGET_WAITKIND_EXITED;
+  status->value.integer = 0;
+
+  while (1)
+    {
+      if (read_pkt (pkt) == -1)
+       continue;
+
+      if (parse_pkt (pkt, &phdr, inbuf) < 0)
+       {
+         if (remote_debug)
+           printf_filtered ("Bad packet in nrom_wait\n");
+         send_query_cmd ();
+         continue;
+       }
+
+      /* Got good packet.  Verify command is right.  */
+      if (phdr.cmd != GDB_STATUS)
+       {
+         /*  Wrong response.  Resend command.  */
+         send_query_cmd ();
+         continue;
+       }
+      /* Packet is fine.  Exit loop.  */
+      return inferior_pid;
+    }
+}
+
+/* Read the remote registers.  */
+
+static void
+nrom_fetch_registers (regno)
+     int regno;
+{
+  char buf[NROM_BUF_SIZE];
+  char regs[REGISTER_BYTES];
+  int i;
+
+#ifdef DEBUG
+  printf_filtered ("reg no is %d\n",regno);
+#endif
+
+  nrom_send (GDB_READ_REGS, NULL, 0, -1, 0, buf);
+  memcpy (regs, buf, REGISTER_BYTES);
+  for (i = 0; i < NUM_REGS; i++)
+    supply_register (i, &regs[REGISTER_BYTE(i)]);
+#ifdef NO_SINGLE_REG
+  nrom_send (GDB_READ_REGS, NULL, 0, regno, 0, buf);
+  if (regno != -1)
+    supply_register(regno,buf);
+  else
+    {
+      memcpy (regs, buf, REGISTER_BYTES);
+      for (i = 0; i < NUM_REGS; i++)
+       supply_register (i, &regs[REGISTER_BYTE(i)]);
+    }
+#endif
+}
+
+static void
+nrom_send (cmd, data, datalen, addr, len, resp)
+     int cmd;
+     char *data;
+     int datalen;
+     long addr;
+     long len;
+     char *resp;
+{
+  GPKTHDR phdr;
+  char inbuf[NROM_BUF_SIZE];
+               
+  while (1)
+    {
+      while (send_pkt (cmd, data, datalen, addr, len) < 0)
+       ;
+      if (read_pkt (inbuf) != -1)
+       {
+         if (parse_pkt (inbuf, &phdr, resp) < 0)
+           continue;
+         if (phdr.cmd != GDB_NACK)
+           return;
+        }
+    }
+}
+
+static void 
+nrom_set_filetype (args, fromtty)
+     char *args;
+     int fromtty;
+{
+  if (args[0] == 'b')
+    nrom_filetype = BINARY_FTYPE;
+  else if (args[0] == 'm')
+    nrom_filetype = MOTO_SREC;
+  else if (args[0] == 'i')
+    nrom_filetype = INTEL_HEX;
+  else
+    printf_filtered ("Unknown file type\n");
+}
+
+static void 
+nrom_set_ipaddr (args, fromtty)
+     char *args;
+     int fromtty;
+{
+  struct hostent *h;
+  char buf[10];
+  int i,j,val;
+  unsigned long        newip = 0;
+
+  /* First do a check to see if they typed in a hostname.  */
+  if (!(*args))
+    error ("Please enter a hostname or IP address");
+
+  h = gethostbyname (args);
+  if (h)
+    {
+      /* It is a hostname.  We just need the ipaddress.  */
+      memcpy (&nrom_ipaddr, h->h_addr, h->h_length);
+    }
+  else
+    {
+      /* Better be in decimal dot notation,ie. xx.xx.xx.xx  */
+      if (isdigit (args[0]) && strchr (args, '.'))
+       {
+         j = 4;
+         while (j)
+           {
+             memset (buf, 0, 10);
+             i = 0;
+             while((*args) && (*args != '.'))
+               {
+                 buf[i] = *args++;
+                 i++;
+               }
+             if (i)
+               {
+                 val = (int) strtol (buf, NULL, 10);
+
+                 if (val > 255)
+                   error ("Invalid IP address");
+
+                 j--;
+                 newip |= val << (8 * j);
+                 args++;
+               }
+           }
+       }
+      else
+       {
+         error ("Invalid host name/address");
+       }
+      nrom_ipaddr = newip;
+    }
+}
+
+static void 
+nrom_set_load_port (args, fromtty)
+     char *args;
+     int fromtty;
+{
+  load_port = (int) strtol (args, NULL, 10);
+}
+
+static void 
+nrom_set_target_port (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  target_port = (int) strtol (args, NULL, 10);
+}
+
+static void
+nrom_set_control_port (args, fromtty)
+     char *args;
+     int fromtty;
+{
+  control_port = (int) strtol (args, NULL, 10);
+}
+
+static void 
+nrom_show_status (args,from_tty)
+     char *args;
+     int from_tty;
+{
+  unsigned char *i;
+
+  i = (unsigned char *)&nrom_ipaddr;
+
+  printf_filtered ("NetROM target port is %d\n", target_port);
+  printf_filtered ("NetROM download port is %d\n", load_port);
+  printf_filtered ("NetROM debug control port is %d\n", control_port);
+  
+  printf_filtered ("NetROM IP Address is %d.%d.%d.%d\n",
+                   UC(i[0]), UC(i[1]), UC(i[2]), UC(i[3]));                            
+  if (nrom_filetype == BINARY_FTYPE)
+    printf_filtered ("download filetype is binary\n");
+  else if (nrom_filetype == MOTO_SREC)
+    printf_filtered ("download filetype is moto-srec\n");
+  else if (nrom_filetype == INTEL_HEX)
+    printf_filtered ("download filetype is intel-hex\n");
+}
+
+/* Pass arguments directly to the NetROM. */
+
+static void
+nrom_passthru (args, fromtty)
+     char *args;
+     int fromtty;
+{
+  char buf[1024];
+
+  sprintf(buf, "%s\n", args);
+  if (nrom_control_send (buf, strlen (buf)) < 0)
+    error ("nrom_reset: control_send() of `%s'failed", args);
+}
+
+static void 
+nrom_store_registers (regno)
+int regno;
+{
+  char buf[NROM_BUF_SIZE];
+  int i;
+  char *p;
+
+  p = buf;
+  for (i = 0; i < REGISTER_BYTES; i++)
+    {
+      *p++ = tohex ((registers[i] >> 4) & 0xf);
+      *p++ = tohex (registers[i] & 0xf);
+    }
+  *p = '\0';
+  nrom_send (GDB_WRITE_REGS, buf, REGISTER_BYTES * 2, 0, REGISTER_BYTES * 2,
+            buf);
+}
+
+static int
+nrom_xfer_inferior_memory (memaddr, myaddr, len, write, target)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+     struct target_ops *target;
+{
+  if (write)
+    return nrom_write_inferior_memory (memaddr, myaddr, len);
+  else
+    return nrom_read_inferior_memory (memaddr, myaddr, len);
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+   to inferior's memory at MEMADDR.  Returns errno value.  */
+
+static int
+nrom_write_inferior_memory (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  char buf[NROM_BUF_SIZE],obuf[NROM_BUF_SIZE];
+  int i;
+  char *p;
+
+  p = obuf;
+  for (i = 0; i < len; i++)
+    {
+      *p++ = tohex ((myaddr[i] >> 4) & 0xf);
+      *p++ = tohex (myaddr[i] & 0xf);
+    }
+  *p = '\0';
+  nrom_send (GDB_WRITE_MEM, obuf, len * 2, memaddr, len, buf);
+
+  return len;
+}
+
+/* Read LEN bytes from inferior memory at MEMADDR.  Put the result
+   at debugger address MYADDR.  Returns errno value.  */
+
+static int
+nrom_read_inferior_memory (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  char buf[NROM_BUF_SIZE];
+
+  nrom_send (GDB_READ_MEM, NULL, 0, memaddr, len, buf);
+  memcpy (myaddr, buf, len);
+  return len;
+}
+
+static void
+nrom_files_info (ignore)
+     struct target_ops *ignore;
+{
+}
+
+static void
+nrom_mourn() 
+{ 
+  unpush_target (&nrom_ops);
+  generic_mourn_inferior ();
+}
+
+/* Convert a packet into its parts and verify check sum.  */
+
+static int
+parse_pkt (pkt, hdr, data)
+     unsigned char *pkt;
+     GPKTHDR *hdr;
+     char *data;
+{
+  unsigned char xcsum;
+  unsigned char *dptr;
+
+  /* Build packet header from received data.  */
+  hex2mem (pkt, (char *) hdr, sizeof(GPKTHDR));
+  if (remote_debug > 1)
+    {
+      printf_filtered ("Packet received: csum = %x,seq number = %x,len = %d\n",
+             hdr->csum,hdr->seq_num,hdr->len);
+      printf_filtered ("cmd = %x,addr = %x,datalen = %d\n",
+             hdr->cmd,hdr->addr,hdr->datalen);
+    }
+  /* Skip first two bytes of packet when computing checksum.  */
+  dptr = (sizeof(GPKTHDR) * 2) + pkt;
+  pkt += 2;
+  if (remote_debug > 1)
+    {
+      printf_filtered ("Computing checksum over pkt %s\n",pkt);
+      printf_filtered ("Of length %d\n",strlen(pkt));
+    }
+  xcsum = compute_csum (pkt, strlen (pkt));
+  if (xcsum != hdr->csum)
+    {
+      if (remote_debug)
+       printf_filtered ("Checksum failure: computed %x, received %x\n",xcsum,  
+               hdr->csum);
+      return (-1);
+    }
+
+  /* Copy data portion to callers data buffer converting from ASCII
+     to data as we go.  */
+  hex2mem (dptr, data, hdr->datalen);
+  return 0;
+}
+
+static int
+read_pkt (pkt)
+     char *pkt;
+{
+  int n, tries;
+  struct sockaddr_in from;
+  int from_len = sizeof(from);
+  int gotstart;
+  int total_len;
+  char *p;
+
+  p = pkt;
+  total_len = 0;
+  gotstart = 0;
+
+  while (1)
+    {
+      /* Don't let us get wedged if the target is losing.  */
+      QUIT;
+
+      if (bufdata == 0)
+       {
+         bufindex = 0;
+         n = NROM_BUF_SIZE;
+         /* Perform read on socket.  This will wait.  */
+         bufdata = recvfrom (nrom_targ_sock, readbuf, n, 0, &from, &from_len);
+         if (bufdata < 0)
+           {
+             printf_filtered ("Error on socket read of %d\n",errno);
+             return (-1);
+           }
+         if (remote_debug > 2)
+           {
+             readbuf[bufdata] = '\0';
+             printf_filtered ("Received %d bytes. Data is %s\n",
+                     bufdata, readbuf);
+           }
+       }
+
+      /* skip stuff between packets */
+      while (gotstart == 0 && bufdata != 0
+            && readbuf[bufindex] != GDB_START_DELIMITER)
+       {
+         bufdata--;
+         bufindex++;
+       }
+
+      /* look for a start if we haven't seen one */
+      if (gotstart == 0 && bufdata != 0
+         && readbuf[bufindex] == GDB_START_DELIMITER)
+       {
+         gotstart = 1;
+         bufindex++;
+         bufdata--;
+       }
+
+      /* copy packet data */
+      if (gotstart != 0)
+       {
+         while (bufdata && readbuf[bufindex] != GDB_END_DELIMITER)
+           {
+             *p = readbuf[bufindex];
+             p++;
+             bufdata--;
+             bufindex++;
+             total_len++;
+             if (total_len > NROM_BUF_SIZE)
+               {
+                 error ("read_pkt: packet length exceeds %d\n", 
+                        NROM_BUF_SIZE);
+                 return (-1);
+               }
+           }
+         *p = '\0';
+         if (remote_debug > 2)
+           printf_filtered ("Packet is '%s'\n", pkt);
+       }
+
+      /* Make sure this is the end of the packet.  */
+      if (gotstart != 0 && bufdata != 0
+         && readbuf[bufindex] == GDB_END_DELIMITER)
+       {
+         gotstart = 0;
+         bufindex++;
+         bufdata--;
+         /* Ensure that the packet is terminated.  */
+         *p = '\0';
+         if (remote_debug > 2)
+           printf_filtered ("Returning '%s'\n", pkt);
+         return 0;
+       }
+    }
+}
+
+static void
+send_query_cmd ()
+{
+  while (send_pkt (GDB_QUERY_CMD, NULL, 0, 0, 0) < 0)
+    ;
+}
+
+static int
+send_pkt (cmd, data, datalen, addr, len)
+     int cmd;
+     char *data;
+     int datalen;
+     long addr;
+     int len;
+{
+  char c[2];
+  unsigned char seq;
+  struct sockaddr_in mysin;
+  int send_cnt;
+
+  while (1)
+    {
+      /*  Get a sequence number for this packet.  */
+      seq = get_seq_number ();
+      /*  Build the packet.  */
+      build_pkt (cmd, data, datalen, workbuf, addr, len, seq);
+      /* Put delimiters around the pkt.  */
+      memset (sendbuf, 0, NROM_BUF_SIZE);
+      sendbuf[0] = GDB_START_DELIMITER;
+      strcat (sendbuf, workbuf);
+      c[0] = GDB_END_DELIMITER;
+      c[1] = '\0';
+      strcat (sendbuf, c);
+
+      /* Send the packet out on our socket.  */
+      if (remote_debug > 1)
+       printf_filtered ("Sending pkt: %s\n", sendbuf);
+      mysin.sin_family = AF_INET;
+      mysin.sin_port = target_port;
+      mysin.sin_addr.S_un.S_addr = nrom_ipaddr;
+
+      send_cnt = 0;
+      while (send_cnt < MAX_SEND_ATTEMPTS)
+       {
+         if (sendto (nrom_targ_sock, sendbuf, strlen(sendbuf), 0, &mysin,
+                     sizeof(struct sockaddr_in)) < 0)
+           {
+             printf_filtered ("sendto error of %d\n", errno);
+             send_cnt++;
+           }
+         else
+           break;
+       }
+      if (send_cnt >= MAX_SEND_ATTEMPTS)
+       {
+         printf_filtered ("Socket send failed after %d tries\n",
+                          MAX_SEND_ATTEMPTS);
+         return (-1);
+       }
+      return 1;
+    }
+}
+
+/* Convert number NIB to a hex digit.  */
+
+static int
+tohex (nib)
+     int nib;
+{
+  if (nib < 10)
+    return '0' + nib;
+  else
+    return 'a' + nib - 10;
+}
+
+/* snatched from Stevens, pp279+ */
+
+int
+writen (sock, ptr, nbytes)
+     int sock;
+     char *ptr;
+     int nbytes;
+{
+  int nleft, nwritten;
+  char *buf = ptr;
+
+  nleft = nbytes;
+  while (nleft > 0)
+    {
+      nwritten = write (sock, buf, nleft);
+      if (nwritten <= 0)
+       return nwritten;
+      nleft -= nwritten;
+      buf += nwritten;
+    }
+  return (nbytes - nleft);
+}
+
+/* Define the target vector. */
+
+struct target_ops nrom_ops = {
+  "nrom",                      /* to_shortname */
+  "Remote XDI `NetROM' target",        /* to_longname */
+  "Remote debug using a NetROM over Ethernet",
+  nrom_open,                   /* to_open */
+  nrom_close,
+  nrom_attach,
+  nrom_detach,
+  nrom_resume,
+  nrom_wait,                   /* to_wait */
+  nrom_fetch_registers,                /* to_fetch_registers */
+  nrom_store_registers,                /* to_store_registers */
+  nrom_prepare_to_store,       /* to_prepare_to_store */
+  nrom_xfer_inferior_memory,   /* to_xfer_memory */
+  nrom_files_info,             /* to_files_info */
+  NULL,                                /* to_insert_breakpoint */
+  NULL,                                /* to_remove_breakpoint */
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  nrom_kill,
+  nrom_load,
+  NULL,
+  nrom_create_inferior,                /* to_create_inferior */
+  nrom_mourn,
+  nrom_can_run,
+  0,                           /* to_notice_signals */
+  0,
+  process_stratum,             /* to_stratum */
+  NULL,                                /* to_next */
+  1,
+  1,
+  1,
+  1,
+  0,                           /* to_has_execution */
+  NULL,                                /* sections */
+  NULL,                                /* sections_end */
+  OPS_MAGIC                    /* to_magic */
+};
+
+void
+_initialize_remote_nrom ()
+{
+  add_target (&nrom_ops);
+
+  /* Add some commands for helpers.  */
+  add_cmd ("nrom_ipaddr", no_class, nrom_set_ipaddr,
+         "Set the IP Address of the NetROM\n",
+         &setlist);
+  add_cmd ("target_port", no_class, nrom_set_target_port,
+          "Set the Port to use for NetROM target communication\n",
+          &setlist);
+  add_cmd ("load_port", no_class, nrom_set_load_port,
+          "Set the Port to use for NetROM downloads\n",
+          &setlist);
+  add_cmd ("control_port", no_class, nrom_set_control_port,
+          "Set the Port to use for NetROM debugger services\n",
+          &setlist);
+  add_cmd ("nrom_filetype", no_class, nrom_set_filetype,
+          "Set the filetype to use on NetROM downloads",
+          &setlist);
+
+  add_cmd ("nrom", no_class, nrom_show_status,
+          "Show the current NetROM status\n",
+          &showlist);
+
+  add_cmd ("nrom", no_class, nrom_passthru,
+          "Pass arguments as command to NetROM",
+          &cmdlist);
+}