summaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/Makefile.in241
-rw-r--r--gdb/gdbserver/README127
-rw-r--r--gdb/gdbserver/configure.in100
-rw-r--r--gdb/gdbserver/gdbreplay.c318
-rw-r--r--gdb/gdbserver/gdbserver.1103
-rw-r--r--gdb/gdbserver/low-hppabsd.c379
-rw-r--r--gdb/gdbserver/low-linux.c451
-rw-r--r--gdb/gdbserver/low-lynx.c746
-rw-r--r--gdb/gdbserver/low-sim.c289
-rw-r--r--gdb/gdbserver/low-sparc.c334
-rw-r--r--gdb/gdbserver/low-sun3.c313
-rw-r--r--gdb/gdbserver/remote-utils.c545
-rw-r--r--gdb/gdbserver/server.c258
-rw-r--r--gdb/gdbserver/server.h72
-rw-r--r--gdb/gdbserver/utils.c114
15 files changed, 4390 insertions, 0 deletions
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
new file mode 100644
index 00000000000..b016e134c5f
--- /dev/null
+++ b/gdb/gdbserver/Makefile.in
@@ -0,0 +1,241 @@
+#Copyright 1989, 90, 91, 92, 93, 94, 95, 96, 1997
+#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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+prefix = /usr/local
+
+program_transform_name =
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib
+tooldir = $(libdir)/$(target_alias)
+
+datadir = $(prefix)/share
+mandir = $(prefix)/man
+man1dir = $(mandir)/man1
+man2dir = $(mandir)/man2
+man3dir = $(mandir)/man3
+man4dir = $(mandir)/man4
+man5dir = $(mandir)/man5
+man6dir = $(mandir)/man6
+man7dir = $(mandir)/man7
+man8dir = $(mandir)/man8
+man9dir = $(mandir)/man9
+infodir = $(prefix)/info
+includedir = $(prefix)/include
+
+SHELL = /bin/sh
+
+INSTALL = `cd $(srcdir)/../..;pwd`/install-sh -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL)
+
+AR = ar
+AR_FLAGS = qv
+RANLIB = ranlib
+
+# If you are compiling with GCC, make sure that either 1) You use the
+# -traditional flag, or 2) You have the fixed include files where GCC
+# can reach them. Otherwise the ioctl calls in inflow.c
+# will be incorrectly compiled. The "fixincludes" script in the gcc
+# distribution will fix your include files up.
+#CC=cc
+#CC=gcc -traditional
+GCC=gcc
+
+# Directory containing source files. Don't clean up the spacing,
+# this exact string is matched for by the "configure" script.
+srcdir = .
+
+# It is also possible that you will need to add -I/usr/include/sys to the
+# CFLAGS section if your system doesn't have fcntl.h in /usr/include (which
+# is where it should be according to Posix).
+
+# Set this up with gcc if you have gnu ld and the loader will print out
+# line numbers for undefinded refs.
+#CC-LD=gcc -static
+CC-LD=${CC}
+
+# Where is the "include" directory? Traditionally ../include or ./include
+INCLUDE_DIR = ${srcdir}/../../include
+INCLUDE_DEP = $$(INCLUDE_DIR)
+
+# Where are the BFD library?
+BFD_DIR = ../../bfd
+BFD = $(BFD_DIR)/libbfd.a
+BFD_SRC = $(srcdir)/$(BFD_DIR)
+BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC)
+
+# Where is the source dir for the READLINE library? Traditionally in .. or .
+# (For the binary library built from it, we use ${READLINE_DIR}${subdir}.)
+READLINE_DIR = ${srcdir}/../readline
+READLINE_DEP = $$(READLINE_DIR)
+
+# All the includes used for CFLAGS and for lint.
+# -I. for config files.
+# -I${srcdir} possibly for regex.h also.
+# -I${srcdir}/config for more generic config files.
+INCLUDE_CFLAGS = -I. -I${srcdir} -I${srcdir}/.. -I${srcdir}/../config -I$(INCLUDE_DIR)
+
+# M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS
+# from the config/ directory.
+GLOBAL_CFLAGS = ${MT_CFLAGS} ${MH_CFLAGS}
+#PROFILE_CFLAGS = -pg
+
+# CFLAGS is specifically reserved for setting from the command line
+# when running make. I.E. "make CFLAGS=-Wmissing-prototypes".
+CFLAGS = -g
+# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros.
+INTERNAL_CFLAGS = ${CFLAGS} ${GLOBAL_CFLAGS} ${PROFILE_CFLAGS} \
+ ${BFD_CFLAGS} ${INCLUDE_CFLAGS}
+
+# LDFLAGS is specifically reserved for setting from the command line
+# when running make.
+
+# Perhaps should come from parent Makefile
+VERSION = gdbserver-4.12.3
+DIST=gdb
+
+LINT=/usr/5bin/lint
+LINTFLAGS= $(BFD_CFLAGS)
+
+# Host and target-dependent makefile fragments come in here.
+####
+# End of host and target-dependent makefile fragments
+
+# All source files that go into linking GDB remote server.
+
+SFILES = $(srcdir)/low-lynx.c $(srcdir)/low-sparc.c $(srcdir)/low-sun3.c \
+ $(srcdir)/low-hppabsd.c \
+ $(srcdir)/utils.c $(srcdir)/server.c $(srcdir)/remote-utils.c
+
+DEPFILES = $(GDBSERVER_DEPFILES)
+
+SOURCES = $(SFILES) $(ALLDEPFILES)
+TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS}
+
+OBS = utils.o $(GDBSERVER_DEPFILES) server.o remote-utils.o
+
+# Prevent Sun make from putting in the machine type. Setting
+# TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1.
+.c.o:
+ ${CC} -c ${INTERNAL_CFLAGS} $<
+
+all: gdbserver gdbreplay
+
+# Traditionally "install" depends on "all". But it may be useful
+# not to; for example, if the user has made some trivial change to a
+# source file and doesn't care about rebuilding or just wants to save the
+# time it takes for make to check that all is up to date.
+# install-only is intended to address that need.
+install: all install-only
+install-only:
+ n=`echo gdbserver | sed '$(program_transform_name)'`; \
+ if [ x$$n = x ]; then n=gdbserver; else true; fi; \
+ $(INSTALL_PROGRAM) gdbserver $(bindir)/$$n; \
+ $(INSTALL_DATA) $(srcdir)/gdbserver.1 $(man1dir)/$$n.1
+
+uninstall: force
+ n=`echo gdbserver | sed '$(program_transform_name)'`; \
+ if [ x$$n = x ]; then n=gdbserver; else true; fi; \
+ rm -f $(bindir)/$$n $(man1dir)/$$n.1
+
+installcheck:
+check:
+info dvi:
+install-info:
+clean-info:
+
+gdbserver: $(OBS) ${ADD_DEPS} ${CDEPS}
+ rm -f gdbserver
+ ${CC-LD} $(GLOBAL_CFLAGS) $(LDFLAGS) -o gdbserver $(OBS) \
+ $(GDBSERVER_LIBS) $(XM_CLIBS)
+
+gdbreplay: gdbreplay.o
+ rm -f gdbreplay
+ ${CC-LD} $(GLOBAL_CFLAGS) $(LDFLAGS) -o gdbreplay gdbreplay.o \
+ $(XM_CLIBS)
+
+config.status:
+ @echo "You must configure gdbserver. Look at the README file for details."
+ @false
+
+# Put the proper machine-specific files first, so M-. on a machine
+# specific routine gets the one for the correct machine.
+# The xyzzy stuff below deals with empty DEPFILES
+TAGS: ${TAGFILES}
+ etags `find ${srcdir}/../config -name $(TM_FILE) -print` \
+ `find ${srcdir}/../config -name ${XM_FILE} -print` \
+ `find ${srcdir}/../config -name ${NAT_FILE} -print` \
+ `for i in yzzy ${DEPFILES}; do \
+ if [ x$$i != xyzzy ]; then \
+ echo ${srcdir}/$$i | sed -e 's/\.o$$/\.c/' ; \
+ fi; \
+ done` \
+ ${TAGFILES}
+tags: TAGS
+
+clean:
+ rm -f *.o ${ADD_FILES} *~
+ rm -f gdbserver core make.log
+
+distclean: clean
+ rm -f nm.h tm.h xm.h config.status
+ rm -f Makefile
+
+maintainer-clean realclean: clean
+ rm -f nm.h tm.h xm.h config.status
+ rm -f Makefile
+
+STAGESTUFF=${OBS} ${TSOBS} ${NTSOBS} ${ADD_FILES} init.c init.o version.c gdb
+
+Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag)
+ $(SHELL) ./config.status
+
+force:
+
+version.c: Makefile
+ echo 'char *version = "$(VERSION)";' >version.c
+
+# GNU Make has an annoying habit of putting *all* the Makefile variables
+# into the environment, unless you include this target as a circumvention.
+# Rumor is that this will be fixed (and this target can be removed)
+# in GNU Make 4.0.
+.NOEXPORT:
+
+# GNU Make 3.63 has a different problem: it keeps tacking command line
+# overrides onto the definition of $(MAKE). This variable setting
+# will remove them.
+MAKEOVERRIDES=
+
+## This is ugly, but I don't want GNU make to put these variables in
+## the environment. Older makes will see this as a set of targets
+## with no dependencies and no actions.
+unexport CHILLFLAGS CHILL_LIB CHILL_FOR_TARGET :
+
+server.o : ${srcdir}/server.c ${srcdir}/server.h
+remote-utils.o : ${srcdir}/remote-utils.c ${srcdir}/server.h
+low-linux.o : ${srcdir}/low-linux.c ${srcdir}/server.h
+low-lynx.o : ${srcdir}/low-lynx.c ${srcdir}/server.h
+low-sim.o : ${srcdir}/low-sim.c ${srcdir}/server.h
+low-sparc.o : $(srcdir)/low-sparc.c $(srcdir)/server.h
+low-sun3.o : $(srcdir)/low-sun3.c $(srcdir)/server.h
+low-hppabsd.o : $(srcdir)/low-hppabsd.c $(srcdir)/server.h
+utils.o : ${srcdir}/utils.c ${srcdir}/server.h
+
+# This is the end of "Makefile.in".
diff --git a/gdb/gdbserver/README b/gdb/gdbserver/README
new file mode 100644
index 00000000000..2281bf686c1
--- /dev/null
+++ b/gdb/gdbserver/README
@@ -0,0 +1,127 @@
+ README for GDBserver & GDBreplay
+ by Stu Grossman and Fred Fish
+
+Introduction:
+
+This is GDBserver, a remote server for Un*x-like systems. It can be used to
+control the execution of a program on a target system from a GDB on a different
+host. GDB and GDBserver communicate using the standard remote serial protocol
+implemented in remote.c, and various *-stub.c files. They communicate via
+either a serial line or a TCP connection.
+
+Usage (server (target) side):
+
+First, you need to have a copy of the program you want to debug put onto
+the target system. The program can be stripped to save space if needed, as
+GDBserver doesn't care about symbols. All symbol handling is taken care of by
+the GDB running on the host system.
+
+To use the server, you log on to the target system, and run the `gdbserver'
+program. You must tell it (a) how to communicate with GDB, (b) the name of
+your program, and (c) its arguments. The general syntax is:
+
+ target> gdbserver COMM PROGRAM [ARGS ...]
+
+For example, using a serial port, you might say:
+
+ target> gdbserver /dev/com1 emacs foo.txt
+
+This tells gdbserver to debug emacs with an argument of foo.txt, and to
+communicate with GDB via /dev/com1. Gdbserver now waits patiently for the
+host GDB to communicate with it.
+
+To use a TCP connection, you could say:
+
+ target> gdbserver host:2345 emacs foo.txt
+
+This says pretty much the same thing as the last example, except that we are
+going to communicate with the host GDB via TCP. The `host:2345' argument means
+that we are expecting to see a TCP connection from `host' to local TCP port
+2345. (Currently, the `host' part is ignored.) You can choose any number you
+want for the port number as long as it does not conflict with any existing TCP
+ports on the target system. This same port number must be used in the host
+GDBs `target remote' command, which will be described shortly. Note that if
+you chose a port number that conflicts with another service, gdbserver will
+print an error message and exit.
+
+Usage (host side):
+
+You need an unstripped copy of the target program on your host system, since
+GDB needs to examine it's symbol tables and such. Start up GDB as you normally
+would, with the target program as the first argument. (You may need to use the
+--baud option if the serial line is running at anything except 9600 baud.)
+Ie: `gdb TARGET-PROG', or `gdb --baud BAUD TARGET-PROG'. After that, the only
+new command you need to know about is `target remote'. It's argument is either
+a device name (usually a serial device, like `/dev/ttyb'), or a HOST:PORT
+descriptor. For example:
+
+ (gdb) target remote /dev/ttyb
+
+communicates with the server via serial line /dev/ttyb, and:
+
+ (gdb) target remote the-target:2345
+
+communicates via a TCP connection to port 2345 on host `the-target', where
+you previously started up gdbserver with the same port number. Note that for
+TCP connections, you must start up gdbserver prior to using the `target remote'
+command, otherwise you may get an error that looks something like
+`Connection refused'.
+
+Building:
+
+Configuring gdbserver you should specify the same machine for host and
+target (which are the machine that gdbserver is going to run on. This
+is not the same as the machine that gdb is going to run on; building
+gdbserver automatically as part of building a whole tree of tools does
+not currently work if cross-compilation is involved (we don't get the
+right CC in the Makefile, to start with)).
+
+gdbserver should work on sparc-sun-sunos4* or Lynx. The following
+instructions pertain to Lynx. To build the server for Lynx, make a
+new copy of the distribution onto a disk that is NFS shared with the
+Lynx system. Lets say that's in a directory called xyzzy. Then,
+follow these steps under the host system:
+
+ 1) cd xyzzy/gdb/gdbserver
+ 2) ../../configure i386-none-lynx
+
+When that completes, do the following on the Lynx system:
+
+ 3) cd xyzzy/gdb/gdbserver
+ 4) make CC=gcc
+
+It should build with only a minor complaint about NULL being redefined. That's
+a LynxOS problem, and can be ignored.
+
+It's also possible that you may have a cross-compiler to Lynx. In that case,
+you can skip the stuff about NFS. You would replace steps 3 & 4 with:
+
+ make CC=lynx-target-compiler...
+
+Using GDBreplay:
+
+A special hacked down version of gdbserver can be used to replay remote
+debug log files created by gdb. Before using the gdb "target" command to
+initiate a remote debug session, use "set remotelogfile <filename>" to tell
+gdb that you want to make a recording of the serial or tcp session. Note
+that when replaying the session, gdb communicates with gdbreplay via tcp,
+regardless of whether the original session was via a serial link or tcp.
+
+Once you are done with the remote debug session, start gdbreplay and
+tell it the name of the log file and the host and port number that gdb
+should connect to (typically the same as the host running gdb):
+
+ $ gdbreplay logfile host:port
+
+Then start gdb (preferably in a different screen or window) and use the
+"target" command to connect to gdbreplay:
+
+ (gdb) target remote host:port
+
+Repeat the same sequence of user commands to gdb that you gave in the
+original debug session. Gdb should not be able to tell that it is talking
+to gdbreplay rather than a real target, all other things being equal. Note
+that gdbreplay echos the command lines to stderr, as well as the contents of
+the packets it sends and receives. The last command echoed by gdbreplay is
+the next command that needs to be typed to gdb to continue the session in
+sync with the original session.
diff --git a/gdb/gdbserver/configure.in b/gdb/gdbserver/configure.in
new file mode 100644
index 00000000000..1bbb73c489d
--- /dev/null
+++ b/gdb/gdbserver/configure.in
@@ -0,0 +1,100 @@
+srcname="Remote GDB server"
+srctrigger=server.c
+gdb_serial_driver=../ser-unix.c
+
+# per-host:
+
+. ${srcdir}/../configure.host
+
+echo "gdbserver/configure.in: host is $host, target is $target"
+
+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:
+
+. ${srcdir}/../configure.tgt
+
+echo "gdbserver/configure.in: host_cpu is $host_cpu, target_cpu is $target_cpu"
+
+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-empty.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/gdbreplay.c b/gdb/gdbserver/gdbreplay.c
new file mode 100644
index 00000000000..ebe06bad8f2
--- /dev/null
+++ b/gdb/gdbserver/gdbreplay.c
@@ -0,0 +1,318 @@
+/* Replay a remote debug session logfile for GDB.
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+/* Sort of a hack... */
+#define EOL (EOF - 1)
+
+static int remote_desc;
+
+/* 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;
+
+ err = (errno < sys_nerr) ? sys_errlist[errno] : "unknown error";
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+ fprintf (stderr, "\n%s.\n", combined);
+ fflush (stderr);
+ exit (1);
+}
+
+static void
+sync_error (fp, desc, expect, got)
+ FILE *fp;
+ char *desc;
+ int expect;
+ int got;
+{
+ fprintf (stderr, "\n%s\n", desc);
+ fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
+ ftell (fp), expect, got);
+ fflush (stderr);
+ exit (1);
+}
+
+void
+remote_close()
+{
+ close (remote_desc);
+}
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+void
+remote_open (name)
+ char *name;
+{
+ extern char *strchr ();
+
+ if (!strchr (name, ':'))
+ {
+ fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
+ fflush (stderr);
+ exit (1);
+ }
+ else
+ {
+ char *port_str;
+ int port;
+ struct sockaddr_in sockaddr;
+ int tmp;
+ struct protoent *protoent;
+ int tmp_desc;
+
+ port_str = strchr (name, ':');
+
+ port = atoi (port_str + 1);
+
+ tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
+ if (tmp_desc < 0)
+ perror_with_name ("Can't open socket");
+
+ /* Allow rapid reuse of this port. */
+ tmp = 1;
+ setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp,
+ sizeof(tmp));
+
+ sockaddr.sin_family = PF_INET;
+ sockaddr.sin_port = htons(port);
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+
+ if (bind (tmp_desc, (struct sockaddr *)&sockaddr, sizeof (sockaddr))
+ || listen (tmp_desc, 1))
+ perror_with_name ("Can't bind address");
+
+ tmp = sizeof (sockaddr);
+ remote_desc = accept (tmp_desc, (struct sockaddr *)&sockaddr, &tmp);
+ if (remote_desc == -1)
+ perror_with_name ("Accept failed");
+
+ protoent = getprotobyname ("tcp");
+ if (!protoent)
+ perror_with_name ("getprotobyname");
+
+ /* Enable TCP keep alive process. */
+ tmp = 1;
+ setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
+
+ /* Tell TCP not to delay small packets. This greatly speeds up
+ interactive response. */
+ tmp = 1;
+ setsockopt (remote_desc, protoent->p_proto, TCP_NODELAY,
+ (char *)&tmp, sizeof(tmp));
+
+ close (tmp_desc); /* No longer need this */
+
+ signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply
+ exits when the remote side dies. */
+ }
+
+ fcntl (remote_desc, F_SETFL, FASYNC);
+
+ fprintf (stderr, "Replay logfile using %s\n", name);
+ fflush (stderr);
+}
+
+static int tohex (ch)
+ int ch;
+{
+ if (ch >= '0' && ch <= '9')
+ {
+ return (ch - '0');
+ }
+ if (ch >= 'A' && ch <= 'F')
+ {
+ return (ch - 'A' + 10);
+ }
+ if (ch >= 'a' && ch <= 'f')
+ {
+ return (ch - 'a' + 10);
+ }
+ fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
+ fflush (stderr);
+ exit (1);
+}
+
+static int
+logchar (fp)
+ FILE *fp;
+{
+ int ch;
+ int ch2;
+
+ ch = fgetc (fp);
+ fputc (ch, stdout);
+ fflush (stdout);
+ switch (ch)
+ {
+ case '\n':
+ ch = EOL;
+ break;
+ case '\\':
+ ch = fgetc (fp);
+ fputc (ch, stdout);
+ fflush (stdout);
+ switch (ch)
+ {
+ case '\\': break;
+ case 'b': ch = '\b'; break;
+ case 'f': ch = '\f'; break;
+ case 'n': ch = '\n'; break;
+ case 'r': ch = '\r'; break;
+ case 't': ch = '\t'; break;
+ case 'v': ch = '\v'; break;
+ case 'x':
+ ch2 = fgetc (fp);
+ fputc (ch2, stdout);
+ fflush (stdout);
+ ch = tohex (ch2) << 4;
+ ch2 = fgetc (fp);
+ fputc (ch2, stdout);
+ fflush (stdout);
+ ch |= tohex (ch2);
+ break;
+ default:
+ /* Treat any other char as just itself */
+ break;
+ }
+ default:
+ break;
+ }
+ return (ch);
+}
+
+/* Accept input from gdb and match with chars from fp (after skipping one
+ blank) up until a \n is read from fp (which is not matched) */
+
+void
+expect (fp)
+ FILE *fp;
+{
+ int fromlog;
+ unsigned char fromgdb;
+
+ if ((fromlog = logchar (fp)) != ' ')
+ {
+ sync_error (fp, "Sync error during gdb read of leading blank", ' ',
+ fromlog);
+ }
+ do
+ {
+ fromlog = logchar (fp);
+ if (fromlog == EOL)
+ {
+ break;
+ }
+ read (remote_desc, &fromgdb, 1);
+ } while (fromlog == fromgdb);
+ if (fromlog != EOL)
+ {
+ sync_error (fp, "Sync error during read of gdb packet", fromlog,
+ fromgdb);
+ }
+}
+
+/* Play data back to gdb from fp (after skipping leading blank) up until a
+ \n is read from fp (which is discarded and not sent to gdb). */
+
+void
+play (fp)
+ FILE *fp;
+{
+ int fromlog;
+ char ch;
+
+ if ((fromlog = logchar (fp)) != ' ')
+ {
+ sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
+ fromlog);
+ }
+ while ((fromlog = logchar (fp)) != EOL)
+ {
+ ch = fromlog;
+ write (remote_desc, &ch, 1);
+ }
+}
+
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ FILE *fp;
+ int ch;
+
+ if (argc < 3)
+ {
+ fprintf (stderr, "Usage: gdbreplay <logfile> <host:port>\n");
+ fflush (stderr);
+ exit (1);
+ }
+ fp = fopen (argv[1], "r");
+ if (fp == NULL)
+ {
+ perror_with_name (argv[1]);
+ }
+ remote_open (argv[2]);
+ while ((ch = logchar (fp)) != EOF)
+ {
+ switch (ch)
+ {
+ case 'w':
+ /* data sent from gdb to gdbreplay, accept and match it */
+ expect (fp);
+ break;
+ case 'r':
+ /* data sent from gdbreplay to gdb, play it */
+ play (fp);
+ break;
+ case 'c':
+ /* Command executed by gdb */
+ while ((ch = logchar (fp)) != EOL);
+ break;
+ }
+ }
+ remote_close ();
+ exit (0);
+}
+
diff --git a/gdb/gdbserver/gdbserver.1 b/gdb/gdbserver/gdbserver.1
new file mode 100644
index 00000000000..9d3fdcd8011
--- /dev/null
+++ b/gdb/gdbserver/gdbserver.1
@@ -0,0 +1,103 @@
+.\" Copyright (c) 1993 Free Software Foundation
+.\" See section COPYING for conditions for redistribution
+.TH gdbserver 1 "2 November 1993" "Cygnus Support" "GNU Development Tools"
+.SH NAME
+gdbserver \- Remote Server for the GNU Debugger
+.SH SYNOPSIS
+.na
+.TP
+.B gdbserver
+.RB tty
+.RB prog
+.RB "[\|" args... "\|]"
+.ad b
+.SH DESCRIPTION
+GDBSERVER is a program that allows you to run GDB on a different machine
+than the one which is running the program being debugged.
+
+Usage (server (target) side):
+
+First, you need to have a copy of the program you want to debug put onto
+the target system. The program can be stripped to save space if needed, as
+GDBserver doesn't care about symbols. All symbol handling is taken care of by
+the GDB running on the host system.
+
+To use the server, you log on to the target system, and run the `gdbserver'
+program. You must tell it (a) how to communicate with GDB, (b) the name of
+your program, and (c) its arguments. The general syntax is:
+
+ target> gdbserver COMM PROGRAM [ARGS ...]
+
+For example, using a serial port, you might say:
+
+ target> gdbserver /dev/com1 emacs foo.txt
+
+This tells gdbserver to debug emacs with an argument of foo.txt, and to
+communicate with GDB via /dev/com1. Gdbserver now waits patiently for the
+host GDB to communicate with it.
+
+To use a TCP connection, you could say:
+
+ target> gdbserver host:2345 emacs foo.txt
+
+This says pretty much the same thing as the last example, except that we are
+going to communicate with the host GDB via TCP. The `host:2345' argument means
+that we are expecting to see a TCP connection from `host' to local TCP port
+2345. (Currently, the `host' part is ignored.) You can choose any number you
+want for the port number as long as it does not conflict with any existing TCP
+ports on the target system. This same port number must be used in the host
+GDBs `target remote' command, which will be described shortly. Note that if
+you chose a port number that conflicts with another service, gdbserver will
+print an error message and exit.
+
+Usage (host side):
+
+You need an unstripped copy of the target program on your host system, since
+GDB needs to examine it's symbol tables and such. Start up GDB as you normally
+would, with the target program as the first argument. (You may need to use the
+--baud option if the serial line is running at anything except 9600 baud.)
+Ie: `gdb TARGET-PROG', or `gdb --baud BAUD TARGET-PROG'. After that, the only
+new command you need to know about is `target remote'. It's argument is either
+a device name (usually a serial device, like `/dev/ttyb'), or a HOST:PORT
+descriptor. For example:
+
+ (gdb) target remote /dev/ttyb
+
+communicates with the server via serial line /dev/ttyb, and:
+
+ (gdb) target remote the-target:2345
+
+communicates via a TCP connection to port 2345 on host `the-target', where
+you previously started up gdbserver with the same port number. Note that for
+TCP connections, you must start up gdbserver prior to using the `target remote'
+command, otherwise you may get an error that looks something like
+`Connection refused'.
+.SH OPTIONS
+You have to supply the name of the program to debug
+and the tty to communicate on; the remote GDB will do everything else.
+Any remaining arguments will be passed to the program verbatim.
+.SH "SEE ALSO"
+.RB "`\|" gdb "\|'"
+entry in
+.B info\c
+\&;
+.I
+Using GDB: A Guide to the GNU Source-Level Debugger\c
+, Richard M. Stallman and Roland H. Pesch, July 1991.
+.SH COPYING
+Copyright (c) 1993 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
diff --git a/gdb/gdbserver/low-hppabsd.c b/gdb/gdbserver/low-hppabsd.c
new file mode 100644
index 00000000000..c784d0c61ac
--- /dev/null
+++ b/gdb/gdbserver/low-hppabsd.c
@@ -0,0 +1,379 @@
+/* Low level interface to ptrace, for the remote server for GDB.
+ Copyright (C) 1995 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include <sys/wait.h>
+#include "frame.h"
+#include "inferior.h"
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/user.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sgtty.h>
+#include <fcntl.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 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 (program, allargs)
+ char *program;
+ char **allargs;
+{
+ int pid;
+
+ pid = fork ();
+ if (pid < 0)
+ perror_with_name ("fork");
+
+ if (pid == 0)
+ {
+ ptrace (PT_TRACE_ME, 0, 0, 0, 0);
+
+ execv (program, allargs);
+
+ fprintf (stderr, "Cannot exec %s: %s.\n", program,
+ 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, 0);
+ wait (0);
+ /*************inferior_died ();****VK**************/
+}
+
+/* Return nonzero if the given thread is still alive. */
+int
+mythread_alive (pid)
+ int pid;
+{
+ return 1;
+}
+
+/* Wait for process, returns status */
+
+unsigned char
+mywait (status)
+ char *status;
+{
+ int pid;
+ union wait w;
+
+ pid = wait (&w);
+ if (pid != inferior_pid)
+ perror_with_name ("wait");
+
+ if (WIFEXITED (w))
+ {
+ fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
+ *status = 'W';
+ return ((unsigned char) WEXITSTATUS (w));
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
+ *status = 'X';
+ return ((unsigned char) WTERMSIG (w));
+ }
+
+ fetch_inferior_registers (0);
+
+ *status = 'T';
+ 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 ? PT_STEP : PT_CONTINUE, inferior_pid, 1, signal, 0);
+ if (errno)
+ perror_with_name ("ptrace");
+}
+
+
+#if !defined (offsetof)
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+/* U_REGS_OFFSET is the offset of the registers within the u area. */
+#if !defined (U_REGS_OFFSET)
+#define U_REGS_OFFSET \
+ ptrace (PT_READ_U, inferior_pid, \
+ (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
+ - KERNEL_U_ADDR
+#endif
+
+CORE_ADDR
+register_addr (regno, blockend)
+ int regno;
+ CORE_ADDR blockend;
+{
+ CORE_ADDR addr;
+
+ if (regno < 0 || regno >= ARCH_NUM_REGS)
+ error ("Invalid register number %d.", regno);
+
+ REGISTER_U_ADDR (addr, blockend, regno);
+
+ return addr;
+}
+
+/* Fetch one register. */
+
+static void
+fetch_register (regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ register int i;
+
+ /* Offset of registers within the u area. */
+ unsigned int offset;
+
+ offset = U_REGS_OFFSET;
+
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ errno = 0;
+ *(int *) &registers[ regno * 4 + i] = ptrace (PT_RUREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) regaddr, 0, 0);
+ regaddr += sizeof (int);
+ if (errno != 0)
+ {
+ /* Warning, not error, in case we are attached; sometimes the
+ kernel doesn't let us at the registers. */
+ char *err = strerror (errno);
+ char *msg = alloca (strlen (err) + 128);
+ sprintf (msg, "reading register %d: %s", regno, err);
+ error (msg);
+ goto error_exit;
+ }
+ }
+ error_exit:;
+}
+
+/* Fetch all registers, or just one, from the child process. */
+
+void
+fetch_inferior_registers (regno)
+ int regno;
+{
+ if (regno == -1 || regno == 0)
+ for (regno = 0; regno < NUM_REGS; regno++)
+ fetch_register (regno);
+ else
+ fetch_register (regno);
+}
+
+/* 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 (regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ char buf[80];
+ extern char registers[];
+ register int i;
+ unsigned int offset = U_REGS_OFFSET;
+ int scratch;
+
+ if (regno >= 0)
+ {
+ if (CANNOT_STORE_REGISTER (regno))
+ return;
+ regaddr = register_addr (regno, offset);
+ errno = 0;
+ if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM)
+ {
+ scratch = *(int *) &registers[REGISTER_BYTE (regno)] | 0x3;
+ ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+ scratch, 0);
+ if (errno != 0)
+ {
+ /* Error, even if attached. Failing to write these two
+ registers is pretty serious. */
+ sprintf (buf, "writing register number %d", regno);
+ perror_with_name (buf);
+ }
+ }
+ else
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
+ {
+ errno = 0;
+ ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+ *(int *) &registers[REGISTER_BYTE (regno) + i], 0);
+ if (errno != 0)
+ {
+ /* Warning, not error, in case we are attached; sometimes the
+ kernel doesn't let us at the registers. */
+ char *err = strerror (errno);
+ char *msg = alloca (strlen (err) + 128);
+ sprintf (msg, "writing register %d: %s",
+ regno, err);
+ error (msg);
+ return;
+ }
+ regaddr += sizeof(int);
+ }
+ }
+ else
+ for (regno = 0; regno < NUM_REGS; regno++)
+ store_inferior_registers (regno);
+}
+
+/* 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, 0);
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), 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, 0);
+
+ if (count > 1)
+ {
+ buffer[count - 1]
+ = ptrace (1, inferior_pid,
+ addr + (count - 1) * sizeof (int), 0, 0);
+ }
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ ptrace (4, inferior_pid, addr, buffer[i], 0);
+ if (errno)
+ return errno;
+ }
+
+ return 0;
+}
+
+void
+initialize ()
+{
+ inferior_pid = 0;
+}
+
+int
+have_inferior_p ()
+{
+ return inferior_pid != 0;
+}
diff --git a/gdb/gdbserver/low-linux.c b/gdb/gdbserver/low-linux.c
new file mode 100644
index 00000000000..106021057a3
--- /dev/null
+++ b/gdb/gdbserver/low-linux.c
@@ -0,0 +1,451 @@
+/* Low level interface to ptrace, for the remote server for GDB.
+ Copyright (C) 1995, 1996 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include <sys/wait.h>
+#include "frame.h"
+#include "inferior.h"
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/user.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#if 0
+#include <sgtty.h>
+#endif
+#include <fcntl.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>
+
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
+#include <sys/reg.h>
+#endif
+
+extern char **environ;
+extern int errno;
+extern int inferior_pid;
+void 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 (program, allargs)
+ char *program;
+ char **allargs;
+{
+ int pid;
+
+ pid = fork ();
+ if (pid < 0)
+ perror_with_name ("fork");
+
+ if (pid == 0)
+ {
+ ptrace (PTRACE_TRACEME, 0, 0, 0);
+
+ execv (program, allargs);
+
+ fprintf (stderr, "Cannot exec %s: %s.\n", program,
+ 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 (PTRACE_KILL, inferior_pid, 0, 0);
+ wait (0);
+ /*************inferior_died ();****VK**************/
+}
+
+/* Return nonzero if the given thread is still alive. */
+int
+mythread_alive (pid)
+ int pid;
+{
+ return 1;
+}
+
+/* Wait for process, returns status */
+
+unsigned char
+mywait (status)
+ char *status;
+{
+ int pid;
+ union wait w;
+
+ pid = wait (&w);
+ if (pid != inferior_pid)
+ perror_with_name ("wait");
+
+ if (WIFEXITED (w))
+ {
+ fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
+ *status = 'W';
+ return ((unsigned char) WEXITSTATUS (w));
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
+ *status = 'X';
+ return ((unsigned char) WTERMSIG (w));
+ }
+
+ fetch_inferior_registers (0);
+
+ *status = 'T';
+ 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");
+}
+
+
+#if !defined (offsetof)
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+/* U_REGS_OFFSET is the offset of the registers within the u area. */
+#if !defined (U_REGS_OFFSET)
+#define U_REGS_OFFSET \
+ ptrace (PT_READ_U, inferior_pid, \
+ (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
+ - KERNEL_U_ADDR
+#endif
+
+#ifndef TARGET_M68K
+/* this table must line up with REGISTER_NAMES in tm-i386v.h */
+/* symbols like 'EAX' come from <sys/reg.h> */
+static int regmap[] =
+{
+ EAX, ECX, EDX, EBX,
+ UESP, EBP, ESI, EDI,
+ EIP, EFL, CS, SS,
+ DS, ES, FS, GS,
+};
+
+int
+i386_register_u_addr (blockend, regnum)
+ int blockend;
+ int regnum;
+{
+#if 0
+ /* this will be needed if fp registers are reinstated */
+ /* for now, you can look at them with 'info float'
+ * sys5 wont let you change them with ptrace anyway
+ */
+ if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM)
+ {
+ int ubase, fpstate;
+ struct user u;
+ ubase = blockend + 4 * (SS + 1) - KSTKSZ;
+ fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u);
+ return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
+ }
+ else
+#endif
+ return (blockend + 4 * regmap[regnum]);
+
+}
+#else /* TARGET_M68K */
+/* This table must line up with REGISTER_NAMES in tm-m68k.h */
+static int regmap[] =
+{
+#ifdef PT_D0
+ PT_D0, PT_D1, PT_D2, PT_D3, PT_D4, PT_D5, PT_D6, PT_D7,
+ PT_A0, PT_A1, PT_A2, PT_A3, PT_A4, PT_A5, PT_A6, PT_USP,
+ PT_SR, PT_PC,
+#else
+ 14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15,
+ 17, 18,
+#endif
+#ifdef PT_FP0
+ PT_FP0, PT_FP1, PT_FP2, PT_FP3, PT_FP4, PT_FP5, PT_FP6, PT_FP7,
+ PT_FPCR, PT_FPSR, PT_FPIAR
+#else
+ 21, 24, 27, 30, 33, 36, 39, 42, 45, 46, 47
+#endif
+};
+
+/* BLOCKEND is the value of u.u_ar0, and points to the place where GS
+ is stored. */
+
+int
+m68k_linux_register_u_addr (blockend, regnum)
+ int blockend;
+ int regnum;
+{
+ return (blockend + 4 * regmap[regnum]);
+}
+#endif
+
+CORE_ADDR
+register_addr (regno, blockend)
+ int regno;
+ CORE_ADDR blockend;
+{
+ CORE_ADDR addr;
+
+ if (regno < 0 || regno >= ARCH_NUM_REGS)
+ error ("Invalid register number %d.", regno);
+
+ REGISTER_U_ADDR (addr, blockend, regno);
+
+ return addr;
+}
+
+/* Fetch one register. */
+
+static void
+fetch_register (regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ register int i;
+
+ /* Offset of registers within the u area. */
+ unsigned int offset;
+
+ offset = U_REGS_OFFSET;
+
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ errno = 0;
+ *(int *) &registers[ regno * 4 + i] = ptrace (PTRACE_PEEKUSR, inferior_pid,
+ (PTRACE_ARG3_TYPE) regaddr, 0);
+ regaddr += sizeof (int);
+ if (errno != 0)
+ {
+ /* Warning, not error, in case we are attached; sometimes the
+ kernel doesn't let us at the registers. */
+ char *err = strerror (errno);
+ char *msg = alloca (strlen (err) + 128);
+ sprintf (msg, "reading register %d: %s", regno, err);
+ error (msg);
+ goto error_exit;
+ }
+ }
+ error_exit:;
+}
+
+/* Fetch all registers, or just one, from the child process. */
+
+void
+fetch_inferior_registers (regno)
+ int regno;
+{
+ if (regno == -1 || regno == 0)
+ for (regno = 0; regno < NUM_REGS-NUM_FREGS; regno++)
+ fetch_register (regno);
+ else
+ fetch_register (regno);
+}
+
+/* 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 (regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ register int i;
+ unsigned int offset = U_REGS_OFFSET;
+
+ if (regno >= 0)
+ {
+#if 0
+ if (CANNOT_STORE_REGISTER (regno))
+ return;
+#endif
+ regaddr = register_addr (regno, offset);
+ errno = 0;
+#if 0
+ if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM)
+ {
+ scratch = *(int *) &registers[REGISTER_BYTE (regno)] | 0x3;
+ ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+ scratch, 0);
+ if (errno != 0)
+ {
+ /* Error, even if attached. Failing to write these two
+ registers is pretty serious. */
+ sprintf (buf, "writing register number %d", regno);
+ perror_with_name (buf);
+ }
+ }
+ else
+#endif
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
+ {
+ errno = 0;
+ ptrace (PTRACE_POKEUSR, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+ *(int *) &registers[REGISTER_BYTE (regno) + i]);
+ if (errno != 0)
+ {
+ /* Warning, not error, in case we are attached; sometimes the
+ kernel doesn't let us at the registers. */
+ char *err = strerror (errno);
+ char *msg = alloca (strlen (err) + 128);
+ sprintf (msg, "writing register %d: %s",
+ regno, err);
+ error (msg);
+ return;
+ }
+ regaddr += sizeof(int);
+ }
+ }
+ else
+ for (regno = 0; regno < NUM_REGS-NUM_FREGS; regno++)
+ store_inferior_registers (regno);
+}
+
+/* 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. */
+
+void
+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 (PTRACE_PEEKTEXT, inferior_pid, addr, 0);
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), 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 (PTRACE_PEEKTEXT, inferior_pid, addr, 0);
+
+ if (count > 1)
+ {
+ buffer[count - 1]
+ = ptrace (PTRACE_PEEKTEXT, inferior_pid,
+ addr + (count - 1) * sizeof (int), 0);
+ }
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ ptrace (PTRACE_POKETEXT, inferior_pid, addr, buffer[i]);
+ if (errno)
+ return errno;
+ }
+
+ return 0;
+}
+
+void
+initialize ()
+{
+ inferior_pid = 0;
+}
+
+int
+have_inferior_p ()
+{
+ return inferior_pid != 0;
+}
diff --git a/gdb/gdbserver/low-lynx.c b/gdb/gdbserver/low-lynx.c
new file mode 100644
index 00000000000..3444f7a116e
--- /dev/null
+++ b/gdb/gdbserver/low-lynx.c
@@ -0,0 +1,746 @@
+/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "server.h"
+#include "frame.h"
+#include "inferior.h"
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#define LYNXOS
+#include <sys/mem.h>
+#include <sys/signal.h>
+#include <sys/file.h>
+#include <sys/kernel.h>
+#ifndef __LYNXOS
+#define __LYNXOS
+#endif
+#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 <sys/wait.h>
+#include <sys/fpp.h>
+
+char registers[REGISTER_BYTES];
+
+#include <sys/ptrace.h>
+
+/* Start an inferior process and returns its pid.
+ ALLARGS is a vector of program-name and args. */
+
+int
+create_inferior (program, allargs)
+ char *program;
+ char **allargs;
+{
+ int pid;
+
+ pid = fork ();
+ if (pid < 0)
+ perror_with_name ("fork");
+
+ if (pid == 0)
+ {
+ int pgrp;
+
+ /* Switch child to it's own process group so that signals won't
+ directly affect gdbserver. */
+
+ pgrp = getpid();
+ setpgrp(0, pgrp);
+ ioctl (0, TIOCSPGRP, &pgrp);
+
+ ptrace (PTRACE_TRACEME, 0, (PTRACE_ARG3_TYPE)0, 0);
+
+ execv (program, allargs);
+
+ fprintf (stderr, "GDBserver (process %d): Cannot exec %s: %s.\n",
+ getpid(), program,
+ 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 (PTRACE_KILL, inferior_pid, 0, 0);
+ wait (0);
+
+ inferior_pid = 0;
+}
+
+/* Return nonzero if the given thread is still alive. */
+int
+mythread_alive (pid)
+ int pid;
+{
+ /* Arggh. Apparently pthread_kill only works for threads within
+ the process that calls pthread_kill.
+
+ We want to avoid the lynx signal extensions as they simply don't
+ map well to the generic gdb interface we want to keep.
+
+ All we want to do is determine if a particular thread is alive;
+ it appears as if we can just make a harmless thread specific
+ ptrace call to do that. */
+ return (ptrace (PTRACE_THREADUSER,
+ BUILDPID (PIDGET (inferior_pid), pid), 0, 0) != -1);
+}
+
+/* Wait for process, returns status */
+
+unsigned char
+mywait (status)
+ char *status;
+{
+ int pid;
+ union wait w;
+
+ while (1)
+ {
+ enable_async_io();
+
+ pid = wait (&w);
+
+ disable_async_io();
+
+ if (pid != PIDGET(inferior_pid))
+ perror_with_name ("wait");
+
+ thread_from_wait = w.w_tid;
+ inferior_pid = BUILDPID (inferior_pid, w.w_tid);
+
+ if (WIFSTOPPED(w)
+ && WSTOPSIG(w) == SIGTRAP)
+ {
+ int realsig;
+
+ realsig = ptrace (PTRACE_GETTRACESIG, inferior_pid,
+ (PTRACE_ARG3_TYPE)0, 0);
+
+ if (realsig == SIGNEWTHREAD)
+ {
+ /* It's a new thread notification. Nothing to do here since
+ the machine independent code in wait_for_inferior will
+ add the thread to the thread list and restart the thread
+ when pid != inferior_pid and pid is not in the thread list.
+ We don't even want to muck with realsig -- the code in
+ wait_for_inferior expects SIGTRAP. */
+ ;
+ }
+ }
+ break;
+ }
+
+ if (WIFEXITED (w))
+ {
+ *status = 'W';
+ return ((unsigned char) WEXITSTATUS (w));
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ *status = 'X';
+ return ((unsigned char) WTERMSIG (w));
+ }
+
+ fetch_inferior_registers (0);
+
+ *status = 'T';
+ 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_ONE : PTRACE_CONT,
+ BUILDPID (inferior_pid, cont_thread == -1 ? 0 : cont_thread),
+ 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+}
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+
+/* Mapping between GDB register #s and offsets into econtext. Must be
+ consistent with REGISTER_NAMES macro in various tmXXX.h files. */
+
+#define X(ENTRY)(offsetof(struct econtext, ENTRY))
+
+#ifdef I386
+/* Mappings from tm-i386v.h */
+
+static int regmap[] =
+{
+ X(eax),
+ X(ecx),
+ X(edx),
+ X(ebx),
+ X(esp), /* sp */
+ X(ebp), /* fp */
+ X(esi),
+ X(edi),
+ X(eip), /* pc */
+ 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. */
+};
+#endif
+
+#ifdef M68K
+/* Mappings from tm-m68k.h */
+
+static int regmap[] =
+{
+ X(regs[0]), /* d0 */
+ X(regs[1]), /* d1 */
+ X(regs[2]), /* d2 */
+ X(regs[3]), /* d3 */
+ X(regs[4]), /* d4 */
+ X(regs[5]), /* d5 */
+ X(regs[6]), /* d6 */
+ X(regs[7]), /* d7 */
+ X(regs[8]), /* a0 */
+ X(regs[9]), /* a1 */
+ X(regs[10]), /* a2 */
+ X(regs[11]), /* a3 */
+ X(regs[12]), /* a4 */
+ X(regs[13]), /* a5 */
+ X(regs[14]), /* fp */
+ 0, /* sp */
+ X(status), /* ps */
+ X(pc),
+
+ X(fregs[0*3]), /* fp0 */
+ X(fregs[1*3]), /* fp1 */
+ X(fregs[2*3]), /* fp2 */
+ X(fregs[3*3]), /* fp3 */
+ X(fregs[4*3]), /* fp4 */
+ X(fregs[5*3]), /* fp5 */
+ X(fregs[6*3]), /* fp6 */
+ X(fregs[7*3]), /* fp7 */
+
+ X(fcregs[0]), /* fpcontrol */
+ X(fcregs[1]), /* fpstatus */
+ X(fcregs[2]), /* fpiaddr */
+ X(ssw), /* fpcode */
+ X(fault), /* fpflags */
+};
+#endif
+
+#ifdef SPARC
+/* Mappings from tm-sparc.h */
+
+#define FX(ENTRY)(offsetof(struct fcontext, ENTRY))
+
+static int regmap[] =
+{
+ -1, /* g0 */
+ X(g1),
+ X(g2),
+ X(g3),
+ X(g4),
+ -1, /* g5->g7 aren't saved by Lynx */
+ -1,
+ -1,
+
+ X(o[0]),
+ X(o[1]),
+ X(o[2]),
+ X(o[3]),
+ X(o[4]),
+ X(o[5]),
+ X(o[6]), /* sp */
+ X(o[7]), /* ra */
+
+ -1,-1,-1,-1,-1,-1,-1,-1, /* l0 -> l7 */
+
+ -1,-1,-1,-1,-1,-1,-1,-1, /* i0 -> i7 */
+
+ FX(f.fregs[0]), /* f0 */
+ FX(f.fregs[1]),
+ FX(f.fregs[2]),
+ FX(f.fregs[3]),
+ FX(f.fregs[4]),
+ FX(f.fregs[5]),
+ FX(f.fregs[6]),
+ FX(f.fregs[7]),
+ FX(f.fregs[8]),
+ FX(f.fregs[9]),
+ FX(f.fregs[10]),
+ FX(f.fregs[11]),
+ FX(f.fregs[12]),
+ FX(f.fregs[13]),
+ FX(f.fregs[14]),
+ FX(f.fregs[15]),
+ FX(f.fregs[16]),
+ FX(f.fregs[17]),
+ FX(f.fregs[18]),
+ FX(f.fregs[19]),
+ FX(f.fregs[20]),
+ FX(f.fregs[21]),
+ FX(f.fregs[22]),
+ FX(f.fregs[23]),
+ FX(f.fregs[24]),
+ FX(f.fregs[25]),
+ FX(f.fregs[26]),
+ FX(f.fregs[27]),
+ FX(f.fregs[28]),
+ FX(f.fregs[29]),
+ FX(f.fregs[30]),
+ FX(f.fregs[31]),
+
+ X(y),
+ X(psr),
+ X(wim),
+ X(tbr),
+ X(pc),
+ X(npc),
+ FX(fsr), /* fpsr */
+ -1, /* cpsr */
+};
+#endif
+
+#ifdef SPARC
+
+/* This routine handles some oddball cases for Sparc registers and LynxOS.
+ In partucular, it causes refs to G0, g5->7, and all fp regs to return zero.
+ It also handles knows where to find the I & L regs on the stack. */
+
+void
+fetch_inferior_registers (regno)
+ int regno;
+{
+#if 0
+ int whatregs = 0;
+
+#define WHATREGS_FLOAT 1
+#define WHATREGS_GEN 2
+#define WHATREGS_STACK 4
+
+ if (regno == -1)
+ whatregs = WHATREGS_FLOAT | WHATREGS_GEN | WHATREGS_STACK;
+ else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
+ whatregs = WHATREGS_STACK;
+ else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
+ whatregs = WHATREGS_FLOAT;
+ else
+ whatregs = WHATREGS_GEN;
+
+ if (whatregs & WHATREGS_GEN)
+ {
+ struct econtext ec; /* general regs */
+ char buf[MAX_REGISTER_RAW_SIZE];
+ int retval;
+ int i;
+
+ errno = 0;
+ retval = ptrace (PTRACE_GETREGS,
+ BUILDPID (inferior_pid, general_thread),
+ (PTRACE_ARG3_TYPE) &ec,
+ 0);
+ if (errno)
+ perror_with_name ("Sparc fetch_inferior_registers(ptrace)");
+
+ memset (buf, 0, REGISTER_RAW_SIZE (G0_REGNUM));
+ supply_register (G0_REGNUM, buf);
+ supply_register (TBR_REGNUM, (char *)&ec.tbr);
+
+ memcpy (&registers[REGISTER_BYTE (G1_REGNUM)], &ec.g1,
+ 4 * REGISTER_RAW_SIZE (G1_REGNUM));
+ for (i = G1_REGNUM; i <= G1_REGNUM + 3; i++)
+ register_valid[i] = 1;
+
+ supply_register (PS_REGNUM, (char *)&ec.psr);
+ supply_register (Y_REGNUM, (char *)&ec.y);
+ supply_register (PC_REGNUM, (char *)&ec.pc);
+ supply_register (NPC_REGNUM, (char *)&ec.npc);
+ supply_register (WIM_REGNUM, (char *)&ec.wim);
+
+ memcpy (&registers[REGISTER_BYTE (O0_REGNUM)], ec.o,
+ 8 * REGISTER_RAW_SIZE (O0_REGNUM));
+ for (i = O0_REGNUM; i <= O0_REGNUM + 7; i++)
+ register_valid[i] = 1;
+ }
+
+ if (whatregs & WHATREGS_STACK)
+ {
+ CORE_ADDR sp;
+ int i;
+
+ sp = read_register (SP_REGNUM);
+
+ target_xfer_memory (sp + FRAME_SAVED_I0,
+ &registers[REGISTER_BYTE(I0_REGNUM)],
+ 8 * REGISTER_RAW_SIZE (I0_REGNUM), 0);
+ for (i = I0_REGNUM; i <= I7_REGNUM; i++)
+ register_valid[i] = 1;
+
+ target_xfer_memory (sp + FRAME_SAVED_L0,
+ &registers[REGISTER_BYTE(L0_REGNUM)],
+ 8 * REGISTER_RAW_SIZE (L0_REGNUM), 0);
+ for (i = L0_REGNUM; i <= L0_REGNUM + 7; i++)
+ register_valid[i] = 1;
+ }
+
+ if (whatregs & WHATREGS_FLOAT)
+ {
+ struct fcontext fc; /* fp regs */
+ int retval;
+ int i;
+
+ errno = 0;
+ retval = ptrace (PTRACE_GETFPREGS, BUILDPID (inferior_pid, general_thread), (PTRACE_ARG3_TYPE) &fc,
+ 0);
+ if (errno)
+ perror_with_name ("Sparc fetch_inferior_registers(ptrace)");
+
+ memcpy (&registers[REGISTER_BYTE (FP0_REGNUM)], fc.f.fregs,
+ 32 * REGISTER_RAW_SIZE (FP0_REGNUM));
+ for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++)
+ register_valid[i] = 1;
+
+ supply_register (FPS_REGNUM, (char *)&fc.fsr);
+ }
+#endif
+}
+
+/* This routine handles storing of the I & L regs for the Sparc. The trick
+ here is that they actually live on the stack. The really tricky part is
+ that when changing the stack pointer, the I & L regs must be written to
+ where the new SP points, otherwise the regs will be incorrect when the
+ process is started up again. We assume that the I & L regs are valid at
+ this point. */
+
+void
+store_inferior_registers (regno)
+ int regno;
+{
+#if 0
+ int whatregs = 0;
+
+ if (regno == -1)
+ whatregs = WHATREGS_FLOAT | WHATREGS_GEN | WHATREGS_STACK;
+ else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
+ whatregs = WHATREGS_STACK;
+ else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
+ whatregs = WHATREGS_FLOAT;
+ else if (regno == SP_REGNUM)
+ whatregs = WHATREGS_STACK | WHATREGS_GEN;
+ else
+ whatregs = WHATREGS_GEN;
+
+ if (whatregs & WHATREGS_GEN)
+ {
+ struct econtext ec; /* general regs */
+ int retval;
+
+ ec.tbr = read_register (TBR_REGNUM);
+ memcpy (&ec.g1, &registers[REGISTER_BYTE (G1_REGNUM)],
+ 4 * REGISTER_RAW_SIZE (G1_REGNUM));
+
+ ec.psr = read_register (PS_REGNUM);
+ ec.y = read_register (Y_REGNUM);
+ ec.pc = read_register (PC_REGNUM);
+ ec.npc = read_register (NPC_REGNUM);
+ ec.wim = read_register (WIM_REGNUM);
+
+ memcpy (ec.o, &registers[REGISTER_BYTE (O0_REGNUM)],
+ 8 * REGISTER_RAW_SIZE (O0_REGNUM));
+
+ errno = 0;
+ retval = ptrace (PTRACE_SETREGS, BUILDPID (inferior_pid, general_thread), (PTRACE_ARG3_TYPE) &ec,
+ 0);
+ if (errno)
+ perror_with_name ("Sparc fetch_inferior_registers(ptrace)");
+ }
+
+ if (whatregs & WHATREGS_STACK)
+ {
+ int regoffset;
+ CORE_ADDR sp;
+
+ sp = read_register (SP_REGNUM);
+
+ if (regno == -1 || regno == SP_REGNUM)
+ {
+ if (!register_valid[L0_REGNUM+5])
+ abort();
+ target_xfer_memory (sp + FRAME_SAVED_I0,
+ &registers[REGISTER_BYTE (I0_REGNUM)],
+ 8 * REGISTER_RAW_SIZE (I0_REGNUM), 1);
+
+ target_xfer_memory (sp + FRAME_SAVED_L0,
+ &registers[REGISTER_BYTE (L0_REGNUM)],
+ 8 * REGISTER_RAW_SIZE (L0_REGNUM), 1);
+ }
+ else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
+ {
+ if (!register_valid[regno])
+ abort();
+ if (regno >= L0_REGNUM && regno <= L0_REGNUM + 7)
+ regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (L0_REGNUM)
+ + FRAME_SAVED_L0;
+ else
+ regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (I0_REGNUM)
+ + FRAME_SAVED_I0;
+ target_xfer_memory (sp + regoffset, &registers[REGISTER_BYTE (regno)],
+ REGISTER_RAW_SIZE (regno), 1);
+ }
+ }
+
+ if (whatregs & WHATREGS_FLOAT)
+ {
+ struct fcontext fc; /* fp regs */
+ int retval;
+
+/* We read fcontext first so that we can get good values for fq_t... */
+ errno = 0;
+ retval = ptrace (PTRACE_GETFPREGS, BUILDPID (inferior_pid, general_thread), (PTRACE_ARG3_TYPE) &fc,
+ 0);
+ if (errno)
+ perror_with_name ("Sparc fetch_inferior_registers(ptrace)");
+
+ memcpy (fc.f.fregs, &registers[REGISTER_BYTE (FP0_REGNUM)],
+ 32 * REGISTER_RAW_SIZE (FP0_REGNUM));
+
+ fc.fsr = read_register (FPS_REGNUM);
+
+ errno = 0;
+ retval = ptrace (PTRACE_SETFPREGS, BUILDPID (inferior_pid, general_thread), (PTRACE_ARG3_TYPE) &fc,
+ 0);
+ if (errno)
+ perror_with_name ("Sparc fetch_inferior_registers(ptrace)");
+ }
+#endif
+}
+#endif /* SPARC */
+
+#ifndef SPARC
+
+/* Return the offset relative to the start of the per-thread data to the
+ saved context block. */
+
+static unsigned long
+lynx_registers_addr()
+{
+ CORE_ADDR stblock;
+ int ecpoff = offsetof(st_t, ecp);
+ CORE_ADDR ecp;
+
+ errno = 0;
+ stblock = (CORE_ADDR) ptrace (PTRACE_THREADUSER, BUILDPID (inferior_pid, general_thread),
+ (PTRACE_ARG3_TYPE)0, 0);
+ if (errno)
+ perror_with_name ("PTRACE_THREADUSER");
+
+ ecp = (CORE_ADDR) ptrace (PTRACE_PEEKTHREAD, BUILDPID (inferior_pid, general_thread),
+ (PTRACE_ARG3_TYPE)ecpoff, 0);
+ if (errno)
+ perror_with_name ("lynx_registers_addr(PTRACE_PEEKTHREAD)");
+
+ return ecp - stblock;
+}
+
+/* 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;
+ unsigned long ecp;
+
+ ecp = lynx_registers_addr();
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ int ptrace_fun = PTRACE_PEEKTHREAD;
+
+#ifdef PTRACE_PEEKUSP
+ ptrace_fun = regno == SP_REGNUM ? PTRACE_PEEKUSP : PTRACE_PEEKTHREAD;
+#endif
+
+ errno = 0;
+ reg = ptrace (ptrace_fun, BUILDPID (inferior_pid, general_thread),
+ (PTRACE_ARG3_TYPE) (ecp + 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;
+ unsigned long ecp;
+
+ ecp = lynx_registers_addr();
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ int ptrace_fun = PTRACE_POKEUSER;
+
+#ifdef PTRACE_POKEUSP
+ ptrace_fun = regno == SP_REGNUM ? PTRACE_POKEUSP : PTRACE_POKEUSER;
+#endif
+
+ reg = *(unsigned long *)&registers[REGISTER_BYTE (regno)];
+
+ errno = 0;
+ ptrace (ptrace_fun, BUILDPID (inferior_pid, general_thread),
+ (PTRACE_ARG3_TYPE) (ecp + regmap[regno]), reg);
+ if (errno)
+ perror_with_name ("PTRACE_POKEUSER");
+ }
+}
+
+#endif /* ! SPARC */
+
+/* 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. */
+
+void
+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 (PTRACE_PEEKTEXT, BUILDPID (inferior_pid, general_thread), addr, 0);
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), 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 (PTRACE_PEEKTEXT, BUILDPID (inferior_pid, general_thread), addr, 0);
+
+ if (count > 1)
+ {
+ buffer[count - 1]
+ = ptrace (PTRACE_PEEKTEXT, BUILDPID (inferior_pid, general_thread),
+ addr + (count - 1) * sizeof (int), 0);
+ }
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ while (1)
+ {
+ errno = 0;
+ ptrace (PTRACE_POKETEXT, BUILDPID (inferior_pid, general_thread), addr, buffer[i]);
+ if (errno)
+ {
+ fprintf(stderr, "\
+ptrace (PTRACE_POKETEXT): errno=%d, pid=0x%x, addr=0x%x, buffer[i] = 0x%x\n",
+ errno, BUILDPID (inferior_pid, general_thread),
+ addr, buffer[i]);
+ fprintf(stderr, "Sleeping for 1 second\n");
+ sleep(1);
+ }
+ else
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/gdb/gdbserver/low-sim.c b/gdb/gdbserver/low-sim.c
new file mode 100644
index 00000000000..8ad6e91d461
--- /dev/null
+++ b/gdb/gdbserver/low-sim.c
@@ -0,0 +1,289 @@
+/* Low level interface to simulators, for the remote server for GDB.
+ Copyright (C) 1995, 1996 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "server.h"
+#include "callback.h" /* GDB simulator callback interface */
+#include "remote-sim.h" /* GDB simulator interface */
+
+extern int remote_debug;
+
+extern host_callback default_callback; /* in sim/common/callback.c */
+
+char registers[REGISTER_BYTES] __attribute__ ((aligned));
+
+int target_byte_order; /* used by simulator */
+
+/* We record the result of sim_open so we can pass it
+ back to the other sim_foo routines. */
+static SIM_DESC gdbsim_desc = 0;
+
+/* This version of "load" should be usable for any simulator that
+ does not support loading itself. */
+
+static void
+generic_load (loadfile_bfd)
+ bfd *loadfile_bfd;
+{
+ asection *s;
+
+ for (s = loadfile_bfd->sections; s; s = s->next)
+ {
+ if (s->flags & SEC_LOAD)
+ {
+ bfd_size_type size;
+
+ size = bfd_get_section_size_before_reloc (s);
+ if (size > 0)
+ {
+ char *buffer;
+ bfd_vma lma; /* use load address, not virtual address */
+
+ buffer = xmalloc (size);
+ lma = s->lma;
+
+ /* Is this really necessary? I guess it gives the user something
+ to look at during a long download. */
+ printf ("Loading section %s, size 0x%lx lma 0x%lx\n",
+ bfd_get_section_name (loadfile_bfd, s),
+ (unsigned long) size,
+ (unsigned long) lma); /* chops high 32 bits. FIXME!! */
+
+ bfd_get_section_contents (loadfile_bfd, s, buffer, 0, size);
+
+ write_inferior_memory (lma, buffer, size);
+ free (buffer);
+ }
+ }
+ }
+
+ printf ("Start address 0x%lx\n",
+ (unsigned long)loadfile_bfd->start_address);
+
+ /* We were doing this in remote-mips.c, I suspect it is right
+ for other targets too. */
+ /* write_pc (loadfile_bfd->start_address); */ /* FIXME!! */
+}
+
+int
+create_inferior (program, argv)
+ char *program;
+ char **argv;
+{
+ bfd *abfd;
+ int pid = 0;
+#ifdef TARGET_BYTE_ORDER_SELECTABLE
+ char **new_argv;
+ int nargs;
+#endif
+
+ abfd = bfd_openr (program, 0);
+ if (!abfd)
+ {
+ fprintf (stderr, "gdbserver: can't open %s: %s\n",
+ program, bfd_errmsg (bfd_get_error ()));
+ exit (1);
+ }
+
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ fprintf (stderr, "gdbserver: unknown load format for %s: %s\n",
+ program, bfd_errmsg (bfd_get_error ()));
+ exit (1);
+ }
+
+#ifdef TARGET_BYTE_ORDER_SELECTABLE
+ /* Add "-E big" or "-E little" to the argument list depending on the
+ endianness of the program to be loaded. */
+ for (nargs = 0; argv[nargs] != NULL; nargs++) /* count the args */
+ ;
+ new_argv = alloca (sizeof (char *) * (nargs + 3)); /* allocate new args */
+ for (nargs = 0; argv[nargs] != NULL; nargs++) /* copy old to new */
+ new_argv[nargs] = argv[nargs];
+ new_argv[nargs] = "-E";
+ new_argv[nargs + 1] = bfd_big_endian (abfd) ? "big" : "little";
+ new_argv[nargs + 2] = NULL;
+ argv = new_argv;
+#endif
+
+ /* Create an instance of the simulator. */
+ default_callback.init (&default_callback);
+ gdbsim_desc = sim_open (SIM_OPEN_STANDALONE, &default_callback, abfd, argv);
+ if (gdbsim_desc == 0)
+ exit (1);
+
+ /* Load the program into the simulator. */
+ if (abfd)
+ if (sim_load (gdbsim_desc, program, NULL, 0) == SIM_RC_FAIL)
+ generic_load (abfd);
+
+ /* Create an inferior process in the simulator. This initializes SP. */
+ sim_create_inferior (gdbsim_desc, abfd, argv, /* env */ NULL);
+ sim_resume (gdbsim_desc, 1, 0); /* execute one instr */
+ return pid;
+}
+
+/* Kill the inferior process. Make us have no inferior. */
+
+void
+kill_inferior ()
+{
+ sim_close (gdbsim_desc, 0);
+ default_callback.shutdown (&default_callback);
+}
+
+/* Fetch one register. */
+
+static void
+fetch_register (regno)
+ int regno;
+{
+ sim_fetch_register (gdbsim_desc, regno, &registers[REGISTER_BYTE (regno)],
+ REGISTER_RAW_SIZE (regno));
+}
+
+/* Fetch all registers, or just one, from the child process. */
+
+void
+fetch_inferior_registers (regno)
+ int regno;
+{
+ if (regno == -1 || regno == 0)
+ for (regno = 0; regno < NUM_REGS/*-NUM_FREGS*/; regno++)
+ fetch_register (regno);
+ else
+ fetch_register (regno);
+}
+
+/* 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 (regno)
+ int regno;
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ store_inferior_registers (regno);
+ }
+ else
+ sim_store_register (gdbsim_desc, regno, &registers[REGISTER_BYTE (regno)],
+ REGISTER_RAW_SIZE (regno));
+}
+
+/* Return nonzero if the given thread is still alive. */
+int
+mythread_alive (pid)
+ int pid;
+{
+ return 1;
+}
+
+/* Wait for process, returns status */
+
+unsigned char
+mywait (status)
+ char *status;
+{
+ int sigrc;
+ enum sim_stop reason;
+
+ sim_stop_reason (gdbsim_desc, &reason, &sigrc);
+ switch (reason)
+ {
+ case sim_exited:
+ if (remote_debug)
+ printf ("\nChild exited with retcode = %x \n", sigrc);
+ *status = 'W';
+ return sigrc;
+
+#if 0
+ case sim_stopped:
+ if (remote_debug)
+ printf ("\nChild terminated with signal = %x \n", sigrc);
+ *status = 'X';
+ return sigrc;
+#endif
+
+ default: /* should this be sim_signalled or sim_stopped? FIXME!! */
+ if (remote_debug)
+ printf ("\nChild received signal = %x \n", sigrc);
+ fetch_inferior_registers (0);
+ *status = 'T';
+ return (unsigned char) sigrc;
+ }
+}
+
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+myresume (step, signo)
+ int step;
+ int signo;
+{
+ /* Should be using target_signal_to_host() or signal numbers in target.h
+ to convert GDB signal number to target signal number. */
+ sim_resume (gdbsim_desc, step, signo);
+}
+
+/* Copy LEN bytes from inferior's memory starting at MEMADDR
+ to debugger memory starting at MYADDR. */
+
+void
+read_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ sim_read (gdbsim_desc, memaddr, 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;
+{
+ sim_write (gdbsim_desc, memaddr, myaddr, len); /* should check for error. FIXME!! */
+ return 0;
+}
+
+#if 0
+void
+initialize ()
+{
+ inferior_pid = 0;
+}
+
+int
+have_inferior_p ()
+{
+ return inferior_pid != 0;
+}
+#endif
diff --git a/gdb/gdbserver/low-sparc.c b/gdb/gdbserver/low-sparc.c
new file mode 100644
index 00000000000..ddffaec5927
--- /dev/null
+++ b/gdb/gdbserver/low-sparc.c
@@ -0,0 +1,334 @@
+/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include <sys/wait.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>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sgtty.h>
+#include <fcntl.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 <sys/reg.h>
+
+extern int sys_nerr;
+extern char **sys_errlist;
+extern char **environ;
+extern int errno;
+extern int inferior_pid;
+void 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 (program, allargs)
+ char *program;
+ char **allargs;
+{
+ int pid;
+
+ pid = fork ();
+ if (pid < 0)
+ perror_with_name ("fork");
+
+ if (pid == 0)
+ {
+ ptrace (PTRACE_TRACEME);
+
+ execv (program, allargs);
+
+ fprintf (stderr, "Cannot exec %s: %s.\n", program,
+ 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**************/
+}
+
+/* Return nonzero if the given thread is still alive. */
+int
+mythread_alive (pid)
+ int pid;
+{
+ return 1;
+}
+
+/* Wait for process, returns status */
+
+unsigned char
+mywait (status)
+ char *status;
+{
+ int pid;
+ union wait w;
+
+ pid = wait (&w);
+ if (pid != inferior_pid)
+ perror_with_name ("wait");
+
+ if (WIFEXITED (w))
+ {
+ fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
+ *status = 'W';
+ return ((unsigned char) WEXITSTATUS (w));
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
+ *status = 'X';
+ return ((unsigned char) WTERMSIG (w));
+ }
+
+ fetch_inferior_registers (0);
+
+ *status = 'T';
+ 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");
+}
+
+/* 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;
+{
+ struct regs inferior_registers;
+ struct fp_status inferior_fp_registers;
+ int i;
+
+ /* Global and Out regs are fetched directly, as well as the control
+ registers. If we're getting one of the in or local regs,
+ and the stack pointer has not yet been fetched,
+ we have to do that first, since they're found in memory relative
+ to the stack pointer. */
+
+ if (ptrace (PTRACE_GETREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_registers, 0))
+ perror("ptrace_getregs");
+
+ registers[REGISTER_BYTE (0)] = 0;
+ memcpy (&registers[REGISTER_BYTE (1)], &inferior_registers.r_g1,
+ 15 * REGISTER_RAW_SIZE (G0_REGNUM));
+ *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
+ *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
+ *(int *)&registers[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc;
+ *(int *)&registers[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y;
+
+ /* Floating point registers */
+
+ if (ptrace (PTRACE_GETFPREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers,
+ 0))
+ perror("ptrace_getfpregs");
+ memcpy (&registers[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
+ sizeof inferior_fp_registers.fpu_fr);
+
+ /* These regs are saved on the stack by the kernel. Only read them
+ all (16 ptrace calls!) if we really need them. */
+
+ read_inferior_memory (*(CORE_ADDR*)&registers[REGISTER_BYTE (SP_REGNUM)],
+ &registers[REGISTER_BYTE (L0_REGNUM)],
+ 16*REGISTER_RAW_SIZE (L0_REGNUM));
+}
+
+/* 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;
+{
+ struct regs inferior_registers;
+ struct fp_status inferior_fp_registers;
+ CORE_ADDR sp = *(CORE_ADDR *)&registers[REGISTER_BYTE (SP_REGNUM)];
+
+ write_inferior_memory (sp, &registers[REGISTER_BYTE (L0_REGNUM)],
+ 16*REGISTER_RAW_SIZE (L0_REGNUM));
+
+ memcpy (&inferior_registers.r_g1, &registers[REGISTER_BYTE (G1_REGNUM)],
+ 15 * REGISTER_RAW_SIZE (G1_REGNUM));
+
+ inferior_registers.r_ps =
+ *(int *)&registers[REGISTER_BYTE (PS_REGNUM)];
+ inferior_registers.r_pc =
+ *(int *)&registers[REGISTER_BYTE (PC_REGNUM)];
+ inferior_registers.r_npc =
+ *(int *)&registers[REGISTER_BYTE (NPC_REGNUM)];
+ inferior_registers.r_y =
+ *(int *)&registers[REGISTER_BYTE (Y_REGNUM)];
+
+ if (ptrace (PTRACE_SETREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_registers, 0))
+ perror("ptrace_setregs");
+
+ memcpy (&inferior_fp_registers, &registers[REGISTER_BYTE (FP0_REGNUM)],
+ sizeof inferior_fp_registers.fpu_fr);
+
+ if (ptrace (PTRACE_SETFPREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0))
+ perror("ptrace_setfpregs");
+}
+
+/* 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. */
+ memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), 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;
+}
+
+void
+initialize ()
+{
+ inferior_pid = 0;
+}
+
+int
+have_inferior_p ()
+{
+ return inferior_pid != 0;
+}
diff --git a/gdb/gdbserver/low-sun3.c b/gdb/gdbserver/low-sun3.c
new file mode 100644
index 00000000000..c84b79f2f68
--- /dev/null
+++ b/gdb/gdbserver/low-sun3.c
@@ -0,0 +1,313 @@
+/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "<sys/wait.h>"
+#include "frame.h"
+#include "inferior.h"
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/user.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sgtty.h>
+#include <fcntl.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 int sys_nerr;
+extern char **sys_errlist;
+extern char **environ;
+extern int errno;
+extern int inferior_pid;
+void 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 (program, allargs)
+ char *program;
+ char **allargs;
+{
+ int pid;
+
+ pid = fork ();
+ if (pid < 0)
+ perror_with_name ("fork");
+
+ if (pid == 0)
+ {
+ ptrace (PTRACE_TRACEME);
+
+ execv (program, allargs);
+
+ fprintf (stderr, "Cannot exec %s: %s.\n", program,
+ 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**************/
+}
+
+/* Return nonzero if the given thread is still alive. */
+int
+mythread_alive (pid)
+ int pid;
+{
+ return 1;
+}
+
+/* Wait for process, returns status */
+
+unsigned char
+mywait (status)
+ char *status;
+{
+ int pid;
+ union wait w;
+
+ pid = wait (&w);
+ if (pid != inferior_pid)
+ perror_with_name ("wait");
+
+ if (WIFEXITED (w))
+ {
+ fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
+ *status = 'W';
+ return ((unsigned char) WEXITSTATUS (w));
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
+ *status = 'X';
+ return ((unsigned char) WTERMSIG (w));
+ }
+
+ fetch_inferior_registers (0);
+
+ *status = 'T';
+ 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");
+}
+
+/* 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;
+{
+ struct regs inferior_registers;
+ struct fp_status inferior_fp_registers;
+
+ ptrace (PTRACE_GETREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_registers);
+#ifdef FP0_REGNUM
+ ptrace (PTRACE_GETFPREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers);
+#endif
+
+ memcpy (registers, &inferior_registers, 16 * 4);
+#ifdef FP0_REGNUM
+ memcpy (&registers[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
+ sizeof inferior_fp_registers.fps_regs);
+#endif
+ *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
+ *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
+#ifdef FP0_REGNUM
+ memcpy
+ (&registers[REGISTER_BYTE (FPC_REGNUM)],
+ &inferior_fp_registers.fps_control,
+ sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
+#endif
+}
+
+/* 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;
+{
+ struct regs inferior_registers;
+ struct fp_status inferior_fp_registers;
+
+ memcpy (&inferior_registers, registers, 16 * 4);
+#ifdef FP0_REGNUM
+ memcpy (&inferior_fp_registers,
+ &registers[REGISTER_BYTE (FP0_REGNUM)],
+ sizeof inferior_fp_registers.fps_regs);
+#endif
+ inferior_registers.r_ps = *(int *)&registers[REGISTER_BYTE (PS_REGNUM)];
+ inferior_registers.r_pc = *(int *)&registers[REGISTER_BYTE (PC_REGNUM)];
+
+#ifdef FP0_REGNUM
+ memcpy (&inferior_fp_registers.fps_control,
+ &registers[REGISTER_BYTE (FPC_REGNUM)],
+ (sizeof inferior_fp_registers
+ - sizeof inferior_fp_registers.fps_regs));
+#endif
+
+ ptrace (PTRACE_SETREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_registers);
+#if FP0_REGNUM
+ ptrace (PTRACE_SETFPREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers);
+#endif
+}
+
+/* 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. */
+ memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), 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 */
+
+ memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, 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;
+}
+
+void
+initialize ()
+{
+ inferior_pid = 0;
+}
+
+int
+have_inferior_p ()
+{
+ return inferior_pid != 0;
+}
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
new file mode 100644
index 00000000000..0a7e0fbc797
--- /dev/null
+++ b/gdb/gdbserver/remote-utils.c
@@ -0,0 +1,545 @@
+/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "server.h"
+#include "terminal.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <fcntl.h>
+
+int remote_debug = 0;
+
+static int remote_desc;
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+void
+remote_open (name)
+ char *name;
+{
+ int save_fcntl_flags;
+
+ if (!strchr (name, ':'))
+ {
+ remote_desc = open (name, O_RDWR);
+ if (remote_desc < 0)
+ perror_with_name ("Could not open remote device");
+
+#ifdef HAVE_TERMIOS
+ {
+ struct termios termios;
+ tcgetattr(remote_desc, &termios);
+
+ termios.c_iflag = 0;
+ termios.c_oflag = 0;
+ termios.c_lflag = 0;
+ termios.c_cflag &= ~(CSIZE|PARENB);
+ termios.c_cflag |= CLOCAL | CS8;
+ termios.c_cc[VMIN] = 0;
+ termios.c_cc[VTIME] = 0;
+
+ tcsetattr(remote_desc, TCSANOW, &termios);
+ }
+#endif
+
+#ifdef HAVE_TERMIO
+ {
+ struct termio termio;
+ ioctl (remote_desc, TCGETA, &termio);
+
+ termio.c_iflag = 0;
+ termio.c_oflag = 0;
+ termio.c_lflag = 0;
+ termio.c_cflag &= ~(CSIZE|PARENB);
+ termio.c_cflag |= CLOCAL | CS8;
+ termio.c_cc[VMIN] = 0;
+ termio.c_cc[VTIME] = 0;
+
+ ioctl (remote_desc, TCSETA, &termio);
+ }
+#endif
+
+#ifdef HAVE_SGTTY
+ {
+ struct sgttyb sg;
+
+ ioctl (remote_desc, TIOCGETP, &sg);
+ sg.sg_flags = RAW;
+ ioctl (remote_desc, TIOCSETP, &sg);
+ }
+#endif
+
+
+ }
+ else
+ {
+ char *port_str;
+ int port;
+ struct sockaddr_in sockaddr;
+ int tmp;
+ struct protoent *protoent;
+ int tmp_desc;
+
+ port_str = strchr (name, ':');
+
+ port = atoi (port_str + 1);
+
+ tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
+ if (tmp_desc < 0)
+ perror_with_name ("Can't open socket");
+
+ /* Allow rapid reuse of this port. */
+ tmp = 1;
+ setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp,
+ sizeof(tmp));
+
+ sockaddr.sin_family = PF_INET;
+ sockaddr.sin_port = htons(port);
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+
+ if (bind (tmp_desc, (struct sockaddr *)&sockaddr, sizeof (sockaddr))
+ || listen (tmp_desc, 1))
+ perror_with_name ("Can't bind address");
+
+ tmp = sizeof (sockaddr);
+ remote_desc = accept (tmp_desc, (struct sockaddr *)&sockaddr, &tmp);
+ if (remote_desc == -1)
+ perror_with_name ("Accept failed");
+
+ protoent = getprotobyname ("tcp");
+ if (!protoent)
+ perror_with_name ("getprotobyname");
+
+ /* Enable TCP keep alive process. */
+ tmp = 1;
+ setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
+
+ /* Tell TCP not to delay small packets. This greatly speeds up
+ interactive response. */
+ tmp = 1;
+ setsockopt (remote_desc, protoent->p_proto, TCP_NODELAY,
+ (char *)&tmp, sizeof(tmp));
+
+ close (tmp_desc); /* No longer need this */
+
+ signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply
+ exits when the remote side dies. */
+ }
+
+#if defined(F_SETFL) && defined (FASYNC)
+ save_fcntl_flags = fcntl (remote_desc, F_GETFL, 0);
+ fcntl (remote_desc, F_SETFL, save_fcntl_flags | FASYNC);
+ disable_async_io ();
+#endif /* FASYNC */
+ fprintf (stderr, "Remote debugging using %s\n", name);
+}
+
+void
+remote_close()
+{
+ close (remote_desc);
+}
+
+/* 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 a packet to the remote machine, with error checking.
+ The data of the packet is in BUF. Returns >= 0 on success, -1 otherwise. */
+
+int
+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);
+
+ *p = '\0';
+
+ /* Send it over and over until we get a positive ack. */
+
+ do
+ {
+ int cc;
+
+ if (write (remote_desc, buf2, p - buf2) != p - buf2)
+ {
+ perror ("putpkt(write)");
+ return -1;
+ }
+
+ if (remote_debug)
+ printf ("putpkt (\"%s\"); [looking for ack]\n", buf2);
+ cc = read (remote_desc, buf3, 1);
+ if (remote_debug)
+ printf ("[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
+ if (cc <= 0)
+ {
+ if (cc == 0)
+ fprintf (stderr, "putpkt(read): Got EOF\n");
+ else
+ perror ("putpkt(read)");
+
+ return -1;
+ }
+ }
+ while (buf3[0] != '+');
+
+ return 1; /* Success! */
+}
+
+/* Come here when we get an input interrupt from the remote side. This
+ interrupt should only be active while we are waiting for the child to do
+ something. About the only thing that should come through is a ^C, which
+ will cause us to send a SIGINT to the child. */
+
+static void
+input_interrupt()
+{
+ int cc;
+ char c;
+
+ cc = read (remote_desc, &c, 1);
+
+ if (cc != 1 || c != '\003')
+ {
+ fprintf(stderr, "input_interrupt, cc = %d c = %d\n", cc, c);
+ return;
+ }
+
+ kill (inferior_pid, SIGINT);
+}
+
+void
+enable_async_io()
+{
+ signal (SIGIO, input_interrupt);
+}
+
+void
+disable_async_io()
+{
+ signal (SIGIO, SIG_IGN);
+}
+
+/* Returns next char from remote GDB. -1 if error. */
+
+static int
+readchar ()
+{
+ static char buf[BUFSIZ];
+ static int bufcnt = 0;
+ static char *bufp;
+
+ if (bufcnt-- > 0)
+ return *bufp++ & 0x7f;
+
+ bufcnt = read (remote_desc, buf, sizeof (buf));
+
+ if (bufcnt <= 0)
+ {
+ if (bufcnt == 0)
+ fprintf (stderr, "readchar: Got EOF\n");
+ else
+ perror ("readchar");
+
+ return -1;
+ }
+
+ bufp = buf;
+ bufcnt--;
+ return *bufp++ & 0x7f;
+}
+
+/* Read a packet from the remote machine, with error checking,
+ and store it in BUF. Returns length of packet, or negative if error. */
+
+int
+getpkt (buf)
+ char *buf;
+{
+ char *bp;
+ unsigned char csum, c1, c2;
+ int c;
+
+ while (1)
+ {
+ csum = 0;
+
+ while (1)
+ {
+ c = readchar ();
+ if (c == '$')
+ break;
+ if (remote_debug)
+ printf ("[getpkt: discarding char '%c']\n", c);
+ if (c < 0)
+ return -1;
+ }
+
+ bp = buf;
+ while (1)
+ {
+ c = readchar ();
+ if (c < 0)
+ return -1;
+ 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);
+ }
+
+ if (remote_debug)
+ printf ("getpkt (\"%s\"); [sending ack] \n", buf);
+
+ write (remote_desc, "+", 1);
+
+ if (remote_debug)
+ printf ("[sent ack]\n");
+ return bp - buf;
+}
+
+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[];
+ int regsize = REGISTER_RAW_SIZE (regno);
+
+ *buf++ = tohex (regno >> 4);
+ *buf++ = tohex (regno & 0xf);
+ *buf++ = ':';
+ convert_int_to_ascii (&registers[REGISTER_BYTE (regno)], buf, regsize);
+ buf += 2 * regsize;
+ *buf++ = ';';
+
+ return buf;
+}
+
+void
+prepare_resume_reply (buf, status, signo)
+ char *buf;
+ char status;
+ unsigned char signo;
+{
+ int nib;
+
+ *buf++ = status;
+
+ /* FIXME! Should be converting this signal number (numbered
+ according to the signal numbering of the system we are running on)
+ to the signal numbers used by the gdb protocol (see enum target_signal
+ in gdb/target.h). */
+ nib = ((signo & 0xf0) >> 4);
+ *buf++ = tohex (nib);
+ nib = signo & 0x0f;
+ *buf++ = tohex (nib);
+
+ if (status == 'T')
+ {
+ 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
+
+ /* If the debugger hasn't used any thread features, don't burden it with
+ threads. If we didn't check this, GDB 4.13 and older would choke. */
+ if (cont_thread != 0)
+ {
+ if (old_thread_from_wait != thread_from_wait)
+ {
+ sprintf (buf, "thread:%x;", thread_from_wait);
+ buf += strlen (buf);
+ old_thread_from_wait = thread_from_wait;
+ }
+ }
+ }
+ /* For W and X, we're done. */
+ *buf++ = 0;
+}
+
+void
+decode_m_packet (from, mem_addr_ptr, len_ptr)
+ char *from;
+ CORE_ADDR *mem_addr_ptr;
+ unsigned int *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;
+ CORE_ADDR *mem_addr_ptr;
+ unsigned int *len_ptr;
+{
+ int i = 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);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
new file mode 100644
index 00000000000..cdec0f8a931
--- /dev/null
+++ b/gdb/gdbserver/server.c
@@ -0,0 +1,258 @@
+/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "server.h"
+
+int cont_thread;
+int general_thread;
+int thread_from_wait;
+int old_thread_from_wait;
+int extended_protocol;
+jmp_buf toplevel;
+int inferior_pid;
+
+static unsigned char
+start_inferior (argv, statusptr)
+ char *argv[];
+ char *statusptr;
+{
+ inferior_pid = create_inferior (argv[0], argv);
+ fprintf (stderr, "Process %s created; pid = %d\n", argv[0], inferior_pid);
+
+ /* Wait till we are at 1st instruction in program, return signal number. */
+ return mywait (statusptr);
+}
+
+extern int remote_debug;
+
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ char ch, status, own_buf[2000], mem_buf[2000];
+ int i = 0;
+ unsigned char signal;
+ unsigned int len;
+ CORE_ADDR mem_addr;
+
+ if (setjmp(toplevel))
+ {
+ fprintf(stderr, "Exiting\n");
+ exit(1);
+ }
+
+ if (argc < 3)
+ error("Usage: gdbserver tty prog [args ...]");
+
+ /* Wait till we are at first instruction in program. */
+ signal = start_inferior (&argv[2], &status);
+
+ /* We are now stopped at the first instruction of the target process */
+
+ while (1)
+ {
+ remote_open (argv[1]);
+
+restart:
+ setjmp(toplevel);
+ while (getpkt (own_buf) > 0)
+ {
+ unsigned char sig;
+ i = 0;
+ ch = own_buf[i++];
+ switch (ch)
+ {
+ case 'd':
+ remote_debug = !remote_debug;
+ break;
+ case '!':
+ extended_protocol = 1;
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case '?':
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 'H':
+ switch (own_buf[1])
+ {
+ case 'g':
+ general_thread = strtol (&own_buf[2], NULL, 16);
+ write_ok (own_buf);
+ fetch_inferior_registers (0);
+ break;
+ case 'c':
+ cont_thread = strtol (&own_buf[2], NULL, 16);
+ write_ok (own_buf);
+ break;
+ default:
+ /* Silently ignore it so that gdb can extend the protocol
+ without compatibility headaches. */
+ own_buf[0] = '\0';
+ break;
+ }
+ 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':
+ convert_ascii_to_int (own_buf + 1, &sig, 1);
+ myresume (0, sig);
+ signal = mywait (&status);
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 'S':
+ convert_ascii_to_int (own_buf + 1, &sig, 1);
+ myresume (1, sig);
+ signal = mywait (&status);
+ prepare_resume_reply (own_buf, status, signal);
+ 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':
+ fprintf (stderr, "Killing inferior\n");
+ kill_inferior ();
+ /* When using the extended protocol, we start up a new
+ debugging session. The traditional protocol will
+ exit instead. */
+ if (extended_protocol)
+ {
+ write_ok (own_buf);
+ fprintf (stderr, "GDBserver restarting\n");
+
+ /* Wait till we are at 1st instruction in prog. */
+ signal = start_inferior (&argv[2], &status);
+ goto restart;
+ break;
+ }
+ else
+ {
+ exit (0);
+ break;
+ }
+ case 'T':
+ if (mythread_alive (strtol (&own_buf[1], NULL, 16)))
+ write_ok (own_buf);
+ else
+ write_enn (own_buf);
+ break;
+ case 'R':
+ /* Restarting the inferior is only supported in the
+ extended protocol. */
+ if (extended_protocol)
+ {
+ kill_inferior ();
+ write_ok (own_buf);
+ fprintf (stderr, "GDBserver restarting\n");
+
+ /* Wait till we are at 1st instruction in prog. */
+ signal = start_inferior (&argv[2], &status);
+ goto restart;
+ break;
+ }
+ else
+ {
+ /* It is a request we don't understand. Respond with an
+ empty packet so that gdb knows that we don't support this
+ request. */
+ own_buf[0] = '\0';
+ break;
+ }
+ default:
+ /* It is a request we don't understand. Respond with an
+ empty packet so that gdb knows that we don't support this
+ request. */
+ own_buf[0] = '\0';
+ break;
+ }
+
+ putpkt (own_buf);
+
+ if (status == 'W')
+ fprintf (stderr,
+ "\nChild exited with status %d\n", sig);
+ if (status == 'X')
+ fprintf (stderr, "\nChild terminated with signal = 0x%x\n", sig);
+ if (status == 'W' || status == 'X')
+ {
+ if (extended_protocol)
+ {
+ fprintf (stderr, "Killing inferior\n");
+ kill_inferior ();
+ write_ok (own_buf);
+ fprintf (stderr, "GDBserver restarting\n");
+
+ /* Wait till we are at 1st instruction in prog. */
+ signal = start_inferior (&argv[2], &status);
+ goto restart;
+ break;
+ }
+ else
+ {
+ fprintf (stderr, "GDBserver exiting\n");
+ exit (0);
+ }
+ }
+ }
+
+ /* We come here when getpkt fails.
+
+ For the extended remote protocol we exit (and this is the only
+ way we gracefully exit!).
+
+ For the traditional remote protocol close the connection,
+ and re-open it at the top of the loop. */
+ if (extended_protocol)
+ {
+ remote_close ();
+ exit (0);
+ }
+ else
+ {
+ fprintf (stderr, "Remote side has terminated connection. GDBserver will reopen the connection.\n");
+
+ remote_close ();
+ }
+ }
+}
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
new file mode 100644
index 00000000000..e23c773a60b
--- /dev/null
+++ b/gdb/gdbserver/server.h
@@ -0,0 +1,72 @@
+/* Common definitions for remote server for GDB.
+ Copyright (C) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include <setjmp.h>
+
+/* Target-specific functions */
+
+int create_inferior PARAMS ((char *program, char **allargs));
+void kill_inferior PARAMS ((void));
+void fetch_inferior_registers PARAMS ((int regno));
+void store_inferior_registers PARAMS ((int regno));
+int mythread_alive PARAMS ((int pid));
+void myresume PARAMS ((int step, int signo));
+unsigned char mywait PARAMS ((char *status));
+void read_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+int write_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+int create_inferior ();
+
+/* Target-specific variables */
+
+extern char registers[];
+
+/* Public variables in server.c */
+
+extern int cont_thread;
+extern int general_thread;
+extern int thread_from_wait;
+extern int old_thread_from_wait;
+
+extern jmp_buf toplevel;
+extern int inferior_pid;
+
+/* Functions from remote-utils.c */
+
+int putpkt PARAMS ((char *buf));
+int getpkt PARAMS ((char *buf));
+void remote_open PARAMS ((char *name));
+void remote_close PARAMS ((void));
+void write_ok PARAMS ((char *buf));
+void write_enn PARAMS ((char *buf));
+void enable_async_io PARAMS ((void));
+void disable_async_io PARAMS ((void));
+void convert_ascii_to_int PARAMS ((char *from, char *to, int n));
+void convert_int_to_ascii PARAMS ((char *from, char *to, int n));
+void prepare_resume_reply PARAMS ((char *buf, char status, unsigned char sig));
+
+void decode_m_packet PARAMS ((char *from, CORE_ADDR *mem_addr_ptr,
+ unsigned int *len_ptr));
+void decode_M_packet PARAMS ((char *from, CORE_ADDR *mem_addr_ptr,
+ unsigned int *len_ptr, char *to));
+
+
+/* Functions from utils.c */
+
+void perror_with_name PARAMS ((char *string));
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
new file mode 100644
index 00000000000..63d522c95a9
--- /dev/null
+++ b/gdb/gdbserver/utils.c
@@ -0,0 +1,114 @@
+/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "server.h"
+#include <stdio.h>
+#include <string.h>
+
+/* Generally useful subroutines used throughout the program. */
+
+/* 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 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. */
+
+#ifdef ANSI_PROTOTYPES
+NORETURN void
+error (const char *string, ...)
+#else
+void
+error (va_alist)
+ va_dcl
+#endif
+{
+ extern jmp_buf toplevel;
+ va_list args;
+#ifdef ANSI_PROTOTYPES
+ va_start (args, string);
+#else
+ va_start (args);
+#endif
+ fflush (stdout);
+#ifdef ANSI_PROTOTYPES
+ vfprintf (stderr, string, args);
+#else
+ {
+ char *string1;
+
+ string1 = va_arg (args, char *);
+ vfprintf (stderr, string1, args);
+ }
+#endif
+ 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. */
+
+/* VARARGS */
+NORETURN void
+#ifdef ANSI_PROTOTYPES
+fatal (char *string, ...)
+#else
+fatal (va_alist)
+ va_dcl
+#endif
+{
+ va_list args;
+#ifdef ANSI_PROTOTYPES
+ va_start (args, string);
+#else
+ char *string;
+ va_start (args);
+ string = va_arg (args, char *);
+#endif
+ fprintf (stderr, "gdb: ");
+ vfprintf (stderr, string, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+ exit (1);
+}