* gdbserver/{remote-gutils.c remote-server.c Makefile.in
authorStu Grossman <grossman@cygnus>
Wed, 26 May 1993 20:49:21 +0000 (20:49 +0000)
committerStu Grossman <grossman@cygnus>
Wed, 26 May 1993 20:49:21 +0000 (20:49 +0000)
configure.in remote-inflow.c remote-utils.c}:  New files to
support GDB remote server.  Currently only works for Lynx.

gdb/gdbserver/configure.in [new file with mode: 0644]
gdb/gdbserver/remote-gutils.c [new file with mode: 0644]
gdb/gdbserver/remote-inflow.c [new file with mode: 0644]
gdb/gdbserver/remote-server.c [new file with mode: 0644]
gdb/gdbserver/remote-utils.c [new file with mode: 0644]

diff --git a/gdb/gdbserver/configure.in b/gdb/gdbserver/configure.in
new file mode 100644 (file)
index 0000000..707f8a5
--- /dev/null
@@ -0,0 +1,331 @@
+srcname="Remote GDB server"
+srctrigger=remote-server.c
+gdb_serial_driver=../ser-unix.c
+
+# per-host:
+
+# per-target:
+
+# Hack alert!  We want this directory to be configured only for the target,
+# which is where it will be running, so we just eliminate the per-host section,
+# and make the per-target stuff setup host & host_cpu according to the target.
+
+host_cpu=$target_cpu
+host=$target
+
+# Map host cpu into the config cpu subdirectory name.
+# The default is $host_cpu.
+
+case "${host_cpu}" in
+
+c[12])                 gdb_host_cpu=convex ;;
+hppa*)                 gdb_host_cpu=pa ;;
+i[34]86)               gdb_host_cpu=i386 ;;
+m68*)                  gdb_host_cpu=m68k ;;
+np1)                   gdb_host_cpu=gould ;;
+pyramid)               gdb_host_cpu=pyr ;;
+*)                     gdb_host_cpu=$target_cpu ;;
+
+esac
+
+# map host info into gdb names.
+
+case "${host}" in
+
+a29k-*-*)              gdb_host=ultra3 ;;
+
+arm-*-*)               gdb_host=arm ;;
+
+c[12]-*-*)             gdb_host=convex ;;
+
+hppa*-hp-bsd*)         gdb_host=hppabsd ;;
+hppa*-hp-hpux*)                gdb_host=hppahpux ;;
+
+i[34]86-ncr-*)         gdb_host=ncr3000 ;;
+i[34]86-sequent-*)     gdb_host=symmetry ;;
+
+i[34]86-*-bsd*)                gdb_host=i386bsd ;;
+i[34]86-*-lynx*)       gdb_host=i386lynx ;;
+i[34]86-*-go32)                gdb_host=go32
+                       gdb_serial_driver=ser-go32.c
+                       ;;
+i[34]86-*-linux)       gdb_host=linux ;;
+i[34]86-*-mach)                gdb_host=i386mach ;;
+i[34]86-*-sco3.2v4*)   gdb_host=i386sco4 ;;
+i[34]86-*-sco*)                gdb_host=i386sco ;;
+i[34]86-*-solaris*)    gdb_host=i386sol2 ;;
+i[34]86-*-sunos*)      gdb_host=sun386 ;;
+i[34]86-*-sysv3.2)     gdb_host=i386v32 ;;
+i[34]86-*-sysv4*)      gdb_host=i386v4 ;;
+i[34]86-*-sysv*)       gdb_host=i386v ;;
+
+m680[01]0-sun-sunos3*) gdb_host=sun2os3 ;;
+m680[01]0-sun-sunos4*) gdb_host=sun2os4 ;;
+m68030-sony-*)         gdb_host=news1000 ;;
+
+m68*-altos-*)          gdb_host=altos ;;
+m68*-apollo*-sysv*)    gdb_host=apollo68v ;;
+m68*-apollo*-bsd*)     gdb_host=apollo68b ;;
+m68*-att-*)            gdb_host=3b1 ;;
+m68*-cbm-sysv4*)       gdb_host=amix ;;
+m68*-hp-bsd*)          gdb_host=hp300bsd ;;
+m68*-hp-hpux*)         gdb_host=hp300hpux ;;
+m68*-isi-*)            gdb_host=isi ;;
+m68*-sony-*)           gdb_host=news ;;
+m68*-sun-sunos3*)      gdb_host=sun3os3 ;;
+m68*-sun-sunos4*)      gdb_host=sun3os4 ;;
+m68*-sun-*)            gdb_host=sun3os4 ;;
+
+m88k-motorola-*)       gdb_host=delta88 ;;
+m88k-*-*)              gdb_host=m88k ;;
+
+mips-dec-*)            gdb_host=decstation ;;
+mips-little-*)         gdb_host=littlemips ;;
+mips-sgi-irix3)                gdb_host=irix3 ;;
+mips-sgi-irix4*)       gdb_host=irix4 ;;
+mips-sony-*)           gdb_host=bigmips ;;
+
+none-*-*)              gdb_host=none ;;
+
+np1-*-*)               gdb_host=np1 ;;
+
+ns32k-umax-*)          gdb_host=umax ;;
+ns32k-utek-sysv)       gdb_host=merlin ;;
+
+pn-*-*)                        gdb_host=pn ;;
+
+pyramid-*-*)           gdb_host=pyramid ;;
+
+romp-*-*)              gdb_host=rtbsd ;;
+
+rs6000-*-*)            gdb_host=rs6000 ;;
+
+sparc-*-solaris2*)     gdb_host=sun4sol2 ;;
+sparc-*-sunos4*)       gdb_host=sun4os4 ;;
+sparc-*-*)             gdb_host=sun4os4 ;;
+
+tahoe-*-*)             gdb_host=tahoe ;;
+
+vax-*-bsd*)            gdb_host=vaxbsd ;;
+vax-*-ultrix2*)                gdb_host=vaxult2 ;;
+vax-*-ultrix*)         gdb_host=vaxult ;;
+
+esac
+
+if [ ! -f ${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh ]; then
+       echo '***' "GDB remote does not support host ${host}" 1>&2
+       exit 1
+fi
+
+#  We really shouldn't depend on there being a space after XM_FILE= ...
+hostfile=`awk '$1 == "XM_FILE=" { print $2 }' <${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh`
+
+# per-target:
+
+# Map target cpu into the config cpu subdirectory name.
+# The default is $target_cpu.
+
+case "${target_cpu}" in
+
+c[12])                 gdb_target_cpu=convex ;;
+hppa*)                 gdb_target_cpu=pa ;;
+i[34]86)               gdb_target_cpu=i386 ;;
+m68*)                  gdb_target_cpu=m68k ;;
+np1)                   gdb_target_cpu=gould ;;
+pn)                    gdb_target_cpu=gould ;;
+pyramid)               gdb_target_cpu=pyr ;;
+sparc*)                        gdb_target_cpu=sparc ;;
+*)                     gdb_target_cpu=$target_cpu ;;
+
+esac
+
+# map target info into gdb names.
+
+case "${target}" in
+
+a29k-*-aout)           gdb_target=a29k ;;
+a29k-*-coff)           gdb_target=a29k ;;
+a29k-*-elf)            gdb_target=a29k ;;
+a29k-*-ebmon)          gdb_target=a29k ;;
+a29k-*-kern)           gdb_target=a29k-kern ;;
+a29k-*-none)           gdb_target=a29k ;;
+a29k-*-sym1)           gdb_target=ultra3 ;;
+a29k-*-udi)            gdb_target=a29k-udi ;;
+
+arm-*-*)               gdb_target=arm ;;
+
+c1-*-*)                        gdb_target=convex ;;
+c2-*-*)                        gdb_target=convex ;;
+
+h8300-*-*)             gdb_target=h8300hms ;;
+h8500-*-*)             gdb_target=h8500hms ;;
+
+sh-*-*)                        gdb_target=sh ;;
+
+hppa*-*-bsd*)          gdb_target=hppabsd ;;
+hppa*-*-hpux*)         gdb_target=hppahpux ;;
+
+i[34]86-sequent-*)     gdb_target=symmetry ;;
+i[34]86-ncr-*)         gdb_target=ncr3000 ;;
+
+i[34]86-*-aout)                gdb_target=i386aout ;;
+i[34]86-*-coff)                gdb_target=i386v ;;
+i[34]86-*-elf)         gdb_target=i386v ;;
+
+i[34]86-*-bsd*)                gdb_target=i386bsd ;;
+i[34]86-*-lynx*)       gdb_target=i386lynx ;;
+i[34]86-*-go32)                gdb_target=i386aout ;;
+i[34]86-*-solaris*)    gdb_target=i386sol2 ;;
+i[34]86-*-sunos*)      gdb_target=sun386 ;;
+i[34]86-*-sysv4*)      gdb_target=i386v4 ;;
+i[34]86-*-sco*)                gdb_target=i386v ;;
+i[34]86-*-sysv*)       gdb_target=i386v ;;
+i[34]86-*-linux)       gdb_target=linux ;;
+
+i960-*-bout)           gdb_target=vxworks960 ;;
+i960-*-coff)           gdb_target=nindy960 ;;
+i960-*-elf)            gdb_target=nindy960 ;;
+
+i960-*-nindy)          gdb_target=nindy960 ;;
+i960-*-vxworks)                gdb_target=vxworks960 ;;
+
+m68000-*-aout)         gdb_target=m68k-nofp ;;
+m68000-*-coff)         gdb_target=m68k-nofp ;;
+m68000-*-elf)          gdb_target=m68k-nofp ;;
+m68000-*-sunos3*)      gdb_target=sun2os3 ;;
+m68000-*-sunos4*)      gdb_target=sun2os4 ;;
+
+m68*-cbm-sysv4*)       gdb_target=amix ;;
+m68*-hp-bsd*)          gdb_target=hp300bsd ;;
+m68*-hp-hpux*)         gdb_target=hp300hpux ;;
+
+m68*-altos-*)          gdb_target=altos ;;
+m68*-att-*)            gdb_target=3b1 ;;
+m68*-ericsson-*)       gdb_target=es1800 ;;
+m68*-isi-*)            gdb_target=isi ;;
+m68*-netx-*)           gdb_target=vxworks68 ;;
+m68*-sony-*)           gdb_target=news ;;
+m68*-tandem-*)         gdb_target=st2000 ;;
+
+m68*-*-aout)           gdb_target=m68k-fp ;;
+m68*-*-coff)           gdb_target=m68k-fp ;;
+m68*-*-elf)            gdb_target=m68k-fp ;;
+m68*-*-os68k)          gdb_target=os68k ;;
+m68*-*-sunos3*)                gdb_target=sun3os3 ;;
+m68*-*-sunos4*)                gdb_target=sun3os4 ;;
+m68*-*-vxworks*)       gdb_target=vxworks68 ;;
+
+m88k-motorola-*)       gdb_target=delta88 ;;
+m88k-*-*)              gdb_target=m88k ;;
+
+mips-big-*)            gdb_target=bigmips ;;
+mips-dec-*)            gdb_target=decstation ;;
+mips-idt-ecoff)                gdb_target=idt ;;
+mips-little-*)         gdb_target=littlemips ;;
+mips-sgi-*)            gdb_target=irix3 ;;
+mips-sony-*)           gdb_target=bigmips ;;
+
+none-*-*)              gdb_target=none ;;
+
+np1-*-*)               gdb_target=np1 ;;
+
+ns32k-utek-sysv)       gdb_target=merlin ;;
+ns32k-utek-*)          gdb_target=umax ;;
+
+pn-*-*)                        gdb_target=pn ;;
+
+pyramid-*-*)           gdb_target=pyramid ;;
+
+rs6000-*-*)            gdb_target=rs6000 ;;
+
+sparc-*-aout)          gdb_target=sparc-em ;;
+sparc-*-coff)          gdb_target=sparc-em ;;
+sparc-*-elf)           gdb_target=sparc-em ;;
+sparc-*-solaris2*)     gdb_target=sun4sol2 ;;
+sparc-*-sunos4*)       gdb_target=sun4os4 ;;
+sparc-*-vxworks*)      gdb_target=sparc-em ;;
+sparc-*-*)             gdb_target=sun4os4 ;;
+sparclite*-*-*)                gdb_target=sparclite ;;
+
+tahoe-*-*)             gdb_target=tahoe ;;
+vax-*-*)               gdb_target=vax ;;
+
+z8k-*-sim)             gdb_target=z8ksim ;;
+esac
+
+if [ ! -f ${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt ]; then
+       echo '***' "GDB remote does not support target ${target}" 1>&2
+       exit 1
+fi
+
+if [ -z "${removing}" ] ; then
+       cat ${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh ${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt | awk '$1 == "#msg" {
+               print substr($0,6)}'
+fi
+
+#  We really shouldn't depend on there being a space after TM_FILE= ...
+targetfile=`awk '$1 == "TM_FILE=" { print $2 }' <${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt`
+
+if [ "${target}" = "${host}" ] ; then
+       nativefile=`awk '$1 == "NAT_FILE=" { print $2 }' <${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh`
+fi
+
+host_makefile_frag=../config/${gdb_host_cpu}/${gdb_host}.mh
+target_makefile_frag=../config/${gdb_target_cpu}/${gdb_target}.mt
+
+# If hostfile (XM_FILE) and/or targetfile (TM_FILE) and/or nativefile
+# (NAT_FILE) is not set in the ?config/* file, we don't make the
+# corresponding links.  But we have to remove the xm.h files and tm.h
+# files anyway, e.g. when switching from "configure host" to
+# "configure none".
+
+files=
+links=
+rm -f xm.h
+rm -f ser-hardwire.c
+if [ "${hostfile}" != "" ]; then
+       if [ -f ${srcdir}/../config/${hostfile} ]; then
+               files="${files} ../config/${hostfile}"
+       else
+               files="${files} ../config/${gdb_host_cpu}/${hostfile}"
+       fi
+       links="${links} xm.h"
+
+#      files="${files} ${gdb_serial_driver}"
+#      links="${links} ser-hardwire.c"
+fi
+rm -f tm.h
+if [ "${targetfile}" != "" ]; then
+       if [ -f ${srcdir}/../config/${targetfile} ]; then
+               files="${files} ../config/${targetfile}"
+       else
+               files="${files} ../config/${gdb_target_cpu}/${targetfile}"
+       fi
+       links="${links} tm.h"
+fi
+rm -f nm.h
+if [ "${nativefile}" != "" ]; then
+       if [ -f ${srcdir}/../config/${nativefile} ]; then
+               files="${files} ../config/${nativefile}"
+       else
+               files="${files} ../config/${gdb_host_cpu}/${nativefile}"
+       fi
+       links="${links} nm.h"
+# temporary scaffolding until all hosts have the host/target/native
+# split in place.
+else
+       files="${files} ../config/nm-trash.h"
+       links="${links} nm.h"
+fi
+
+if [ ${target_cpu} = "sparclite" ]; then
+       configdirs="${configdirs} sparclite"
+fi
+
+# post-target:
+
+if [ "${nativefile}" = "" ] ; then
+       sed -e '/^NATDEPFILES= /s//# NATDEPFILES= /' \
+               < Makefile > Makefile.tem
+       mv -f Makefile.tem Makefile
+fi
diff --git a/gdb/gdbserver/remote-gutils.c b/gdb/gdbserver/remote-gutils.c
new file mode 100644 (file)
index 0000000..9db9641
--- /dev/null
@@ -0,0 +1,412 @@
+/* General utility routines for the remote server for GDB.
+   Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc.
+
+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 <stdio.h>
+#include <sys/ioctl.h>
+#include "defs.h"
+#include <setjmp.h>
+
+void error ();
+void fatal ();
+
+/* Chain of cleanup actions established with make_cleanup,
+   to be executed if an error happens.  */
+
+static struct cleanup *cleanup_chain;
+
+/* Nonzero means a quit has been requested.  */
+
+int quit_flag;
+
+/* Nonzero means quit immediately if Control-C is typed now,
+   rather than waiting until QUIT is executed.  */
+
+int immediate_quit;
+\f
+/* Add a new cleanup to the cleanup_chain,
+   and return the previous chain pointer
+   to be passed later to do_cleanups or discard_cleanups.
+   Args are FUNCTION to clean up with, and ARG to pass to it.  */
+
+struct cleanup *
+make_cleanup (function, arg)
+     void (*function) ();
+     PTR arg;
+{
+  register struct cleanup *new
+    = (struct cleanup *) xmalloc (sizeof (struct cleanup));
+  register struct cleanup *old_chain = cleanup_chain;
+
+  new->next = cleanup_chain;
+  new->function = function;
+  new->arg = arg;
+  cleanup_chain = new;
+
+  return old_chain;
+}
+
+/* Discard cleanups and do the actions they describe
+   until we get back to the point OLD_CHAIN in the cleanup_chain.  */
+
+void
+do_cleanups (old_chain)
+     register struct cleanup *old_chain;
+{
+  register struct cleanup *ptr;
+  while ((ptr = cleanup_chain) != old_chain)
+    {
+      (*ptr->function) (ptr->arg);
+      cleanup_chain = ptr->next;
+      free (ptr);
+    }
+}
+
+/* Discard cleanups, not doing the actions they describe,
+   until we get back to the point OLD_CHAIN in the cleanup_chain.  */
+
+void
+discard_cleanups (old_chain)
+     register struct cleanup *old_chain;
+{
+  register struct cleanup *ptr;
+  while ((ptr = cleanup_chain) != old_chain)
+    {
+      cleanup_chain = ptr->next;
+      free (ptr);
+    }
+}
+
+/* This function is useful for cleanups.
+   Do
+
+     foo = xmalloc (...);
+     old_chain = make_cleanup (free_current_contents, &foo);
+
+   to arrange to free the object thus allocated.  */
+
+void
+free_current_contents (location)
+     char **location;
+{
+  free (*location);
+}
+\f
+/* Generally useful subroutines used throughout the program.  */
+
+/* Like malloc but get error if no storage available.  */
+
+PTR
+xmalloc (size)
+     long size;
+{
+  register char *val = (char *) malloc (size);
+  if (!val)
+    fatal ("virtual memory exhausted.", 0);
+  return val;
+}
+
+/* Like realloc but get error if no storage available.  */
+
+PTR
+xrealloc (ptr, size)
+     PTR ptr;
+     long size;
+{
+  register char *val = (char *) realloc (ptr, size);
+  if (!val)
+    fatal ("virtual memory exhausted.", 0);
+  return val;
+}
+
+/* Print the system error message for errno, and also mention STRING
+   as the file name for which the error was encountered.
+   Then return to command level.  */
+
+void
+perror_with_name (string)
+     char *string;
+{
+  extern int sys_nerr;
+  extern char *sys_errlist[];
+  extern int errno;
+  char *err;
+  char *combined;
+
+  if (errno < sys_nerr)
+    err = sys_errlist[errno];
+  else
+    err = "unknown error";
+
+  combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+  strcpy (combined, string);
+  strcat (combined, ": ");
+  strcat (combined, err);
+
+  error ("%s.", combined);
+}
+
+/* Print the system error message for ERRCODE, and also mention STRING
+   as the file name for which the error was encountered.  */
+
+void
+print_sys_errmsg (string, errcode)
+     char *string;
+     int errcode;
+{
+  extern int sys_nerr;
+  extern char *sys_errlist[];
+  char *err;
+  char *combined;
+
+  if (errcode < sys_nerr)
+    err = sys_errlist[errcode];
+  else
+    err = "unknown error";
+
+  combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+  strcpy (combined, string);
+  strcat (combined, ": ");
+  strcat (combined, err);
+
+  printf ("%s.\n", combined);
+}
+
+void
+quit ()
+{
+  fflush (stdout);
+  ioctl (fileno (stdout), TIOCFLUSH, 0);
+  error ("Quit");
+}
+
+/* Control C comes here */
+
+void
+request_quit (ignored)
+     int ignored;
+{
+  quit_flag = 1;
+  if (immediate_quit)
+    quit ();
+}
+
+/* Print an error message and return to command level.
+   STRING is the error message, used as a fprintf string,
+   and ARG is passed as an argument to it.  */
+
+NORETURN void
+error (string, arg1, arg2, arg3)
+     char *string;
+     int arg1, arg2, arg3;
+{
+  extern jmp_buf toplevel;
+
+  fflush (stdout);
+  fprintf (stderr, string, arg1, arg2, arg3);
+  fprintf (stderr, "\n");
+  longjmp(toplevel, 1);
+}
+
+/* Print an error message and exit reporting failure.
+   This is for a error that we cannot continue from.
+   STRING and ARG are passed to fprintf.  */
+
+void
+fatal (string, arg)
+     char *string;
+     int arg;
+{
+  fprintf (stderr, "gdb: ");
+  fprintf (stderr, string, arg);
+  fprintf (stderr, "\n");
+  exit (1);
+}
+
+/* Make a copy of the string at PTR with SIZE characters
+   (and add a null character at the end in the copy).
+   Uses malloc to get the space.  Returns the address of the copy.  */
+
+char *
+savestring (ptr, size)
+     const char *ptr;
+     int size;
+{
+  register char *p = (char *) xmalloc (size + 1);
+  bcopy (ptr, p, size);
+  p[size] = 0;
+  return p;
+}
+
+void
+print_spaces (n, file)
+     register int n;
+     register FILE *file;
+{
+  while (n-- > 0)
+    fputc (' ', file);
+}
+
+/* Ask user a y-or-n question and return 1 iff answer is yes.
+   Takes three args which are given to printf to print the question.
+   The first, a control string, should end in "? ".
+   It should not say how to answer, because we do that.  */
+
+int
+query (ctlstr, arg1, arg2)
+     char *ctlstr;
+{
+  register int answer;
+
+  /* Automatically answer "yes" if input is not from a terminal.  */
+  /***********if (!input_from_terminal_p ())
+    return 1; *************************/
+
+  while (1)
+    {
+      printf (ctlstr, arg1, arg2);
+      printf ("(y or n) ");
+      fflush (stdout);
+      answer = fgetc (stdin);
+      clearerr (stdin);                /* in case of C-d */
+      if (answer != '\n')
+       while (fgetc (stdin) != '\n')
+         clearerr (stdin);
+      if (answer >= 'a')
+       answer -= 040;
+      if (answer == 'Y')
+       return 1;
+      if (answer == 'N')
+       return 0;
+      printf ("Please answer y or n.\n");
+    }
+}
+\f
+/* Parse a C escape sequence.  STRING_PTR points to a variable
+   containing a pointer to the string to parse.  That pointer
+   is updated past the characters we use.  The value of the
+   escape sequence is returned.
+
+   A negative value means the sequence \ newline was seen,
+   which is supposed to be equivalent to nothing at all.
+
+   If \ is followed by a null character, we return a negative
+   value and leave the string pointer pointing at the null character.
+
+   If \ is followed by 000, we return 0 and leave the string pointer
+   after the zeros.  A value of 0 does not mean end of string.  */
+
+int
+parse_escape (string_ptr)
+     char **string_ptr;
+{
+  register int c = *(*string_ptr)++;
+  switch (c)
+    {
+    case 'a':
+      return '\a';
+    case 'b':
+      return '\b';
+    case 'e':
+      return 033;
+    case 'f':
+      return '\f';
+    case 'n':
+      return '\n';
+    case 'r':
+      return '\r';
+    case 't':
+      return '\t';
+    case 'v':
+      return '\v';
+    case '\n':
+      return -2;
+    case 0:
+      (*string_ptr)--;
+      return 0;
+    case '^':
+      c = *(*string_ptr)++;
+      if (c == '\\')
+       c = parse_escape (string_ptr);
+      if (c == '?')
+       return 0177;
+      return (c & 0200) | (c & 037);
+
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+      {
+       register int i = c - '0';
+       register int count = 0;
+       while (++count < 3)
+         {
+           if ((c = *(*string_ptr)++) >= '0' && c <= '7')
+             {
+               i *= 8;
+               i += c - '0';
+             }
+           else
+             {
+               (*string_ptr)--;
+               break;
+             }
+         }
+       return i;
+      }
+    default:
+      return c;
+    }
+}
+\f
+void
+printchar (ch, stream)
+     unsigned char ch;
+     FILE *stream;
+{
+  register int c = ch;
+  if (c < 040 || c >= 0177)
+    {
+      if (c == '\n')
+       fprintf (stream, "\\n");
+      else if (c == '\b')
+       fprintf (stream, "\\b");
+      else if (c == '\t')
+       fprintf (stream, "\\t");
+      else if (c == '\f')
+       fprintf (stream, "\\f");
+      else if (c == '\r')
+       fprintf (stream, "\\r");
+      else if (c == 033)
+       fprintf (stream, "\\e");
+      else if (c == '\a')
+       fprintf (stream, "\\a");
+      else
+       fprintf (stream, "\\%03o", c);
+    }
+  else
+    {
+      if (c == '\\' || c == '"' || c == '\'')
+       fputc ('\\', stream);
+      fputc (c, stream);
+    }
+}
diff --git a/gdb/gdbserver/remote-inflow.c b/gdb/gdbserver/remote-inflow.c
new file mode 100644 (file)
index 0000000..f093d83
--- /dev/null
@@ -0,0 +1,366 @@
+/* Low level interface to ptrace, for the remote server for GDB.
+   Copyright (C) 1986, 1987, 1993 Free Software Foundation, Inc.
+
+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 "initialize.h"
+****************************/
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+/*#include <sys/user.h>*/
+#define LYNXOS
+#include <sys/mem.h>
+#include <sys/signal.h>
+#include <sys/file.h>
+#include <sys/kernel.h>
+#include <sys/itimer.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/proc.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sgtty.h>
+#include <fcntl.h>
+#include "/usr/include/wait.h"
+
+/***************Begin MY defs*********************/
+int quit_flag = 0;
+char registers[REGISTER_BYTES];
+
+/* Index within `registers' of the first byte of the space for
+   register N.  */
+
+
+char buf2[MAX_REGISTER_RAW_SIZE];
+/***************End MY defs*********************/
+
+#include <sys/ptrace.h>
+/*#include <machine/reg.h>*/
+
+extern char **environ;
+extern int errno;
+extern int inferior_pid;
+void error (), quit (), perror_with_name ();
+int query ();
+
+/* Start an inferior process and returns its pid.
+   ALLARGS is a vector of program-name and args.
+   ENV is the environment vector to pass.  */
+
+int
+create_inferior (allargs, env)
+     char **allargs;
+     char **env;
+{
+  int pid;
+  extern int sys_nerr;
+  extern char *sys_errlist[];
+  extern int errno;
+  char status;
+  char execbuf[1024];
+
+  /* exec is said to fail if the executable is open.  */
+  /****************close_exec_file ();*****************/
+
+  sprintf (execbuf, "exec %s", allargs);
+
+  pid = fork ();
+  if (pid < 0)
+    perror_with_name ("fork");
+
+  if (pid == 0)
+    {
+      /* Run inferior in a separate process group.  */
+      setpgrp (getpid (), getpid ());
+
+      errno = 0;
+      ptrace (PTRACE_TRACEME);
+
+      execle ("/bin/sh", "sh", "-c", execbuf, 0, env);
+
+      fprintf (stderr, "Cannot exec /bin/sh: %s.\n",
+              errno < sys_nerr ? sys_errlist[errno] : "unknown error");
+      fflush (stderr);
+      _exit (0177);
+    }
+
+  return pid;
+}
+
+/* Kill the inferior process.  Make us have no inferior.  */
+
+void
+kill_inferior ()
+{
+  if (inferior_pid == 0)
+    return;
+  ptrace (8, inferior_pid, 0, 0);
+  wait (0);
+  /*************inferior_died ();****VK**************/
+}
+
+/* Wait for process, returns status */
+
+unsigned char
+mywait (status)
+     char *status;
+{
+  int pid;
+  union wait w;
+
+  pid = wait (&w);
+  if (pid != PIDGET(inferior_pid))
+    perror_with_name ("wait");
+
+  inferior_pid = BUILDPID (inferior_pid, w.w_tid);
+
+  if (WIFEXITED (w))
+    {
+      fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
+      *status = 'E';
+      return ((unsigned char) WEXITSTATUS (w));
+    }
+  else if (!WIFSTOPPED (w))
+    {
+      fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
+      *status = 'T';
+      return ((unsigned char) WTERMSIG (w));
+    }
+
+  fetch_inferior_registers (0);
+
+  *status = 'S';
+  return ((unsigned char) WSTOPSIG (w));
+}
+
+/* Resume execution of the inferior process.
+   If STEP is nonzero, single-step it.
+   If SIGNAL is nonzero, give it that signal.  */
+
+void
+myresume (step, signal)
+     int step;
+     int signal;
+{
+  errno = 0;
+  ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal);
+  if (errno)
+    perror_with_name ("ptrace");
+}
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+
+static struct econtext *
+lynx_registers_addr()
+{
+  st_t *stblock;
+  int ecpoff = offsetof(st_t, ecp);
+  CORE_ADDR ecp;
+
+  errno = 0;
+  stblock = (st_t *) ptrace (PTRACE_THREADUSER, inferior_pid,
+                            (PTRACE_ARG3_TYPE)0, 0);
+  if (errno)
+    perror_with_name ("PTRACE_THREADUSER");
+
+  ecp = (CORE_ADDR) ptrace (PTRACE_PEEKTHREAD, inferior_pid,
+                           (PTRACE_ARG3_TYPE)ecpoff, 0);
+  ecp -= (CORE_ADDR)stblock;
+  if (errno)
+    perror_with_name ("lynx_registers_addr(PTRACE_PEEKTHREAD)");
+
+  return (struct econtext *)ecp;
+}
+
+static struct econtext *ecp;
+
+/* Mapping between GDB register #s and offsets into econtext.  Must be
+   consistent with REGISTER_NAMES macro in tm-i386v.h. */
+
+#define X(ENTRY)(offsetof(struct econtext, ENTRY) / 4)
+static int regmap[] = {
+  X(eax),
+  X(ecx),
+  X(edx),
+  X(ebx),
+  X(esp),
+  X(ebp),
+  X(esi),
+  X(edi),
+  X(eip),
+  X(flags),                    /* ps */
+  X(cs),
+  X(ss),
+  X(ds),
+  X(es),
+  X(ecode),                    /* Lynx doesn't give us either fs or gs, so */
+  X(fault)                     /* we just substitute these two in the hopes
+                                  that they are useful. */
+  };
+
+/* Fetch one or more registers from the inferior.  REGNO == -1 to get
+   them all.  We actually fetch more than requested, when convenient,
+   marking them as valid so we won't fetch them again.  */
+
+void
+fetch_inferior_registers (ignored)
+     int ignored;
+{
+  int regno;
+  unsigned long reg;
+  struct econtext *ecp;
+
+  ecp = lynx_registers_addr();
+
+  for (regno = 0; regno < NUM_REGS; regno++)
+    {
+      errno = 0;
+      reg = ptrace (PTRACE_PEEKTHREAD, inferior_pid,
+                   (PTRACE_ARG3_TYPE) (&ecp->fault + regmap[regno]), 0);
+      if (errno)
+       perror_with_name ("fetch_inferior_registers(PTRACE_PEEKTHREAD)");
+  
+      *(unsigned long *)&registers[REGISTER_BYTE (regno)] = reg;
+    }
+}
+
+/* Store our register values back into the inferior.
+   If REGNO is -1, do this for all registers.
+   Otherwise, REGNO specifies which register (so we can save time).  */
+
+void
+store_inferior_registers (ignored)
+     int ignored;
+{
+  int regno;
+  unsigned long reg;
+  struct econtext *ecp;
+
+  ecp = lynx_registers_addr();
+
+  for (regno = 0; regno < NUM_REGS; regno++)
+    {
+      reg = *(unsigned long *)&registers[REGISTER_BYTE (regno)];
+
+      errno = 0;
+      ptrace (PTRACE_POKEUSER, inferior_pid,
+             (PTRACE_ARG3_TYPE) (&ecp->fault + regmap[regno]), reg);
+      if (errno)
+       perror_with_name ("PTRACE_POKEUSER");
+    }
+}
+
+/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
+   in the NEW_SUN_PTRACE case.
+   It ought to be straightforward.  But it appears that writing did
+   not write the data that I specified.  I cannot understand where
+   it got the data that it actually did write.  */
+
+/* Copy LEN bytes from inferior's memory starting at MEMADDR
+   to debugger memory starting at MYADDR.  */
+
+read_inferior_memory (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  register int i;
+  /* Round starting address down to longword boundary.  */
+  register CORE_ADDR addr = memaddr & -sizeof (int);
+  /* Round ending address up; get number of longwords that makes.  */
+  register int count
+  = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+  /* Allocate buffer of that many longwords.  */
+  register int *buffer = (int *) alloca (count * sizeof (int));
+
+  /* Read all the longwords */
+  for (i = 0; i < count; i++, addr += sizeof (int))
+    {
+      buffer[i] = ptrace (1, inferior_pid, addr, 0);
+    }
+
+  /* Copy appropriate bytes out of the buffer.  */
+  bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+   to inferior's memory at MEMADDR.
+   On failure (cannot write the inferior)
+   returns the value of errno.  */
+
+int
+write_inferior_memory (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  register int i;
+  /* Round starting address down to longword boundary.  */
+  register CORE_ADDR addr = memaddr & -sizeof (int);
+  /* Round ending address up; get number of longwords that makes.  */
+  register int count
+  = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+  /* Allocate buffer of that many longwords.  */
+  register int *buffer = (int *) alloca (count * sizeof (int));
+  extern int errno;
+
+  /* Fill start and end extra bytes of buffer with existing memory data.  */
+
+  buffer[0] = ptrace (1, inferior_pid, addr, 0);
+
+  if (count > 1)
+    {
+      buffer[count - 1]
+       = ptrace (1, inferior_pid,
+                 addr + (count - 1) * sizeof (int), 0);
+    }
+
+  /* Copy data to be written over corresponding part of buffer */
+
+  bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+
+  /* Write the entire buffer.  */
+
+  for (i = 0; i < count; i++, addr += sizeof (int))
+    {
+      errno = 0;
+      ptrace (4, inferior_pid, addr, buffer[i]);
+      if (errno)
+       return errno;
+    }
+
+  return 0;
+}
+\f
+void
+initialize ()
+{
+  inferior_pid = 0;
+}
+
+int
+have_inferior_p ()
+{
+  return inferior_pid != 0;
+}
diff --git a/gdb/gdbserver/remote-server.c b/gdb/gdbserver/remote-server.c
new file mode 100644 (file)
index 0000000..6a53390
--- /dev/null
@@ -0,0 +1,151 @@
+/* Main code for remote server for GDB.
+   Copyright (C) 1989, 1993 Free Software Foundation, Inc.
+
+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 <setjmp.h>
+#include <signal.h>
+
+void read_inferior_memory ();
+unsigned char mywait ();
+void myresume();
+void initialize ();
+int create_inferior ();
+
+extern char registers[];
+int inferior_pid;
+extern char **environ;
+
+/* Descriptor for I/O to remote machine.  */
+int remote_desc;
+int kiodebug = 0;
+int remote_debugging;
+
+void remote_send ();
+void putpkt ();
+void getpkt ();
+void remote_open ();
+void write_ok ();
+void write_enn ();
+void convert_ascii_to_int ();
+void convert_int_to_ascii ();
+void prepare_resume_reply ();
+void decode_m_packet ();
+void decode_M_packet ();
+jmp_buf toplevel;
+
+main (argc, argv)
+     int argc;
+     char *argv[];
+{
+  char ch, status, own_buf[2000], mem_buf[2000];
+  int i = 0;
+  unsigned char signal;
+  unsigned int mem_addr, len;
+  char argvec[1024];
+
+  if (setjmp(toplevel))
+    {
+      fprintf(stderr, "Exiting\n");
+      exit(1);
+    }
+
+  if (argc < 3)
+    error("Usage: gdbserver tty prog [args ...]");
+
+  initialize ();
+  remote_open (argv[1], 0);
+
+  argvec[0] = '\000';
+  for (i = 2; i < argc; i++)
+    strcat(argvec, argv[i]);
+
+  inferior_pid = create_inferior (argvec, environ);
+  fprintf (stderr, "Process %s created; pid = %d\n", argv[1], inferior_pid);
+
+  signal = mywait (&status);   /* Wait till we are at 1st instr in shell */
+  if (status != 'S' || signal != SIGTRAP)
+    error ("Bad status from shell\n");
+  myresume (0, 0);             /* Start up the shell */
+  signal = mywait (&status);   /* Wait for program to start */
+
+  /* We are now stopped at the first instruction of the target process */
+
+  setjmp(toplevel);
+  do
+    {
+      getpkt (own_buf);
+      i = 0;
+      ch = own_buf[i++];
+      switch (ch)
+       {
+       case '?':
+         prepare_resume_reply (own_buf, status, signal);
+         break;
+       case 'g':
+         convert_int_to_ascii (registers, own_buf, REGISTER_BYTES);
+         break;
+       case 'G':
+         convert_ascii_to_int (&own_buf[1], registers, REGISTER_BYTES);
+         store_inferior_registers (-1);
+           write_ok (own_buf);
+         break;
+       case 'm':
+         decode_m_packet (&own_buf[1], &mem_addr, &len);
+         read_inferior_memory (mem_addr, mem_buf, len);
+         convert_int_to_ascii (mem_buf, own_buf, len);
+         break;
+       case 'M':
+         decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
+         if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
+           write_ok (own_buf);
+         else
+           write_enn (own_buf);
+         break;
+       case 'c':
+         myresume (0, 0);
+         signal = mywait (&status);
+         prepare_resume_reply (own_buf, status, signal);
+         break;
+       case 's':
+         myresume (1, 0);
+         signal = mywait (&status);
+         prepare_resume_reply (own_buf, status, signal);
+         break;
+       case 'k':
+         kill_inferior ();
+         sprintf (own_buf, "q");
+         putpkt (own_buf);
+         fprintf (stderr, "Obtained kill request...terminating\n");
+         close (remote_desc);
+         exit (0);
+       default:
+         printf ("\nUnknown option chosen by master\n");
+         write_enn (own_buf);
+         break;
+       }
+
+      putpkt (own_buf);
+    }
+  while (1);
+
+  close (remote_desc);
+  /** now get out of here**/
+  fprintf (stderr, "Finished reading data from serial link - Bye!\n");
+  exit (0);
+}
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
new file mode 100644 (file)
index 0000000..2781ac5
--- /dev/null
@@ -0,0 +1,339 @@
+/* Remote utility routines for the remote server for GDB.
+   Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc.
+
+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 <stdio.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <a.out.h>
+#include <sys/file.h>
+#include <sgtty.h>
+
+extern int remote_desc;
+extern int remote_debugging;
+extern int kiodebug;
+
+void remote_open ();
+void remote_send ();
+void putpkt ();
+void getpkt ();
+
+void write_ok ();
+void write_enn ();
+void convert_ascii_to_int ();
+void convert_int_to_ascii ();
+void prepare_resume_reply ();
+
+/* Open a connection to a remote debugger.
+   NAME is the filename used for communication.  */
+
+void
+remote_open (name, from_tty)
+     char *name;
+     int from_tty;
+{
+  struct sgttyb sg;
+
+  remote_debugging = 0;
+
+  remote_desc = open (name, O_RDWR);
+  if (remote_desc < 0)
+    perror_with_name ("Could not open remote device");
+
+  ioctl (remote_desc, TIOCGETP, &sg);
+  sg.sg_flags = RAW;
+  ioctl (remote_desc, TIOCSETP, &sg);
+
+  fprintf (stderr, "Remote debugging using %s\n", name);
+  remote_debugging = 1;
+}
+
+/* Convert hex digit A to a number.  */
+
+static int
+fromhex (a)
+     int a;
+{
+  if (a >= '0' && a <= '9')
+    return a - '0';
+  else if (a >= 'a' && a <= 'f')
+    return a - 'a' + 10;
+  else
+    error ("Reply contains invalid hex digit");
+}
+
+/* Convert number NIB to a hex digit.  */
+
+static int
+tohex (nib)
+     int nib;
+{
+  if (nib < 10)
+    return '0' + nib;
+  else
+    return 'a' + nib - 10;
+}
+
+/* Send the command in BUF to the remote machine,
+   and read the reply into BUF.
+   Report an error if we get an error reply.  */
+
+void
+remote_send (buf)
+     char *buf;
+{
+  putpkt (buf);
+  getpkt (buf);
+
+  if (buf[0] == 'E')
+    error ("Remote failure reply: E");
+}
+
+/* Send a packet to the remote machine, with error checking.
+   The data of the packet is in BUF.  */
+
+void
+putpkt (buf)
+     char *buf;
+{
+  int i;
+  unsigned char csum = 0;
+  char buf2[2000];
+  char buf3[1];
+  int cnt = strlen (buf);
+  char *p;
+
+  /* Copy the packet into buffer BUF2, encapsulating it
+     and giving it a checksum.  */
+
+  p = buf2;
+  *p++ = '$';
+
+  for (i = 0; i < cnt; i++)
+    {
+      csum += buf[i];
+      *p++ = buf[i];
+    }
+  *p++ = '#';
+  *p++ = tohex ((csum >> 4) & 0xf);
+  *p++ = tohex (csum & 0xf);
+
+  /* Send it over and over until we get a positive ack.  */
+
+  do
+    {
+      write (remote_desc, buf2, p - buf2);
+      read (remote_desc, buf3, 1);
+    }
+  while (buf3[0] != '+');
+}
+
+static int
+readchar ()
+{
+  char buf[1];
+  while (read (remote_desc, buf, 1) != 1);
+  return buf[0] & 0x7f;
+}
+
+/* Read a packet from the remote machine, with error checking,
+   and store it in BUF.  */
+
+void
+getpkt (buf)
+     char *buf;
+{
+  char *bp;
+  unsigned char csum, c, c1, c2;
+  extern kiodebug;
+
+  while (1)
+    {
+      csum = 0;
+      while ((c = readchar ()) != '$');
+
+      bp = buf;
+      while (1)
+       {
+         c = readchar ();
+         if (c == '#')
+           break;
+         *bp++ = c;
+         csum += c;
+       }
+      *bp = 0;
+
+      c1 = fromhex (readchar ());
+      c2 = fromhex (readchar ());
+      if (csum == (c1 << 4) + c2)
+       break;
+
+      fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
+              (c1 << 4) + c2, csum, buf);
+      write (remote_desc, "-", 1);
+    }
+
+  write (remote_desc, "+", 1);
+}
+
+void
+write_ok (buf)
+     char *buf;
+{
+  buf[0] = 'O';
+  buf[1] = 'k';
+  buf[2] = '\0';
+}
+
+void
+write_enn (buf)
+     char *buf;
+{
+  buf[0] = 'E';
+  buf[1] = 'N';
+  buf[2] = 'N';
+  buf[3] = '\0';
+}
+
+void
+convert_int_to_ascii (from, to, n)
+     char *from, *to;
+     int n;
+{
+  int nib;
+  char ch;
+  while (n--)
+    {
+      ch = *from++;
+      nib = ((ch & 0xf0) >> 4) & 0x0f;
+      *to++ = tohex (nib);
+      nib = ch & 0x0f;
+      *to++ = tohex (nib);
+    }
+  *to++ = 0;
+}
+
+
+void
+convert_ascii_to_int (from, to, n)
+     char *from, *to;
+     int n;
+{
+  int nib1, nib2;
+  while (n--)
+    {
+      nib1 = fromhex (*from++);
+      nib2 = fromhex (*from++);
+      *to++ = (((nib1 & 0x0f) << 4) & 0xf0) | (nib2 & 0x0f);
+    }
+}
+
+static char *
+outreg(regno, buf)
+     int regno;
+     char *buf;
+{
+  extern char registers[];
+
+  *buf++ = tohex (regno >> 4);
+  *buf++ = tohex (regno & 0xf);
+  *buf++ = ':';
+  convert_int_to_ascii (&registers[REGISTER_BYTE (regno)], buf, 4);
+  buf += 8;
+  *buf++ = ';';
+
+  return buf;
+}
+
+void
+prepare_resume_reply (buf, status, signal)
+     char *buf, status;
+     unsigned char signal;
+{
+  int nib;
+  char ch;
+
+  *buf++ = 'T';
+
+  nib = ((signal & 0xf0) >> 4);
+  *buf++ = tohex (nib);
+  nib = signal & 0x0f;
+  *buf++ = tohex (nib);
+
+  buf = outreg (PC_REGNUM, buf);
+  buf = outreg (FP_REGNUM, buf);
+  buf = outreg (SP_REGNUM, buf);
+#ifdef NPC_REGNUM
+  buf = outreg (NPC_REGNUM, buf);
+#endif
+#ifdef O7_REGNUM
+  buf = outreg (O7_REGNUM, buf);
+#endif
+
+  *buf++ = 0;
+}
+
+void
+decode_m_packet (from, mem_addr_ptr, len_ptr)
+     char *from;
+     unsigned int *mem_addr_ptr, *len_ptr;
+{
+  int i = 0, j = 0;
+  char ch;
+  *mem_addr_ptr = *len_ptr = 0;
+
+  while ((ch = from[i++]) != ',')
+    {
+      *mem_addr_ptr = *mem_addr_ptr << 4;
+      *mem_addr_ptr |= fromhex (ch) & 0x0f;
+    }
+
+  for (j = 0; j < 4; j++)
+    {
+      if ((ch = from[i++]) == 0)
+       break;
+      *len_ptr = *len_ptr << 4;
+      *len_ptr |= fromhex (ch) & 0x0f;
+    }
+}
+
+void
+decode_M_packet (from, mem_addr_ptr, len_ptr, to)
+     char *from, *to;
+     unsigned int *mem_addr_ptr, *len_ptr;
+{
+  int i = 0, j = 0;
+  char ch;
+  *mem_addr_ptr = *len_ptr = 0;
+
+  while ((ch = from[i++]) != ',')
+    {
+      *mem_addr_ptr = *mem_addr_ptr << 4;
+      *mem_addr_ptr |= fromhex (ch) & 0x0f;
+    }
+
+  while ((ch = from[i++]) != ':')
+    {
+      *len_ptr = *len_ptr << 4;
+      *len_ptr |= fromhex (ch) & 0x0f;
+    }
+
+  convert_ascii_to_int (&from[i++], to, *len_ptr);
+}