diff -purN gdb-5.2.1-orig/gdb/gdbserver/Makefile.in gdb-5.2.1/gdb/gdbserver/Makefile.in
--- gdb-5.2.1-orig/gdb/gdbserver/Makefile.in	Fri Mar 29 20:03:33 2002
+++ gdb-5.2.1/gdb/gdbserver/Makefile.in	Tue Sep  2 14:04:40 2003
@@ -90,13 +90,15 @@ INCLUDE_CFLAGS = -I. -I${srcdir} -I$(src
 GLOBAL_CFLAGS = ${MT_CFLAGS} ${MH_CFLAGS}
 #PROFILE_CFLAGS = -pg
 
+WARN_CFLAGS = -Wall
+
 # CFLAGS is specifically reserved for setting from the command line
 # when running make.  I.E.  "make CFLAGS=-Wmissing-prototypes".
 CFLAGS = @CFLAGS@
 
 # INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros.
-INTERNAL_CFLAGS = ${CFLAGS} ${GLOBAL_CFLAGS} ${PROFILE_CFLAGS} \
-	${INCLUDE_CFLAGS} ${BFD_CFLAGS}
+INTERNAL_CFLAGS =  $(WARN_CFLAGS) ${CFLAGS} ${GLOBAL_CFLAGS} \
+	${PROFILE_CFLAGS} ${INCLUDE_CFLAGS} ${BFD_CFLAGS}
 
 # LDFLAGS is specifically reserved for setting from the command line
 # when running make.
@@ -120,7 +122,11 @@ DEPFILES = @GDBSERVER_DEPFILES@
 SOURCES = $(SFILES)
 TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} 
 
-OBS = utils.o $(DEPFILES) server.o remote-utils.o regcache.o signals.o
+OBS = inferiors.o regcache.o remote-utils.o server.o signals.o target.o \
+	utils.o \
+	mem-break.o \
+	$(DEPFILES)
+GDBSERVER_LIBS = @GDBSERVER_LIBS@
 
 # 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.
@@ -195,8 +201,12 @@ maintainer-clean realclean: clean
 
 STAGESTUFF=${OBS} ${TSOBS} ${NTSOBS} ${ADD_FILES} init.c init.o version.c gdb
 
+config.h: stamp-h ; @true
+stamp-h: config.in config.status
+	CONFIG_FILES="" $(SHELL) ./config.status
+
 Makefile: Makefile.in config.status
-	$(SHELL) ./config.status
+	CONFIG_HEADERS="" $(SHELL) ./config.status
 
 config.status: configure configure.srv
 	$(SHELL) ./config.status --recheck
@@ -222,17 +232,24 @@ MAKEOVERRIDES=
 ## with no dependencies and no actions.
 unexport CHILLFLAGS CHILL_LIB CHILL_FOR_TARGET :
 
-regdat_sh = $(srcdir)/../regformats/regdat.sh
-regdef_h = $(srcdir)/../regformats/regdef.h
+gdb_proc_service_h = $(srcdir)/../gdb_proc_service.h $(srcdir)/../gregset.h
+regdat_sh = $(srcdir)/../regformats/regdat.sh
+regdef_h = $(srcdir)/../regformats/regdef.h
 regcache_h = $(srcdir)/regcache.h
-server_h = $(srcdir)/server.h $(regcache_h) config.h
+server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \
+		$(srcdir)/mem-break.h
 
-server.o: server.c $(server_h)
+inferiors.o: inferiors.c $(server_h)
+mem-break.o: mem-break.c $(server_h)
+proc-service.o: proc-service.c $(server_h) $(gdb_proc_service_h)
+regcache.o: regcache.c $(server_h) $(regdef_h)
 remote-utils.o: remote-utils.c terminal.h $(server_h)
+server.o: server.c $(server_h)
+target.o: target.c $(server_h)
+thread-db.o: thread-db.c $(server_h) $(gdb_proc_service_h)
 utils.o: utils.c $(server_h)
-regcache.o: regcache.c $(server_h) $(regdef_h)
 
-signals.o: ../signals/signals.c $(server_h)
+signals.o: ../signals.c $(server_h)
 	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER
 
 i387-fp.o: i387-fp.c $(server_h)
@@ -240,6 +257,8 @@ i387-fp.o: i387-fp.c $(server_h)
 linux_low_h = $(srcdir)/linux-low.h
 
 linux-low.o: linux-low.c $(linux_low_h) $(server_h)
+	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< @USE_THREAD_DB@
+
 linux-arm-low.o: linux-arm-low.c $(linux_low_h) $(server_h)
 linux-i386-low.o: linux-i386-low.c $(linux_low_h) $(server_h)
 linux-ia64-low.o: linux-ia64-low.c $(linux_low_h) $(server_h)
@@ -249,14 +268,6 @@ linux-s390-low.o: linux-s390-low.c $(lin
 linux-sh-low.o: linux-sh-low.c $(linux_low_h) $(server_h)
 linux-x86-64-low.o: linux-x86-64-low.c $(linux_low_h) $(server_h)
 
-# OBSOLETE TARGETS
-# OBSOLETE # low-lynx.o : ${srcdir}/low-lynx.c ${srcdir}/server.h
-# OBSOLETE # low-nbsd.o : ${srcdir}/low-nbsd.c ${srcdir}/server.h
-# OBSOLETE # low-sim.o : ${srcdir}/low-sim.c ${srcdir}/server.h
-# OBSOLETE # low-sparc.o : $(srcdir)/low-sparc.c $(srcdir)/server.h
-# OBSOLETE # low-sun3.o : $(srcdir)/low-sun3.c $(srcdir)/server.h
-# OBSOLETE # low-hppabsd.o : $(srcdir)/low-hppabsd.c $(srcdir)/server.h
-
 reg-arm.o : reg-arm.c $(regdef_h)
 reg-arm.c : $(srcdir)/../regformats/reg-arm.dat $(regdat_sh)
 	sh $(regdat_sh) $(srcdir)/../regformats/reg-arm.dat reg-arm.c
diff -purN gdb-5.2.1-orig/gdb/gdbserver/acconfig.h gdb-5.2.1/gdb/gdbserver/acconfig.h
--- gdb-5.2.1-orig/gdb/gdbserver/acconfig.h	Wed Feb 27 08:07:38 2002
+++ gdb-5.2.1/gdb/gdbserver/acconfig.h	Tue Sep  2 14:04:40 2003
@@ -7,3 +7,18 @@
 /* Define if the target supports PTRACE_GETFPXREGS for extended
    register access.  */
 #undef HAVE_PTRACE_GETFPXREGS
+
+/* Define if <sys/procfs.h> has prgregset_t. */
+#undef HAVE_PRGREGSET_T
+
+/* Define if <sys/procfs.h> has prfpregset_t. */
+#undef HAVE_PRFPREGSET_T
+
+/* Define if <sys/procfs.h> has lwpid_t. */
+#undef HAVE_LWPID_T
+
+/* Define if <sys/procfs.h> has psaddr_t. */
+#undef HAVE_PSADDR_T
+
+/* Define if the prfpregset_t type is broken. */
+#undef PRFPREGSET_T_BROKEN
diff -purN gdb-5.2.1-orig/gdb/gdbserver/acinclude.m4 gdb-5.2.1/gdb/gdbserver/acinclude.m4
--- gdb-5.2.1-orig/gdb/gdbserver/acinclude.m4	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/acinclude.m4	Tue Sep  2 14:04:40 2003
@@ -0,0 +1,41 @@
+dnl gdb/gdbserver/configure.in uses BFD_HAVE_SYS_PROCFS_TYPE.
+sinclude(../../bfd/acinclude.m4)
+
+AC_DEFUN([SRV_CHECK_THREAD_DB],
+[AC_CACHE_CHECK([for libthread_db],[srv_cv_thread_db],
+ [old_LIBS="$LIBS"
+  LIBS="$LIBS -lthread_db"
+  AC_TRY_LINK(
+  [void ps_pglobal_lookup() {}
+   void ps_pdread() {}
+   void ps_pdwrite() {}
+   void ps_lgetregs() {}
+   void ps_lsetregs() {}
+   void ps_lgetfpregs() {}
+   void ps_lsetfpregs() {}
+   void ps_getpid() {}],
+  [td_ta_new();],
+  [srv_cv_thread_db="-lthread_db"],
+  [srv_cv_thread_db=no
+
+ if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
+  thread_db="/lib/libthread_db.so.1"
+ else
+  thread_db='$prefix/lib/libthread_db.so.1'
+ fi
+ LIBS="$old_LIBS `eval echo "$thread_db"`"
+ AC_TRY_LINK(
+  [void ps_pglobal_lookup() {}
+   void ps_pdread() {}
+   void ps_pdwrite() {}
+   void ps_lgetregs() {}
+   void ps_lsetregs() {}
+   void ps_lgetfpregs() {}
+   void ps_lsetfpregs() {}
+   void ps_getpid() {}],
+  [td_ta_new();],
+  [srv_cv_thread_db="$thread_db"],
+  [srv_cv_thread_db=no])
+ LIBS="$old_LIBS"
+ ]])
+)])
diff -purN gdb-5.2.1-orig/gdb/gdbserver/aclocal.m4 gdb-5.2.1/gdb/gdbserver/aclocal.m4
--- gdb-5.2.1-orig/gdb/gdbserver/aclocal.m4	Wed Feb 20 00:48:14 2002
+++ gdb-5.2.1/gdb/gdbserver/aclocal.m4	Tue Sep  2 14:04:40 2003
@@ -1,6 +1,6 @@
-dnl aclocal.m4 generated automatically by aclocal 1.4-p4
+dnl aclocal.m4 generated automatically by aclocal 1.4-p5
 
-dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
@@ -10,91 +10,45 @@ dnl but WITHOUT ANY WARRANTY, to the ext
 dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 dnl PARTICULAR PURPOSE.
 
+dnl gdb/gdbserver/configure.in uses BFD_HAVE_SYS_PROCFS_TYPE.
+sinclude(../../bfd/acinclude.m4)
 
-# serial 1
-
-# @defmac AC_PROG_CC_STDC
-# @maindex PROG_CC_STDC
-# @ovindex CC
-# If the C compiler in not in ANSI C mode by default, try to add an option
-# to output variable @code{CC} to make it so.  This macro tries various
-# options that select ANSI C on some system or another.  It considers the
-# compiler to be in ANSI C mode if it handles function prototypes correctly.
-#
-# If you use this macro, you should check after calling it whether the C
-# compiler has been set to accept ANSI C; if not, the shell variable
-# @code{am_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
-# code in ANSI C, you can make an un-ANSIfied copy of it by using the
-# program @code{ansi2knr}, which comes with Ghostscript.
-# @end defmac
-
-AC_DEFUN(AM_PROG_CC_STDC,
-[AC_REQUIRE([AC_PROG_CC])
-AC_BEFORE([$0], [AC_C_INLINE])
-AC_BEFORE([$0], [AC_C_CONST])
-dnl Force this before AC_PROG_CPP.  Some cpp's, eg on HPUX, require
-dnl a magic option to avoid problems with ANSI preprocessor commands
-dnl like #elif.
-dnl FIXME: can't do this because then AC_AIX won't work due to a
-dnl circular dependency.
-dnl AC_BEFORE([$0], [AC_PROG_CPP])
-AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
-AC_CACHE_VAL(am_cv_prog_cc_stdc,
-[am_cv_prog_cc_stdc=no
-ac_save_CC="$CC"
-# Don't try gcc -ansi; that turns off useful extensions and
-# breaks some systems' header files.
-# AIX			-qlanglvl=ansi
-# Ultrix and OSF/1	-std1
-# HP-UX			-Aa -D_HPUX_SOURCE
-# SVR4			-Xc -D__EXTENSIONS__
-for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
-  CC="$ac_save_CC $ac_arg"
-  AC_TRY_COMPILE(
-[#include <stdarg.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
-     char **p;
-     int i;
-{
-  return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
-  char *s;
-  va_list v;
-  va_start (v,p);
-  s = g (p, va_arg (v,int));
-  va_end (v);
-  return s;
-}
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-], [
-return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
-],
-[am_cv_prog_cc_stdc="$ac_arg"; break])
-done
-CC="$ac_save_CC"
-])
-if test -z "$am_cv_prog_cc_stdc"; then
-  AC_MSG_RESULT([none needed])
-else
-  AC_MSG_RESULT($am_cv_prog_cc_stdc)
-fi
-case "x$am_cv_prog_cc_stdc" in
-  x|xno) ;;
-  *) CC="$CC $am_cv_prog_cc_stdc" ;;
-esac
-])
+AC_DEFUN([SRV_CHECK_THREAD_DB],
+[AC_CACHE_CHECK([for libthread_db],[srv_cv_thread_db],
+ [old_LIBS="$LIBS"
+  LIBS="$LIBS -lthread_db"
+  AC_TRY_LINK(
+  [void ps_pglobal_lookup() {}
+   void ps_pdread() {}
+   void ps_pdwrite() {}
+   void ps_lgetregs() {}
+   void ps_lsetregs() {}
+   void ps_lgetfpregs() {}
+   void ps_lsetfpregs() {}
+   void ps_getpid() {}],
+  [td_ta_new();],
+  [srv_cv_thread_db="-lthread_db"],
+  [srv_cv_thread_db=no
+
+ if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
+  thread_db="/lib/libthread_db.so.1"
+ else
+  thread_db='$prefix/lib/libthread_db.so.1'
+ fi
+ LIBS="$old_LIBS `eval echo "$thread_db"`"
+ AC_TRY_LINK(
+  [void ps_pglobal_lookup() {}
+   void ps_pdread() {}
+   void ps_pdwrite() {}
+   void ps_lgetregs() {}
+   void ps_lsetregs() {}
+   void ps_lgetfpregs() {}
+   void ps_lsetfpregs() {}
+   void ps_getpid() {}],
+  [td_ta_new();],
+  [srv_cv_thread_db="$thread_db"],
+  [srv_cv_thread_db=no])
+ LIBS="$old_LIBS"
+ ]])
+)])
 
diff -purN gdb-5.2.1-orig/gdb/gdbserver/config.in gdb-5.2.1/gdb/gdbserver/config.in
--- gdb-5.2.1-orig/gdb/gdbserver/config.in	Wed Feb 27 08:07:38 2002
+++ gdb-5.2.1/gdb/gdbserver/config.in	Tue Sep  2 14:04:40 2003
@@ -1,4 +1,4 @@
-/* config.in.  Generated automatically from configure.in by autoheader 2.13.  */
+/* config.in.  Generated automatically from configure.in by autoheader.  */
 
 /* Define if you have the ANSI C header files.  */
 #undef STDC_HEADERS
@@ -13,9 +13,24 @@
    register access.  */
 #undef HAVE_PTRACE_GETFPXREGS
 
+/* Define if the prfpregset_t type is broken. */
+#undef PRFPREGSET_T_BROKEN
+
+/* Define if you have the <linux/elf.h> header file.  */
+#undef HAVE_LINUX_ELF_H
+
+/* Define if you have the <proc_service.h> header file.  */
+#undef HAVE_PROC_SERVICE_H
+
 /* Define if you have the <sgtty.h> header file.  */
 #undef HAVE_SGTTY_H
 
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/procfs.h> header file.  */
+#undef HAVE_SYS_PROCFS_H
+
 /* Define if you have the <sys/reg.h> header file.  */
 #undef HAVE_SYS_REG_H
 
@@ -24,3 +39,25 @@
 
 /* Define if you have the <termios.h> header file.  */
 #undef HAVE_TERMIOS_H
+
+/* Define if you have the <thread_db.h> header file.  */
+#undef HAVE_THREAD_DB_H
+
+/* Define if <sys/procfs.h> has lwpid_t. */
+#undef HAVE_LWPID_T
+
+/* Define if <sys/procfs.h> has psaddr_t. */
+#undef HAVE_PSADDR_T
+
+/* Define if <sys/procfs.h> has prgregset_t. */
+#undef HAVE_PRGREGSET_T
+
+/* Define if <sys/procfs.h> has prfpregset_t. */
+#undef HAVE_PRFPREGSET_T
+
+/* Define if <sys/procfs.h> has elf_fpregset_t. */
+#undef HAVE_ELF_FPREGSET_T
+
+#undef HAVE_TARGET_ATTACH
+
+#undef HAVE_TARGET_SHELL
diff -purN gdb-5.2.1-orig/gdb/gdbserver/configure gdb-5.2.1/gdb/gdbserver/configure
--- gdb-5.2.1-orig/gdb/gdbserver/configure	Wed Feb 27 08:07:38 2002
+++ gdb-5.2.1/gdb/gdbserver/configure	Tue Sep  2 14:04:41 2003
@@ -1105,7 +1105,7 @@ EOF
 fi
 
 
-for ac_hdr in sgtty.h termio.h termios.h sys/reg.h
+for ac_hdr in sgtty.h termio.h termios.h sys/reg.h string.h                 proc_service.h sys/procfs.h thread_db.h linux/elf.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
@@ -1223,7 +1223,333 @@ EOF
   fi
 fi
 
-GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj"
+if test "$ac_cv_header_sys_procfs_h" = yes; then
+  echo $ac_n "checking for lwpid_t in sys/procfs.h""... $ac_c" 1>&6
+echo "configure:1229: checking for lwpid_t in sys/procfs.h" >&5
+ if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_lwpid_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1234 "configure"
+#include "confdefs.h"
+
+#define _SYSCALL32
+#include <sys/procfs.h>
+int main() {
+lwpid_t avar
+; return 0; }
+EOF
+if { (eval echo configure:1243: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_lwpid_t=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_lwpid_t=no
+   
+fi
+rm -f conftest*
+fi
+
+ if test $bfd_cv_have_sys_procfs_type_lwpid_t = yes; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_LWPID_T 1
+EOF
+
+ fi
+ echo "$ac_t""$bfd_cv_have_sys_procfs_type_lwpid_t" 1>&6
+
+  echo $ac_n "checking for psaddr_t in sys/procfs.h""... $ac_c" 1>&6
+echo "configure:1265: checking for psaddr_t in sys/procfs.h" >&5
+ if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_psaddr_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1270 "configure"
+#include "confdefs.h"
+
+#define _SYSCALL32
+#include <sys/procfs.h>
+int main() {
+psaddr_t avar
+; return 0; }
+EOF
+if { (eval echo configure:1279: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_psaddr_t=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_psaddr_t=no
+   
+fi
+rm -f conftest*
+fi
+
+ if test $bfd_cv_have_sys_procfs_type_psaddr_t = yes; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_PSADDR_T 1
+EOF
+
+ fi
+ echo "$ac_t""$bfd_cv_have_sys_procfs_type_psaddr_t" 1>&6
+
+  echo $ac_n "checking for prgregset_t in sys/procfs.h""... $ac_c" 1>&6
+echo "configure:1301: checking for prgregset_t in sys/procfs.h" >&5
+ if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_prgregset_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1306 "configure"
+#include "confdefs.h"
+
+#define _SYSCALL32
+#include <sys/procfs.h>
+int main() {
+prgregset_t avar
+; return 0; }
+EOF
+if { (eval echo configure:1315: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_prgregset_t=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_prgregset_t=no
+   
+fi
+rm -f conftest*
+fi
+
+ if test $bfd_cv_have_sys_procfs_type_prgregset_t = yes; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_PRGREGSET_T 1
+EOF
+
+ fi
+ echo "$ac_t""$bfd_cv_have_sys_procfs_type_prgregset_t" 1>&6
+
+  echo $ac_n "checking for prfpregset_t in sys/procfs.h""... $ac_c" 1>&6
+echo "configure:1337: checking for prfpregset_t in sys/procfs.h" >&5
+ if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_prfpregset_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1342 "configure"
+#include "confdefs.h"
+
+#define _SYSCALL32
+#include <sys/procfs.h>
+int main() {
+prfpregset_t avar
+; return 0; }
+EOF
+if { (eval echo configure:1351: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_prfpregset_t=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_prfpregset_t=no
+   
+fi
+rm -f conftest*
+fi
+
+ if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_PRFPREGSET_T 1
+EOF
+
+ fi
+ echo "$ac_t""$bfd_cv_have_sys_procfs_type_prfpregset_t" 1>&6
+
+
+  
+        
+  if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then
+    echo $ac_n "checking whether prfpregset_t type is broken""... $ac_c" 1>&6
+echo "configure:1377: checking whether prfpregset_t type is broken" >&5
+    if eval "test \"`echo '$''{'gdb_cv_prfpregset_t_broken'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  gdb_cv_prfpregset_t_broken=yes
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1385 "configure"
+#include "confdefs.h"
+#include <sys/procfs.h>
+       int main ()
+       {
+         if (sizeof (prfpregset_t) == sizeof (void *))
+           return 1;
+         return 0;
+       }
+EOF
+if { (eval echo configure:1395: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  gdb_cv_prfpregset_t_broken=no
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  gdb_cv_prfpregset_t_broken=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+
+    echo "$ac_t""$gdb_cv_prfpregset_t_broken" 1>&6
+    if test $gdb_cv_prfpregset_t_broken = yes; then
+      cat >> confdefs.h <<\EOF
+#define PRFPREGSET_T_BROKEN 1
+EOF
+
+    fi
+  fi
+
+  echo $ac_n "checking for elf_fpregset_t in sys/procfs.h""... $ac_c" 1>&6
+echo "configure:1419: checking for elf_fpregset_t in sys/procfs.h" >&5
+ if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_elf_fpregset_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1424 "configure"
+#include "confdefs.h"
+
+#define _SYSCALL32
+#include <sys/procfs.h>
+int main() {
+elf_fpregset_t avar
+; return 0; }
+EOF
+if { (eval echo configure:1433: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_elf_fpregset_t=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  bfd_cv_have_sys_procfs_type_elf_fpregset_t=no
+   
+fi
+rm -f conftest*
+fi
+
+ if test $bfd_cv_have_sys_procfs_type_elf_fpregset_t = yes; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_ELF_FPREGSET_T 1
+EOF
+
+ fi
+ echo "$ac_t""$bfd_cv_have_sys_procfs_type_elf_fpregset_t" 1>&6
+
+fi
+
+srv_thread_depfiles=
+srv_libs=
+USE_THREAD_DB=
+
+if test "$srv_linux_thread_db" = "yes"; then
+  echo $ac_n "checking for libthread_db""... $ac_c" 1>&6
+echo "configure:1462: checking for libthread_db" >&5
+if eval "test \"`echo '$''{'srv_cv_thread_db'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  old_LIBS="$LIBS"
+  LIBS="$LIBS -lthread_db"
+  cat > conftest.$ac_ext <<EOF
+#line 1469 "configure"
+#include "confdefs.h"
+void ps_pglobal_lookup() {}
+   void ps_pdread() {}
+   void ps_pdwrite() {}
+   void ps_lgetregs() {}
+   void ps_lsetregs() {}
+   void ps_lgetfpregs() {}
+   void ps_lsetfpregs() {}
+   void ps_getpid() {}
+int main() {
+td_ta_new();
+; return 0; }
+EOF
+if { (eval echo configure:1483: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  srv_cv_thread_db="-lthread_db"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  srv_cv_thread_db=no
+
+ if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
+  thread_db="/lib/libthread_db.so.1"
+ else
+  thread_db='$prefix/lib/libthread_db.so.1'
+ fi
+ LIBS="$old_LIBS `eval echo "$thread_db"`"
+ cat > conftest.$ac_ext <<EOF
+#line 1499 "configure"
+#include "confdefs.h"
+void ps_pglobal_lookup() {}
+   void ps_pdread() {}
+   void ps_pdwrite() {}
+   void ps_lgetregs() {}
+   void ps_lsetregs() {}
+   void ps_lgetfpregs() {}
+   void ps_lsetfpregs() {}
+   void ps_getpid() {}
+int main() {
+td_ta_new();
+; return 0; }
+EOF
+if { (eval echo configure:1513: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  srv_cv_thread_db="$thread_db"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  srv_cv_thread_db=no
+fi
+rm -f conftest*
+ LIBS="$old_LIBS"
+ 
+fi
+
+echo "$ac_t""$srv_cv_thread_db" 1>&6
+
+fi
+rm -f conftest*
+  if test "$srv_cv_thread_db" = no; then
+    echo "configure: warning: Could not find libthread_db." 1>&2
+    echo "configure: warning: Disabling thread support in gdbserver." 1>&2
+    srv_linux_thread_db=no
+  else
+    srv_libs="$srv_cv_thread_db"
+  fi
+fi
+
+if test "$srv_linux_thread_db" = "yes"; then
+  srv_thread_depfiles="thread-db.o proc-service.o"
+  USE_THREAD_DB="-DUSE_THREAD_DB"
+fi
+
+cat >> confdefs.h <<\EOF
+#define HAVE_TARGET_ATTACH 1
+#define HAVE_TARGET_SHELL 1
+EOF
+
+GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_thread_depfiles"
+GDBSERVER_LIBS="$srv_libs"
+
+
 
 
 
@@ -1381,6 +1707,8 @@ s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
 s%@INSTALL_DATA@%$INSTALL_DATA%g
 s%@CPP@%$CPP%g
 s%@GDBSERVER_DEPFILES@%$GDBSERVER_DEPFILES%g
+s%@GDBSERVER_LIBS@%$GDBSERVER_LIBS%g
+s%@USE_THREAD_DB@%$USE_THREAD_DB%g
 
 CEOF
 EOF
@@ -1593,6 +1921,10 @@ cat >> $CONFIG_STATUS <<EOF
 
 EOF
 cat >> $CONFIG_STATUS <<\EOF
+case x$CONFIG_HEADERS in
+xconfig.h:config.in)
+echo > stamp-h ;;
+esac
 
 exit 0
 EOF
diff -purN gdb-5.2.1-orig/gdb/gdbserver/configure.in gdb-5.2.1/gdb/gdbserver/configure.in
--- gdb-5.2.1-orig/gdb/gdbserver/configure.in	Wed Feb 27 08:07:38 2002
+++ gdb-5.2.1/gdb/gdbserver/configure.in	Tue Sep  2 14:04:41 2003
@@ -30,7 +30,8 @@ AC_PROG_INSTALL
 
 AC_HEADER_STDC
 
-AC_CHECK_HEADERS(sgtty.h termio.h termios.h sys/reg.h)
+AC_CHECK_HEADERS(sgtty.h termio.h termios.h sys/reg.h string.h dnl
+                proc_service.h sys/procfs.h thread_db.h linux/elf.h)
 
 . ${srcdir}/configure.srv
 
@@ -62,8 +63,71 @@ if test "${srv_linux_regsets}" = "yes"; 
   fi
 fi
 
-GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj"
+if test "$ac_cv_header_sys_procfs_h" = yes; then
+  BFD_HAVE_SYS_PROCFS_TYPE(lwpid_t)
+  BFD_HAVE_SYS_PROCFS_TYPE(psaddr_t)
+  BFD_HAVE_SYS_PROCFS_TYPE(prgregset_t)
+  BFD_HAVE_SYS_PROCFS_TYPE(prfpregset_t)
+
+  dnl Check for broken prfpregset_t type
+
+  dnl For Linux/i386, glibc 2.1.3 was released with a bogus
+  dnl prfpregset_t type (it's a typedef for the pointer to a struct
+  dnl instead of the struct itself).  We detect this here, and work
+  dnl around it in gdb_proc_service.h.
+
+  if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then
+    AC_MSG_CHECKING(whether prfpregset_t type is broken)
+    AC_CACHE_VAL(gdb_cv_prfpregset_t_broken,
+      [AC_TRY_RUN([#include <sys/procfs.h>
+       int main ()
+       {
+         if (sizeof (prfpregset_t) == sizeof (void *))
+           return 1;
+         return 0;
+       }],
+       gdb_cv_prfpregset_t_broken=no,
+       gdb_cv_prfpregset_t_broken=yes,
+       gdb_cv_prfpregset_t_broken=yes)])
+    AC_MSG_RESULT($gdb_cv_prfpregset_t_broken)
+    if test $gdb_cv_prfpregset_t_broken = yes; then
+      AC_DEFINE(PRFPREGSET_T_BROKEN)
+    fi
+  fi
+
+  BFD_HAVE_SYS_PROCFS_TYPE(elf_fpregset_t)
+fi
+
+srv_thread_depfiles=
+srv_libs=
+USE_THREAD_DB=
+
+if test "$srv_linux_thread_db" = "yes"; then
+  SRV_CHECK_THREAD_DB
+  if test "$srv_cv_thread_db" = no; then
+    AC_WARN([Could not find libthread_db.])
+    AC_WARN([Disabling thread support in gdbserver.])
+    srv_linux_thread_db=no
+  else
+    srv_libs="$srv_cv_thread_db"
+  fi
+fi
+
+if test "$srv_linux_thread_db" = "yes"; then
+  srv_thread_depfiles="thread-db.o proc-service.o"
+  USE_THREAD_DB="-DUSE_THREAD_DB"
+fi
+
+GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_thread_depfiles"
+GDBSERVER_LIBS="$srv_libs"
 
 AC_SUBST(GDBSERVER_DEPFILES)
+AC_SUBST(GDBSERVER_LIBS)
+AC_SUBST(USE_THREAD_DB)
 
-AC_OUTPUT(Makefile)
+AC_OUTPUT(Makefile,
+[case x$CONFIG_HEADERS in
+xconfig.h:config.in)
+echo > stamp-h ;;
+esac
+])
diff -purN gdb-5.2.1-orig/gdb/gdbserver/configure.srv gdb-5.2.1/gdb/gdbserver/configure.srv
--- gdb-5.2.1-orig/gdb/gdbserver/configure.srv	Thu Feb 28 17:58:14 2002
+++ gdb-5.2.1/gdb/gdbserver/configure.srv	Tue Sep  2 14:04:41 2003
@@ -21,11 +21,13 @@ case "${target}" in
   arm*-*-linux*)	srv_regobj=reg-arm.o
 			srv_tgtobj="linux-low.o linux-arm-low.o"
 			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
 			;;
   i[3456]86-*-linux*)	srv_regobj=reg-i386-linux.o
 			srv_tgtobj="linux-low.o linux-i386-low.o i387-fp.o"
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
+			srv_linux_thread_db=yes
 			;;
   ia64-*-linux*)	srv_regobj=reg-ia64.o
 			srv_tgtobj="linux-low.o linux-ia64-low.o"
@@ -38,10 +40,12 @@ case "${target}" in
   mips*-*-linux*)	srv_regobj=reg-mips.o
 			srv_tgtobj="linux-low.o linux-mips-low.o"
 			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
 			;;
   powerpc*-*-linux*)	srv_regobj=reg-ppc.o
 			srv_tgtobj="linux-low.o linux-ppc-low.o"
 			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
 			;;
   s390-*-linux*)	srv_regobj=reg-s390.o
 			srv_tgtobj="linux-low.o linux-s390-low.o"
@@ -54,6 +58,7 @@ case "${target}" in
   sh*-*-linux*)		srv_regobj=reg-sh.o
 			srv_tgtobj="linux-low.o linux-sh-low.o"
 			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
 			;;
   x86_64-*-linux*)	srv_regobj=reg-x86-64.o
 			srv_tgtobj="linux-low.o linux-x86-64-low.o i387-fp.o"
@@ -63,3 +68,4 @@ case "${target}" in
 			exit 1
 			;;
 esac
+
diff -purN gdb-5.2.1-orig/gdb/gdbserver/i387-fp.c gdb-5.2.1/gdb/gdbserver/i387-fp.c
--- gdb-5.2.1-orig/gdb/gdbserver/i387-fp.c	Wed Feb 27 08:07:38 2002
+++ gdb-5.2.1/gdb/gdbserver/i387-fp.c	Tue Sep  2 14:04:41 2003
@@ -20,6 +20,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
+#include "i387-fp.h"
 
 int num_xmm_registers = 8;
 
@@ -108,7 +109,7 @@ i387_cache_to_fsave (void *buf)
 }
 
 void
-i387_fsave_to_cache (void *buf)
+i387_fsave_to_cache (const void *buf)
 {
   struct i387_fsave *fp = (struct i387_fsave *) buf;
   int i;
@@ -240,7 +241,7 @@ i387_ftag (struct i387_fxsave *fp, int r
 }
 
 void
-i387_fxsave_to_cache (void *buf)
+i387_fxsave_to_cache (const void *buf)
 {
   struct i387_fxsave *fp = (struct i387_fxsave *) buf;
   int i, top;
@@ -287,4 +288,3 @@ i387_fxsave_to_cache (void *buf)
   val = (fp->fop) & 0x7FF;
   supply_register_by_name ("fop", &val);
 }
-
diff -purN gdb-5.2.1-orig/gdb/gdbserver/i387-fp.h gdb-5.2.1/gdb/gdbserver/i387-fp.h
--- gdb-5.2.1-orig/gdb/gdbserver/i387-fp.h	Wed Feb 27 08:07:38 2002
+++ gdb-5.2.1/gdb/gdbserver/i387-fp.h	Tue Sep  2 14:04:41 2003
@@ -23,10 +23,10 @@
 #define I387_FP_H
 
 void i387_cache_to_fsave (void *buf);
-void i387_fsave_to_cache (void *buf);
+void i387_fsave_to_cache (const void *buf);
 
 void i387_cache_to_fxsave (void *buf);
-void i387_fxsave_to_cache (void *buf);
+void i387_fxsave_to_cache (const void *buf);
 
 extern int num_xmm_registers;
 
diff -purN gdb-5.2.1-orig/gdb/gdbserver/inferiors.c gdb-5.2.1/gdb/gdbserver/inferiors.c
--- gdb-5.2.1-orig/gdb/gdbserver/inferiors.c	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/inferiors.c	Tue Sep  2 14:04:41 2003
@@ -0,0 +1,214 @@
+/* Inferior process information for the remote server for GDB.
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   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 <stdlib.h>
+
+#include "server.h"
+
+struct thread_info
+{
+  struct inferior_list_entry entry;
+  void *target_data;
+  void *regcache_data;
+};
+
+struct inferior_list all_threads;
+
+struct thread_info *current_inferior;
+
+#define get_thread(inf) ((struct thread_info *)(inf))
+#define get_process(inf) ((struct process_info *)(inf))
+
+void
+add_inferior_to_list (struct inferior_list *list,
+                     struct inferior_list_entry *new_inferior)
+{
+  new_inferior->next = NULL;
+  if (list->tail != NULL)
+    list->tail->next = new_inferior;
+  else
+    list->head = new_inferior;
+  list->tail = new_inferior;
+}
+
+void
+for_each_inferior (struct inferior_list *list,
+                  void (*action) (struct inferior_list_entry *))
+{
+  struct inferior_list_entry *cur = list->head, *next;
+
+  while (cur != NULL)
+    {
+      next = cur->next;
+      (*action) (cur);
+      cur = next;
+    }
+}
+
+void
+change_inferior_id (struct inferior_list *list,
+                   int new_id)
+{
+  if (list->head != list->tail)
+    error ("tried to change thread ID after multiple threads are created");
+
+  list->head->id = new_id;
+}
+
+
+void
+remove_inferior (struct inferior_list *list,
+                struct inferior_list_entry *entry)
+{
+  struct inferior_list_entry **cur;
+  if (list->head == entry)
+    {
+      list->head = entry->next;
+      if (list->tail == entry)
+       list->tail = list->head;
+      return;
+    }
+
+  cur = &list->head;
+  while (*cur && (*cur)->next != entry)
+    cur = &(*cur)->next;
+
+  if (*cur == NULL)
+    return;
+
+  (*cur)->next = entry->next;
+
+  if (list->tail == entry)
+    list->tail = *cur;
+}
+
+void
+add_thread (int thread_id, void *target_data)
+{
+  struct thread_info *new_thread
+    = (struct thread_info *) malloc (sizeof (*new_thread));
+
+  memset (new_thread, 0, sizeof (*new_thread));
+
+  new_thread->entry.id = thread_id;
+
+  add_inferior_to_list (&all_threads, & new_thread->entry);
+
+  if (current_inferior == NULL)
+    current_inferior = new_thread;
+
+  new_thread->target_data = target_data;
+  set_inferior_regcache_data (new_thread, new_register_cache ());
+}
+
+static void
+free_one_thread (struct inferior_list_entry *inf)
+{
+  struct thread_info *thread = get_thread (inf);
+  free_register_cache (inferior_regcache_data (thread));
+  free (thread);
+}
+
+
+static void
+free_one_process (struct inferior_list_entry *inf)
+{
+  struct process_info *proc = get_process (inf);
+  free (proc);
+}
+
+
+void
+remove_thread (struct thread_info *thread)
+{
+  remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
+  free_one_thread (&thread->entry);
+}
+
+void
+clear_inferiors (void)
+{
+  extern struct inferior_list all_processes;
+
+  for_each_inferior (&all_threads, free_one_thread);
+
+  all_threads.head = all_threads.tail = NULL;
+#ifdef HAVE_TARGET_ATTACH
+  for_each_inferior (&all_processes, free_one_process);
+  all_processes.head = all_processes.tail = NULL;
+#endif
+}
+
+struct inferior_list_entry *
+find_inferior (struct inferior_list *list,
+              int (*func) (struct inferior_list_entry *, void *), void *arg)
+{
+  struct inferior_list_entry *inf = list->head;
+
+  while (inf != NULL)
+    {
+      if ((*func) (inf, arg))
+       return inf;
+      inf = inf->next;
+    }
+
+  return NULL;
+}
+
+struct inferior_list_entry *
+find_inferior_id (struct inferior_list *list, int id)
+{
+  struct inferior_list_entry *inf = list->head;
+
+  while (inf != NULL)
+    {
+      if (inf->id == id)
+       return inf;
+      inf = inf->next;
+    }
+  return NULL;
+}
+
+void *
+inferior_target_data (struct thread_info *inferior)
+{
+  return inferior->target_data;
+}
+
+void
+set_inferior_target_data (struct thread_info *inferior, void *data)
+{
+  inferior->target_data = data;
+}
+
+void *
+inferior_regcache_data (struct thread_info *inferior)
+{
+  return inferior->regcache_data;
+}
+
+void
+set_inferior_regcache_data (struct thread_info *inferior, void *data)
+{
+  inferior->regcache_data = data;
+}
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-arm-low.c gdb-5.2.1/gdb/gdbserver/linux-arm-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-arm-low.c	Wed Feb 27 08:07:39 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-arm-low.c	Tue Sep  2 14:04:41 2003
@@ -26,22 +26,68 @@
 #include <sys/reg.h>
 #endif
 
-int num_regs = 16;
+#define arm_num_regs 16
 
-int regmap[] = {
+static int arm_regmap[] = {
   0, 4, 8, 12, 16, 20, 24, 28,
   32, 36, 40, 44, 48, 52, 56, 60,
 };
 
-int
-cannot_store_register (int regno)
+static int
+arm_cannot_store_register (int regno)
 {
-  return (regno >= num_regs);
+  return (regno >= arm_num_regs);
 }
 
-int
-cannot_fetch_register (int regno)
+static int
+arm_cannot_fetch_register (int regno)
 {
-  return (regno >= num_regs);
+  return (regno >= arm_num_regs);
 }
 
+static CORE_ADDR
+arm_get_pc ()
+{
+  unsigned long pc;
+  collect_register_by_name ("pc", &pc);
+  return pc;
+}
+
+static void
+arm_set_pc (CORE_ADDR pc)
+{
+  unsigned long newpc = pc;
+  supply_register_by_name ("pc", &newpc);
+}
+
+/* Correct in either endianness.  We do not support Thumb yet.  */
+static const unsigned long arm_breakpoint = 0xef9f0001;
+#define arm_breakpoint_len 4
+
+static int
+arm_breakpoint_at (CORE_ADDR where)
+{
+  unsigned long insn;
+
+  (*the_target->read_memory) (where, (char *) &insn, 4);
+  if (insn == arm_breakpoint)
+    return 1;
+
+  /* If necessary, recognize more trap instructions here.  GDB only uses the
+     one.  */
+  return 0;
+}
+
+struct linux_target_ops the_low_target = {
+  arm_num_regs,
+  arm_regmap,
+  arm_cannot_fetch_register,
+  arm_cannot_store_register,
+  arm_get_pc,
+  arm_set_pc,
+  (const char *) &arm_breakpoint,
+  arm_breakpoint_len,
+  NULL,
+  0,
+  arm_breakpoint_at,
+};
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-i386-low.c gdb-5.2.1/gdb/gdbserver/linux-i386-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-i386-low.c	Wed Feb 27 08:07:39 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-i386-low.c	Tue Sep  2 14:04:41 2003
@@ -29,13 +29,13 @@
 
 /* This module only supports access to the general purpose registers.  */
 
-int num_regs = 16;
+#define i386_num_regs 16
 
 /* This stuff comes from i386-linux-nat.c.  */
 
 /* Mapping between the general-purpose registers in `struct user'
    format and GDB's register array layout.  */
-int regmap[] = 
+static int i386_regmap[] = 
 {
   EAX * 4, ECX * 4, EDX * 4, EBX * 4,
   UESP * 4, EBP * 4, ESI * 4, EDI * 4,
@@ -43,16 +43,16 @@ int regmap[] = 
   DS * 4, ES * 4, FS * 4, GS * 4
 };
 
-int
-cannot_store_register (int regno)
+static int
+i386_cannot_store_register (int regno)
 {
-  return (regno >= num_regs);
+  return (regno >= i386_num_regs);
 }
 
-int
-cannot_fetch_register (int regno)
+static int
+i386_cannot_fetch_register (int regno)
 {
-  return (regno >= num_regs);
+  return (regno >= i386_num_regs);
 }
 
 
@@ -65,19 +65,19 @@ i386_fill_gregset (void *buf)
 {
   int i;
 
-  for (i = 0; i < num_regs; i++)
-    collect_register (i, ((char *) buf) + regmap[i]);
+  for (i = 0; i < i386_num_regs; i++)
+    collect_register (i, ((char *) buf) + i386_regmap[i]);
 
   collect_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4);
 }
 
 static void
-i386_store_gregset (void *buf)
+i386_store_gregset (const void *buf)
 {
   int i;
 
-  for (i = 0; i < num_regs; i++)
-    supply_register (i, ((char *) buf) + regmap[i]);
+  for (i = 0; i < i386_num_regs; i++)
+    supply_register (i, ((char *) buf) + i386_regmap[i]);
 
   supply_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4);
 }
@@ -89,7 +89,7 @@ i386_fill_fpregset (void *buf)
 }
 
 static void
-i386_store_fpregset (void *buf)
+i386_store_fpregset (const void *buf)
 {
   i387_fsave_to_cache (buf);
 }
@@ -101,7 +101,7 @@ i386_fill_fpxregset (void *buf)
 }
 
 static void
-i386_store_fpxregset (void *buf)
+i386_store_fpxregset (const void *buf)
 {
   i387_fxsave_to_cache (buf);
 }
@@ -109,15 +109,68 @@ i386_store_fpxregset (void *buf)
 
 struct regset_info target_regsets[] = {
   { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
+    GENERAL_REGS,
     i386_fill_gregset, i386_store_gregset },
 #ifdef HAVE_PTRACE_GETFPXREGS
   { PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, sizeof (elf_fpxregset_t),
+    EXTENDED_REGS,
     i386_fill_fpxregset, i386_store_fpxregset },
 #endif
   { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
+    FP_REGS,
     i386_fill_fpregset, i386_store_fpregset },
-  { 0, 0, -1, NULL, NULL }
+  { 0, 0, -1, -1, NULL, NULL }
 };
 
 #endif /* HAVE_LINUX_REGSETS */
 
+static const char i386_breakpoint[] = { 0xCC };
+#define i386_breakpoint_len 1
+
+extern int debug_threads;
+
+static CORE_ADDR
+i386_get_pc ()
+{
+  unsigned long pc;
+
+  collect_register_by_name ("eip", &pc);
+
+  if (debug_threads)
+    fprintf (stderr, "stop pc (before any decrement) is %08lx\n", pc);
+  return pc;
+}
+
+static void
+i386_set_pc (CORE_ADDR newpc)
+{
+  if (debug_threads)
+    fprintf (stderr, "set pc to %08lx\n", (long) newpc);
+  supply_register_by_name ("eip", &newpc);
+}
+
+static int
+i386_breakpoint_at (CORE_ADDR pc)
+{
+  unsigned char c;
+
+  read_inferior_memory (pc, &c, 1);
+  if (c == 0xCC)
+    return 1;
+
+  return 0;
+}
+
+struct linux_target_ops the_low_target = {
+  i386_num_regs,
+  i386_regmap,
+  i386_cannot_fetch_register,
+  i386_cannot_store_register,
+  i386_get_pc,
+  i386_set_pc,
+  i386_breakpoint,
+  i386_breakpoint_len,
+  NULL,
+  1,
+  i386_breakpoint_at,
+};
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-ia64-low.c gdb-5.2.1/gdb/gdbserver/linux-ia64-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-ia64-low.c	Wed Feb 27 08:07:39 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-ia64-low.c	Tue Sep  2 14:04:41 2003
@@ -26,11 +26,11 @@
 #include <sys/reg.h>
 #endif
 
-int num_regs = 590;
+#define ia64_num_regs 590
 
 #include <asm/ptrace_offsets.h>
 
-int regmap[] =
+static int ia64_regmap[] =
   {
     /* general registers */
     -1,		/* gr0 not available; i.e, it's always zero */
@@ -283,15 +283,21 @@ int regmap[] =
     -1, -1, -1, -1, -1, -1, -1, -1,
   };
 
-int
-cannot_store_register (int regno)
+static int
+ia64_cannot_store_register (int regno)
 {
   return 0;
 }
 
-int
-cannot_fetch_register (int regno)
+static int
+ia64_cannot_fetch_register (int regno)
 {
   return 0;
 }
 
+struct linux_target_ops the_low_target = {
+  ia64_num_regs,
+  ia64_regmap,
+  ia64_cannot_fetch_register,
+  ia64_cannot_store_register,
+};
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-low.c gdb-5.2.1/gdb/gdbserver/linux-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-low.c	Thu Mar  7 21:56:18 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-low.c	Tue Sep  2 14:04:41 2003
@@ -35,6 +35,37 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+/* ``all_threads'' is keyed by the LWP ID - it should be the thread ID instead,
+   however.  This requires changing the ID in place when we go from !using_threads
+   to using_threads, immediately.
+
+   ``all_processes'' is keyed by the process ID - which on Linux is (presently)
+   the same as the LWP ID.  */
+
+struct inferior_list all_processes;
+
+/* FIXME this is a bit of a hack, and could be removed.  */
+int stopping_threads;
+
+/* FIXME make into a target method?  */
+int using_threads;
+
+static void linux_resume_one_process (struct inferior_list_entry *entry,
+                                     int step, int signal);
+static void linux_resume (int step, int signal);
+static void stop_all_processes (void);
+static int linux_wait_for_event (struct thread_info *child);
+#ifdef HAVE_TARGET_ATTACH
+static void
+linux_detach_one_process (struct inferior_list_entry *entry);
+#endif
+
+struct pending_signals
+{
+  int signal;
+  struct pending_signals *prev;
+};
+
 #define PTRACE_ARG3_TYPE long
 #define PTRACE_XFER_TYPE long
 
@@ -44,17 +75,72 @@ static int use_regsets_p = 1;
 
 extern int errno;
 
-#ifdef HAVE_LINUX_USRREGS
-extern int num_regs;
-extern int regmap[];
-#endif
+int debug_threads = 0;
+
+#define pid_of(proc) ((proc)->head.id)
+
+/* FIXME: Delete eventually.  */
+#define inferior_pid (pid_of (get_thread_process (current_inferior)))
+
+/* This function should only be called if the process got a SIGTRAP.
+   The SIGTRAP could mean several things.
+
+   On i386, where decr_pc_after_break is non-zero:
+   If we were single-stepping this process using PTRACE_SINGLESTEP,
+   we will get only the one SIGTRAP (even if the instruction we
+   stepped over was a breakpoint).  The value of $eip will be the
+   next instruction.
+   If we continue the process using PTRACE_CONT, we will get a
+   SIGTRAP when we hit a breakpoint.  The value of $eip will be
+   the instruction after the breakpoint (i.e. needs to be
+   decremented).  If we report the SIGTRAP to GDB, we must also
+   report the undecremented PC.  If we cancel the SIGTRAP, we
+   must resume at the decremented PC.
+
+   (Presumably, not yet tested) On a non-decr_pc_after_break machine
+   with hardware or kernel single-step:
+   If we single-step over a breakpoint instruction, our PC will
+   point at the following instruction.  If we continue and hit a
+   breakpoint instruction, our PC will point at the breakpoint
+   instruction.  */
+
+static CORE_ADDR
+get_stop_pc (void)
+{
+  CORE_ADDR stop_pc = (*the_low_target.get_pc) ();
+
+  if (get_thread_process (current_inferior)->stepping)
+    return stop_pc;
+  else
+    return stop_pc - the_low_target.decr_pc_after_break;
+}
+
+static void *
+add_process (int pid)
+{
+  struct process_info *process;
+
+  process = (struct process_info *) malloc (sizeof (*process));
+  memset (process, 0, sizeof (*process));
+
+  process->head.id = pid;
+
+  /* Default to tid == lwpid == pid.  */
+  process->tid = pid;
+  process->lwpid = pid;
+
+  add_inferior_to_list (&all_processes, &process->head);
+
+  return process;
+}
 
 /* Start an inferior process and returns its pid.
    ALLARGS is a vector of program-name and args. */
 
-int
-create_inferior (char *program, char **allargs)
+static int
+linux_create_inferior (char *program, char **allargs)
 {
+  void *new_process;
   int pid;
 
   pid = fork ();
@@ -65,6 +151,8 @@ create_inferior (char *program, char **a
     {
       ptrace (PTRACE_TRACEME, 0, 0, 0);
 
+      signal (SIGRTMIN + 1, SIG_DFL);
+
       execv (program, allargs);
 
       fprintf (stderr, "Cannot exec %s: %s.\n", program,
@@ -73,104 +161,767 @@ create_inferior (char *program, char **a
       _exit (0177);
     }
 
-  return pid;
+  new_process = add_process (pid);
+  add_thread (pid, new_process);
+
+  return 0;
 }
 
 /* Attach to an inferior process.  */
 
-int
-myattach (int pid)
+void
+linux_attach_lwp (int pid, int tid)
 {
+  struct process_info *new_process;
+
   if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0)
     {
       fprintf (stderr, "Cannot attach to process %d: %s (%d)\n", pid,
 	       errno < sys_nerr ? sys_errlist[errno] : "unknown error",
 	       errno);
       fflush (stderr);
-      _exit (0177);
+      /* If we fail to attach to an LWP, just return.  */
+      if (!using_threads)
+       _exit (0177);
+      return;
     }
+  new_process = (struct process_info *) add_process (pid);
+  add_thread (tid, new_process);
+
+  /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH
+     brings it to a halt.  We should ignore that SIGSTOP and resume the process
+     (unless this is the first process, in which case the flag will be cleared
+     in linux_attach).
+
+     On the other hand, if we are currently trying to stop all threads, we
+     should treat the new thread as if we had sent it a SIGSTOP.  This works
+     because we are guaranteed that add_process added us to the end of the
+     list, and so the new thread has not yet reached wait_for_sigstop (but
+     will).  */
+  if (! stopping_threads)
+    new_process->stop_expected = 1;
+}
 
+int
+linux_attach (int pid)
+{
+  struct process_info *process;
+
+  linux_attach_lwp (pid, pid);
+
+  /* Don't ignore the initial SIGSTOP if we just attached to this process.  */
+  process = (struct process_info *) find_inferior_id (&all_processes, pid);
+  process->stop_expected = 0;
+
+  return 0;
+}
+
+#ifdef HAVE_TARGET_ATTACH
+int
+linux_detach (int sig)
+{
+  if (using_threads) {
+    thread_db_deinit();
+    using_threads = 0;
+  }
+  for_each_inferior (&all_threads, linux_detach_one_process);
+  clear_inferiors ();
+  current_inferior = NULL;
   return 0;
 }
 
+static void
+linux_detach_one_process (struct inferior_list_entry *entry)
+{
+  struct thread_info *thread = (struct thread_info *) entry;
+  struct process_info *process = get_thread_process (thread);
+
+  if (debug_threads)
+    fprintf(stderr, "detaching from pid %d...\n", 
+			pid_of (process));
+  errno = 0;
+  ptrace (PTRACE_DETACH, pid_of (process),0, 0);
+  if (errno) {
+    char *err = strerror(errno);
+	fprintf(stderr,"Error detaching %d: %s\n", pid_of (process), err);
+  }
+}
+
+#endif
+
 /* Kill the inferior process.  Make us have no inferior.  */
 
-void
-kill_inferior (void)
+static void
+linux_kill_one_process (struct inferior_list_entry *entry)
 {
-  if (inferior_pid == 0)
-    return;
-  ptrace (PTRACE_KILL, inferior_pid, 0, 0);
-  wait (0);
+  struct thread_info *thread = (struct thread_info *) entry;
+  struct process_info *process = get_thread_process (thread);
+  int wstat;
+
+  do
+    {
+      ptrace (PTRACE_KILL, pid_of (process), 0, 0);
+
+      /* Make sure it died.  The loop is most likely unnecessary.  */
+      wstat = linux_wait_for_event (thread);
+    } while (WIFSTOPPED (wstat));
 }
 
 /* Return nonzero if the given thread is still alive.  */
-int
-mythread_alive (int pid)
+static void
+linux_kill (void)
+{
+  for_each_inferior (&all_threads, linux_kill_one_process);
+}
+
+static int
+linux_thread_alive (int tid)
+{
+  if (find_inferior_id (&all_threads, tid) != NULL)
+    return 1;
+  else
+    return 0;
+}
+
+/* Return nonzero if this process stopped at a breakpoint which
+   no longer appears to be inserted.  Also adjust the PC
+   appropriately to resume where the breakpoint used to be.  */
+static int
+check_removed_breakpoint (struct process_info *event_child)
 {
+  CORE_ADDR stop_pc;
+  struct thread_info *saved_inferior;
+
+  if (event_child->pending_is_breakpoint == 0)
+    return 0;
+
+  if (debug_threads)
+    fprintf (stderr, "Checking for breakpoint.\n");
+
+  saved_inferior = current_inferior;
+  current_inferior = get_process_thread (event_child);
+
+  stop_pc = get_stop_pc ();
+
+  /* If the PC has changed since we stopped, then we shouldn't do
+     anything.  This happens if, for instance, GDB handled the
+     decr_pc_after_break subtraction itself.  */
+  if (stop_pc != event_child->pending_stop_pc)
+    {
+      if (debug_threads)
+       fprintf (stderr, "Ignoring, PC was changed.\n");
+
+      event_child->pending_is_breakpoint = 0;
+      current_inferior = saved_inferior;
+      return 0;
+    }
+
+  /* If the breakpoint is still there, we will report hitting it.  */
+  if ((*the_low_target.breakpoint_at) (stop_pc))
+    {
+      if (debug_threads)
+       fprintf (stderr, "Ignoring, breakpoint is still present.\n");
+      current_inferior = saved_inferior;
+      return 0;
+    }
+
+  if (debug_threads)
+    fprintf (stderr, "Removed breakpoint.\n");
+
+  /* For decr_pc_after_break targets, here is where we perform the
+     decrement.  We go immediately from this function to resuming,
+     and can not safely call get_stop_pc () again.  */
+  if (the_low_target.set_pc != NULL)
+    (*the_low_target.set_pc) (stop_pc);
+
+  /* We consumed the pending SIGTRAP.  */
+  event_child->status_pending_p = 0;
+  event_child->status_pending = 0;
+
+  current_inferior = saved_inferior;
   return 1;
 }
 
-/* Wait for process, returns status */
+/* Return 1 if this process has an interesting status pending.  This function
+   may silently resume an inferior process.  */
+static int
+status_pending_p (struct inferior_list_entry *entry, void *dummy)
+{
+  struct process_info *process = (struct process_info *) entry;
 
-unsigned char
-mywait (char *status)
+  if (process->status_pending_p)
+    if (check_removed_breakpoint (process))
+      {
+       /* This thread was stopped at a breakpoint, and the breakpoint
+          is now gone.  We were told to continue (or step...) all threads,
+          so GDB isn't trying to single-step past this breakpoint.
+          So instead of reporting the old SIGTRAP, pretend we got to
+          the breakpoint just after it was removed instead of just
+          before; resume the process.  */
+       linux_resume_one_process (&process->head, 0, 0);
+       return 0;
+      }
+
+  return process->status_pending_p;
+}
+
+static void
+linux_wait_for_process (struct process_info **childp, int *wstatp)
+{
+  int ret;
+  int to_wait_for = -1;
+
+  if (*childp != NULL)
+    to_wait_for = (*childp)->lwpid;
+
+  while (1)
+    {
+      ret = waitpid (to_wait_for, wstatp, WNOHANG);
+
+      if (ret == -1)
+       {
+         if (errno != ECHILD)
+           perror_with_name ("waitpid");
+       }
+      else if (ret > 0)
+       break;
+
+      ret = waitpid (to_wait_for, wstatp, WNOHANG | __WCLONE);
+       if (ret == -1)
+	{
+         if (errno != ECHILD)
+           perror_with_name ("waitpid (WCLONE)");
+       }
+      else if (ret > 0)
+       break;
+
+      usleep (1000);
+    }
+
+  if (debug_threads
+      && (!WIFSTOPPED (*wstatp)
+         || (WSTOPSIG (*wstatp) != 32
+             && WSTOPSIG (*wstatp) != 33)))
+    fprintf (stderr, "Got an event from %d (%x)\n", ret, *wstatp);
+
+  if (to_wait_for == -1)
+    *childp = (struct process_info *) find_inferior_id (&all_processes, ret);
+
+  (*childp)->stopped = 1;
+  (*childp)->pending_is_breakpoint = 0;
+
+  if (debug_threads
+      && WIFSTOPPED (*wstatp))
+    {
+      current_inferior = (struct thread_info *)
+       find_inferior_id (&all_threads, (*childp)->tid);
+      /* For testing only; i386_stop_pc prints out a diagnostic.  */
+      if (the_low_target.get_pc != NULL)
+       get_stop_pc ();
+    }
+}
+static int
+linux_wait_for_event (struct thread_info *child)
+{
+  CORE_ADDR stop_pc;
+  struct process_info *event_child;
+  int wstat;
+
+  /* Check for a process with a pending status.  */
+  /* It is possible that the user changed the pending task's registers since
+     it stopped.  We correctly handle the change of PC if we hit a breakpoint
+     (in check_removed_breakpoints); signals should be reported anyway.  */
+  if (child == NULL)
+    {
+      event_child = (struct process_info *)
+       find_inferior (&all_processes, status_pending_p, NULL);
+      if (debug_threads && event_child)
+       fprintf (stderr, "Got a pending child %d\n", event_child->lwpid);
+    }
+  else
+    {
+      event_child = get_thread_process (child);
+      if (event_child->status_pending_p
+         && check_removed_breakpoint (event_child))
+       event_child = NULL;
+    }
+
+  if (event_child != NULL)
+    {
+      if (event_child->status_pending_p)
+       {
+         if (debug_threads)
+           fprintf (stderr, "Got an event from pending child %d (%04x)\n",
+                    event_child->lwpid, event_child->status_pending);
+         wstat = event_child->status_pending;
+         event_child->status_pending_p = 0;
+         event_child->status_pending = 0;
+         current_inferior = get_process_thread (event_child);
+         return wstat;
+       }
+    }
+
+  /* We only enter this loop if no process has a pending wait status.  Thus
+     any action taken in response to a wait status inside this loop is
+     responding as soon as we detect the status, not after any pending
+     events.  */
+  while (1)
+    {
+      if (child == NULL)
+       event_child = NULL;
+      else
+       event_child = get_thread_process (child);
+
+      linux_wait_for_process (&event_child, &wstat);
+
+      if (event_child == NULL)
+       error ("event from unknown child");
+
+      current_inferior = (struct thread_info *)
+       find_inferior_id (&all_threads, event_child->tid);
+
+      if (using_threads)
+       {
+         /* Check for thread exit.  */
+         if (! WIFSTOPPED (wstat))
+	    {
+             if (debug_threads)
+               fprintf (stderr, "Thread %d (LWP %d) exiting\n",
+                        event_child->tid, event_child->head.id);
+
+             /* If the last thread is exiting, just return.  */
+             if (all_threads.head == all_threads.tail)
+               return wstat;
+
+             dead_thread_notify (event_child->tid);
+
+             remove_inferior (&all_processes, &event_child->head);
+             free (event_child);
+             remove_thread (current_inferior);
+             current_inferior = (struct thread_info *) all_threads.head;
+
+             /* If we were waiting for this particular child to do something...
+                well, it did something.  */
+             if (child != NULL)
+               return wstat;
+
+             /* Wait for a more interesting event.  */
+	      continue;
+	    }
+
+         if (WIFSTOPPED (wstat)
+             && WSTOPSIG (wstat) == SIGSTOP
+             && event_child->stop_expected)
+           {
+             if (debug_threads)
+               fprintf (stderr, "Expected stop.\n");
+             event_child->stop_expected = 0;
+             linux_resume_one_process (&event_child->head,
+                                       event_child->stepping, 0);
+             continue;
+           }
+
+         /* FIXME drow/2002-06-09: Get signal numbers from the inferior's
+            thread library?  */
+         if (WIFSTOPPED (wstat)
+             && (WSTOPSIG (wstat) == SIGRTMIN
+                 || WSTOPSIG (wstat) == SIGRTMIN + 1))
+	    {
+             if (debug_threads)
+               fprintf (stderr, "Ignored signal %d for %d (LWP %d).\n",
+                        WSTOPSIG (wstat), event_child->tid,
+                        event_child->head.id);
+             linux_resume_one_process (&event_child->head,
+                                       event_child->stepping,
+                                       WSTOPSIG (wstat));
+             continue;
+           }
+       }
+
+      /* If this event was not handled above, and is not a SIGTRAP, report
+        it.  */
+      if (!WIFSTOPPED (wstat) || WSTOPSIG (wstat) != SIGTRAP)
+       return wstat;
+
+      /* If this target does not support breakpoints, we simply report the
+        SIGTRAP; it's of no concern to us.  */
+      if (the_low_target.get_pc == NULL)
+       return wstat;
+
+      stop_pc = get_stop_pc ();
+
+      /* bp_reinsert will only be set if we were single-stepping.
+        Notice that we will resume the process after hitting
+        a gdbserver breakpoint; single-stepping to/over one
+        is not supported (yet).  */
+      if (event_child->bp_reinsert != 0)
+       {
+         if (debug_threads)
+           fprintf (stderr, "Reinserted breakpoint.\n");
+         reinsert_breakpoint (event_child->bp_reinsert);
+         event_child->bp_reinsert = 0;
+         /* Clear the single-stepping flag and SIGTRAP as we resume.  */
+         linux_resume_one_process (&event_child->head, 0, 0);
+         continue;
+       }
+
+      if (debug_threads)
+       fprintf (stderr, "Hit a (non-reinsert) breakpoint.\n");
+
+      if (check_breakpoints (stop_pc) != 0)
+       {
+         /* We hit one of our own breakpoints.  We mark it as a pending
+            breakpoint, so that check_removed_breakpoints () will do the PC
+            adjustment for us at the appropriate time.  */
+         event_child->pending_is_breakpoint = 1;
+         event_child->pending_stop_pc = stop_pc;
+
+         /* Now we need to put the breakpoint back.  We continue in the event
+            loop instead of simply replacing the breakpoint right away,
+            in order to not lose signals sent to the thread that hit the
+            breakpoint.  Unfortunately this increases the window where another
+            thread could sneak past the removed breakpoint.  For the current
+            use of server-side breakpoints (thread creation) this is
+            acceptable; but it needs to be considered before this breakpoint
+            mechanism can be used in more general ways.  For some breakpoints
+            it may be necessary to stop all other threads, but that should
+            be avoided where possible.
+
+            If breakpoint_reinsert_addr is NULL, that means that we can
+            use PTRACE_SINGLESTEP on this platform.  Uninsert the breakpoint,
+            mark it for reinsertion, and single-step.
+
+            Otherwise, call the target function to figure out where we need
+            our temporary breakpoint, create it, and continue executing this
+            process.  */
+         if (the_low_target.breakpoint_reinsert_addr == NULL)
+           {
+             event_child->bp_reinsert = stop_pc;
+             uninsert_breakpoint (stop_pc);
+             linux_resume_one_process (&event_child->head, 1, 0);
+           }
+         else
+           {
+             reinsert_breakpoint_by_bp
+               (stop_pc, (*the_low_target.breakpoint_reinsert_addr) ());
+             linux_resume_one_process (&event_child->head, 0, 0);
+    }
+
+         continue;
+       }
+
+      /* If we were single-stepping, we definitely want to report the
+        SIGTRAP.  The single-step operation has completed, so also
+         clear the stepping flag; in general this does not matter,
+        because the SIGTRAP will be reported to the client, which
+        will give us a new action for this thread, but clear it for
+        consistency anyway.  It's safe to clear the stepping flag
+         because the only consumer of get_stop_pc () after this point
+        is check_removed_breakpoints, and pending_is_breakpoint is not
+        set.  It might be wiser to use a step_completed flag instead.  */
+      if (event_child->stepping)
+       {
+         event_child->stepping = 0;
+         return wstat;
+       }
+
+      /* A SIGTRAP that we can't explain.  It may have been a breakpoint.
+        Check if it is a breakpoint, and if so mark the process information
+        accordingly.  This will handle both the necessary fiddling with the
+        PC on decr_pc_after_break targets and suppressing extra threads
+        hitting a breakpoint if two hit it at once and then GDB removes it
+        after the first is reported.  Arguably it would be better to report
+        multiple threads hitting breakpoints simultaneously, but the current
+        remote protocol does not allow this.  */
+      if ((*the_low_target.breakpoint_at) (stop_pc))
+       {
+         event_child->pending_is_breakpoint = 1;
+         event_child->pending_stop_pc = stop_pc;
+	}
+
+      return wstat;
+    }
+
+  /* NOTREACHED */
+  return 0;
+}
+
+/* Wait for process, returns status.  */
+
+static unsigned char
+linux_wait (char *status)
 {
-  int pid;
   int w;
+  struct thread_info *child = NULL;
+
+retry:
+  /* If we were only supposed to resume one thread, only wait for
+     that thread - if it's still alive.  If it died, however - which
+     can happen if we're coming from the thread death case below -
+     then we need to make sure we restart the other threads.  We could
+     pick a thread at random or restart all; restarting all is less
+     arbitrary.  */
+  if (cont_thread > 0)
+    {
+      child = (struct thread_info *) find_inferior_id (&all_threads,
+                                                      cont_thread);
+
+      /* No stepping, no signal - unless one is pending already, of course.  */
+      if (child == NULL)
+       linux_resume (0, 0);
+    }
 
   enable_async_io ();
-  pid = waitpid (inferior_pid, &w, 0);
+  w = linux_wait_for_event (child);
+  stop_all_processes ();
   disable_async_io ();
-  if (pid != inferior_pid)
-    perror_with_name ("wait");
 
-  if (WIFEXITED (w))
+  /* If we are waiting for a particular child, and it exited,
+     linux_wait_for_event will return its exit status.  Similarly if
+     the last child exited.  If this is not the last child, however,
+     do not report it as exited until there is a 'thread exited' response
+     available in the remote protocol.  Instead, just wait for another event.
+     This should be safe, because if the thread crashed we will already
+     have reported the termination signal to GDB; that should stop any
+     in-progress stepping operations, etc.
+
+     Report the exit status of the last thread to exit.  This matches
+     LinuxThreads' behavior.  */
+
+  if (all_threads.head == all_threads.tail)
     {
-      fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
-      *status = 'W';
-      return ((unsigned char) WEXITSTATUS (w));
+      if (WIFEXITED (w))
+       {
+         fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
+         *status = 'W';
+         clear_inferiors ();
+         return ((unsigned char) WEXITSTATUS (w));
+       }
+      else if (!WIFSTOPPED (w))
+       {
+         fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
+         clear_inferiors ();
+         *status = 'X';
+         return ((unsigned char) WTERMSIG (w));
+       }
     }
-  else if (!WIFSTOPPED (w))
+  else 
     {
-      fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
-      *status = 'X';
-      return ((unsigned char) WTERMSIG (w));
-    }
+      if (!WIFSTOPPED (w))
+       goto retry;
 
-  fetch_inferior_registers (0);
+    }
 
   *status = 'T';
   return ((unsigned char) WSTOPSIG (w));
 }
 
+static void
+send_sigstop (struct inferior_list_entry *entry)
+{
+  struct process_info *process = (struct process_info *) entry;
+
+  if (process->stopped)
+    return;
+
+  /* If we already have a pending stop signal for this process, don't
+     send another.  */
+  if (process->stop_expected)
+    {
+      process->stop_expected = 0;
+      return;
+    }
+
+  if (debug_threads)
+    fprintf (stderr, "Sending sigstop to process %d\n", process->head.id);
+
+  kill (process->head.id, SIGSTOP);
+  process->sigstop_sent = 1;
+}
+
+static void
+wait_for_sigstop (struct inferior_list_entry *entry)
+{
+  struct process_info *process = (struct process_info *) entry;
+  struct thread_info *saved_inferior, *thread;
+  int wstat, saved_tid;
+
+  if (process->stopped)
+    return;
+
+  saved_inferior = current_inferior;
+  saved_tid = ((struct inferior_list_entry *) saved_inferior)->id;
+  thread = (struct thread_info *) find_inferior_id (&all_threads,
+                                                   process->tid);
+  wstat = linux_wait_for_event (thread);
+
+  /* If we stopped with a non-SIGSTOP signal, save it for later
+     and record the pending SIGSTOP.  If the process exited, just
+     return.  */
+  if (WIFSTOPPED (wstat)
+      && WSTOPSIG (wstat) != SIGSTOP)
+    {
+      if (debug_threads)
+       fprintf (stderr, "Stopped with non-sigstop signal\n");
+      process->status_pending_p = 1;
+      process->status_pending = wstat;
+      process->stop_expected = 1;
+    }
+
+  if (linux_thread_alive (saved_tid))
+    current_inferior = saved_inferior;
+  else
+    {
+      if (debug_threads)
+       fprintf (stderr, "Previously current thread died.\n");
+
+      /* Set a valid thread as current.  */
+      set_desired_inferior (0);
+    }
+}
+
+static void
+stop_all_processes (void)
+{
+  stopping_threads = 1;
+  for_each_inferior (&all_processes, send_sigstop);
+  for_each_inferior (&all_processes, wait_for_sigstop);
+  stopping_threads = 0;
+}
+
 /* Resume execution of the inferior process.
    If STEP is nonzero, single-step it.
    If SIGNAL is nonzero, give it that signal.  */
 
-void
-myresume (int step, int signal)
+static void
+linux_resume_one_process (struct inferior_list_entry *entry,
+                         int step, int signal)
 {
+  struct process_info *process = (struct process_info *) entry;
+  struct thread_info *saved_inferior;
+
+  if (process->stopped == 0)
+    return;
+
+  /* If we have pending signals or status, and a new signal, enqueue the
+     signal.  Also enqueue the signal if we are waiting to reinsert a
+     breakpoint; it will be picked up again below.  */
+  if (signal != 0
+      && (process->status_pending_p || process->pending_signals != NULL
+         || process->bp_reinsert != 0))
+    {
+      struct pending_signals *p_sig;
+      p_sig = malloc (sizeof (*p_sig));
+      p_sig->prev = process->pending_signals;
+      p_sig->signal = signal;
+      process->pending_signals = p_sig;
+    }
+
+  if (process->status_pending_p)
+    return;
+
+  saved_inferior = current_inferior;
+  current_inferior = get_process_thread (process);
+
+  if (debug_threads)
+    fprintf (stderr, "Resuming process %d (%s, signal %d, stop %s)\n", inferior_pid,
+            step ? "step" : "continue", signal,
+            process->stop_expected ? "expected" : "not expected");
+
+  /* This bit needs some thinking about.  If we get a signal that
+     we must report while a single-step reinsert is still pending,
+     we often end up resuming the thread.  It might be better to
+     (ew) allow a stack of pending events; then we could be sure that
+     the reinsert happened right away and not lose any signals.
+
+     Making this stack would also shrink the window in which breakpoints are
+     uninserted (see comment in linux_wait_for_process) but not enough for
+     complete correctness, so it won't solve that problem.  It may be
+     worthwhile just to solve this one, however.  */
+  if (process->bp_reinsert != 0)
+    {
+      if (debug_threads)
+       fprintf (stderr, "  pending reinsert at %08lx", (long)process->bp_reinsert);
+      if (step == 0)
+       fprintf (stderr, "BAD - reinserting but not stepping.\n");
+      step = 1;
+
+      /* Postpone any pending signal.  It was enqueued above.  */
+      signal = 0;
+    }
+
+  check_removed_breakpoint (process);
+
+  if (debug_threads && the_low_target.get_pc != NULL)
+    {
+      fprintf (stderr, "  ");
+      (long) (*the_low_target.get_pc) ();
+    }
+
+  /* If we have pending signals, consume one unless we are trying to reinsert
+     a breakpoint.  */
+  if (process->pending_signals != NULL && process->bp_reinsert == 0)
+    {
+      struct pending_signals **p_sig;
+
+      p_sig = &process->pending_signals;
+      while ((*p_sig)->prev != NULL)
+       p_sig = &(*p_sig)->prev;
+
+      signal = (*p_sig)->signal;
+      free (*p_sig);
+      *p_sig = NULL;
+    }
+
+  regcache_invalidate_one ((struct inferior_list_entry *)
+                          get_process_thread (process));
+
   errno = 0;
-  ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal);
+  process->stopped = 0;
+  process->stepping = step;
+  ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, process->lwpid, 0, signal);
+
+  current_inferior = saved_inferior;
   if (errno)
     perror_with_name ("ptrace");
 }
+/* This function is called once per process other than the first
+   one.  The first process we are told the signal to continue
+   with, and whether to step or continue; for all others, any
+   existing signals will be marked in status_pending_p to be
+   reported momentarily, and we preserve the stepping flag.  */
+static void
+linux_continue_one_process (struct inferior_list_entry *entry)
+{
+  struct process_info *process;
+  process = (struct process_info *) entry;
+  linux_resume_one_process (entry, process->stepping, 0);
+}
 
+static void
+linux_resume (int step, int signal)
+{
+  struct process_info *process;
 
-#ifdef HAVE_LINUX_USRREGS
+  process = get_thread_process (current_inferior);
 
-#define REGISTER_RAW_SIZE(regno) register_size((regno))
+  /* If the current process has a status pending, this signal will
+     be enqueued and sent later.  */
+  linux_resume_one_process (&process->head, step, signal);
+  if (cont_thread == 0 || cont_thread == -1)
+    for_each_inferior (&all_processes, linux_continue_one_process);
+}
 
+#ifdef HAVE_LINUX_USRREGS
 int
 register_addr (int regnum)
 {
   int addr;
 
-  if (regnum < 0 || regnum >= num_regs)
+  if (regnum < 0 || regnum >= the_low_target.num_regs)
     error ("Invalid register number %d.", regnum);
 
-  addr = regmap[regnum];
+  addr = the_low_target.regmap[regnum];
   if (addr == -1)
     addr = 0;
 
@@ -183,19 +934,21 @@ fetch_register (int regno)
 {
   CORE_ADDR regaddr;
   register int i;
+  char *buf;
 
-  if (regno >= num_regs)
+  if (regno >= the_low_target.num_regs)
     return;
-  if (cannot_fetch_register (regno))
+  if ((*the_low_target.cannot_fetch_register) (regno))
     return;
 
   regaddr = register_addr (regno);
   if (regaddr == -1)
     return;
-  for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+  buf = alloca (register_size (regno));
+  for (i = 0; i < register_size (regno); i += sizeof (PTRACE_XFER_TYPE))
     {
       errno = 0;
-      *(PTRACE_XFER_TYPE *) (register_data (regno) + i) =
+      *(PTRACE_XFER_TYPE *) (buf + i) =
 	ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0);
       regaddr += sizeof (PTRACE_XFER_TYPE);
       if (errno != 0)
@@ -209,6 +962,8 @@ fetch_register (int regno)
 	  goto error_exit;
 	}
     }
+  supply_register (regno, buf);
+
 error_exit:;
 }
 
@@ -217,7 +972,7 @@ static void
 usr_fetch_inferior_registers (int regno)
 {
   if (regno == -1 || regno == 0)
-    for (regno = 0; regno < num_regs; regno++)
+    for (regno = 0; regno < the_low_target.num_regs; regno++)
       fetch_register (regno);
   else
     fetch_register (regno);
@@ -231,41 +986,45 @@ usr_store_inferior_registers (int regno)
 {
   CORE_ADDR regaddr;
   int i;
+  char *buf;
 
   if (regno >= 0)
     {
-      if (regno >= num_regs)
+      if (regno >= the_low_target.num_regs)
 	return;
 
-      if (cannot_store_register (regno))
+      if ((*the_low_target.cannot_store_register) (regno) == 1)
 	return;
 
       regaddr = register_addr (regno);
       if (regaddr == -1)
 	return;
       errno = 0;
-      for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+      buf = alloca (register_size (regno));
+      collect_register (regno, buf);
+      for (i = 0; i < register_size (regno); i += sizeof (PTRACE_XFER_TYPE))
 	{
 	  errno = 0;
 	  ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
-		  *(int *) (register_data (regno) + i));
+		  *(int *) (buf + 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;
+	      if ((*the_low_target.cannot_store_register) (regno) == 0)
+		{
+		  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);
+    for (regno = 0; regno < the_low_target.num_regs; regno++)
+      usr_store_inferior_registers (regno);
 }
 #endif /* HAVE_LINUX_USRREGS */
 
@@ -274,7 +1033,7 @@ usr_store_inferior_registers (int regno)
 #ifdef HAVE_LINUX_REGSETS
 
 static int
-regsets_fetch_inferior_registers (void)
+regsets_fetch_inferior_registers ()
 {
   struct regset_info *regset;
 
@@ -292,7 +1051,7 @@ regsets_fetch_inferior_registers (void)
 	}
 
       buf = malloc (regset->size);
-      res = ptrace (regset->get_request, inferior_pid, 0, (int) buf);
+      res = ptrace (regset->get_request, inferior_pid, 0, buf);
       if (res < 0)
 	{
 	  if (errno == EIO)
@@ -312,16 +1071,21 @@ regsets_fetch_inferior_registers (void)
 	    }
 	  else
 	    {
-	      perror ("Warning: ptrace(regsets_fetch_inferior_registers)");
+             char s[256];
+             sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d",
+                      inferior_pid);
+             perror (s);
+
 	    }
 	}
       regset->store_function (buf);
       regset ++;
     }
+  return 0;
 }
 
 static int
-regsets_store_inferior_registers (void)
+regsets_store_inferior_registers ()
 {
   struct regset_info *regset;
 
@@ -340,7 +1104,7 @@ regsets_store_inferior_registers (void)
 
       buf = malloc (regset->size);
       regset->fill_function (buf);
-      res = ptrace (regset->set_request, inferior_pid, 0, (int) buf);
+      res = ptrace (regset->set_request, inferior_pid, 0, buf);
       if (res < 0)
 	{
 	  if (errno == EIO)
@@ -360,18 +1124,19 @@ regsets_store_inferior_registers (void)
 	    }
 	  else
 	    {
-	      perror ("Warning: ptrace(regsets_fetch_inferior_registers)");
+	      perror ("Warning: ptrace(regsets_store_inferior_registers)");
 	    }
 	}
       regset ++;
     }
+  return 0;
 }
 
 #endif /* HAVE_LINUX_REGSETS */
 
 
 void
-fetch_inferior_registers (int regno)
+linux_fetch_registers (int regno)
 {
 #ifdef HAVE_LINUX_REGSETS
   if (use_regsets_p)
@@ -386,7 +1151,7 @@ fetch_inferior_registers (int regno)
 }
 
 void
-store_inferior_registers (int regno)
+linux_store_registers (int regno)
 {
 #ifdef HAVE_LINUX_REGSETS
   if (use_regsets_p)
@@ -404,8 +1169,8 @@ store_inferior_registers (int regno)
 /* Copy LEN bytes from inferior's memory starting at MEMADDR
    to debugger memory starting at MYADDR.  */
 
-void
-read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
+static void
+linux_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
 {
   register int i;
   /* Round starting address down to longword boundary.  */
@@ -433,8 +1198,8 @@ read_inferior_memory (CORE_ADDR memaddr,
    On failure (cannot write the inferior)
    returns the value of errno.  */
 
-int
-write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
+static int
+linux_write_memory (CORE_ADDR memaddr, const char *myaddr, int len)
 {
   register int i;
   /* Round starting address down to longword boundary.  */
@@ -446,6 +1211,11 @@ write_inferior_memory (CORE_ADDR memaddr
   register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
   extern int errno;
 
+  if (debug_threads)
+    {
+      fprintf (stderr, "Writing %02x to %08lx\n", (unsigned)myaddr[0], (long)memaddr);
+    }
+
   /* Fill start and end extra bytes of buffer with existing memory data.  */
 
   buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
@@ -476,9 +1246,189 @@ write_inferior_memory (CORE_ADDR memaddr
 
   return 0;
 }
-
+
+static void
+linux_look_up_symbols (void)
+{
+#ifdef USE_THREAD_DB
+  if (using_threads)
+    return;
+
+  using_threads = thread_db_init ();
+#endif
+}
+
+/* Return 1 if this process is not stopped.  */
+static int
+unstopped_p (struct inferior_list_entry *entry, void *dummy)
+{
+  struct process_info *process = (struct process_info *) entry;
+
+  if (process->stopped)
+    return 0;
+
+  return 1;
+}
+
+static int
+linux_signal_pid ()
+{
+  struct inferior_list_entry *process;
+
+  process = find_inferior (&all_processes, unstopped_p, NULL);
+
+  if (process == NULL)
+    {
+      warning ("no unstopped process");
+      return inferior_pid;
+    }
+
+  return pid_of ((struct process_info *) process);
+}
+
+
+static struct target_ops linux_target_ops = {
+  linux_create_inferior,
+  linux_attach,
+#ifdef HAVE_TARGET_ATTACH
+  linux_detach,
+#endif
+  linux_kill,
+  linux_thread_alive,
+  linux_resume,
+  linux_wait,
+  linux_fetch_registers,
+  linux_store_registers,
+  linux_read_memory,
+  linux_write_memory,
+  linux_look_up_symbols,
+  linux_signal_pid,
+};
+
+static void
+linux_init_signals ()
+{
+  /* FIXME drow/2002-06-09: As above, we should check with LinuxThreads
+     to find what the cancel signal actually is.  */
+  signal (SIGRTMIN+1, SIG_IGN);
+}
+
+
 void
 initialize_low (void)
 {
+  using_threads = 0;
+  set_target_ops (&linux_target_ops);
+  set_breakpoint_data (the_low_target.breakpoint,
+		       the_low_target.breakpoint_len);
   init_registers ();
+  linux_init_signals ();
+}
+#ifdef HAVE_TARGET_SHELL
+extern int remote_desc;
+static void
+my_perror(char *s)
+{
+  const char *err;
+
+  if (errno < sys_nerr)
+    err = sys_errlist[errno];
+  else
+    err = "unknown error";
+  fprintf(stderr, "%s: ", s);
+  error(err);
+}
+
+void
+exec_shellcmd(char *args)
+{
+ int fd[2];
+ int pid, saved_pid;
+ int len;
+ char ch;
+ char buf[100];	/* must be <128 */
+ char **shell, *argv[100], **argp, *p;
+ static char *shells[] = {
+	"/bin/sh", "/bin/bash", "/bin/tcsh",
+	"/usr/bin/sh", "/usr/bin/bash", "/usr/bin/tsch", (char *)0};
+
+  if (pipe(fd))
+    perror_with_name("opening pipe");
+
+  if (current_inferior) 
+	  saved_pid = inferior_pid;
+
+  switch (pid = fork())
+    {
+    case -1:
+      perror_with_name("forking exec shell");
+      break;
+
+    case 0:
+      /* disable stdin */
+      close(0);
+      open("/dev/null", O_RDONLY);
+
+      /* redirect stdout and stderr to pipe */
+      if (dup2(fd[1], 1) != 1 || dup2(fd[1], 2) != 2)
+	{
+          my_perror("dup in exec shell");
+	  exit(1);
+	}
+      /* which shell? */
+      for (shell = shells; *shell; shell++)
+	if (access(*shell, X_OK) == 0)
+	  break;
+      if (*shell)
+        execlp(*shell, *shell, "-c", args, (char *)0);
+      else
+	{/* No shell installed. Exec it directly */
+	  for (p = args, argp = argv;
+		*p && argp < &argv[sizeof(argv)/sizeof(argv[0])] - 1; )
+	    {
+	      *argp++ = p;
+	      while (*p && !isspace(*p))
+		p++;	/* skip word */
+	      if (!*p)
+		break;	/* no more chars */
+	      *p++ = '\0';
+	      while (isspace(*p))
+		p++;	/* skip delimiting spaces */
+	      if (!*p)
+		break;	/* no more chars */
+	    }
+	  *argp = (char *)0;
+          execvp(*argv, argv);
+	}
+
+      my_perror("exec shell");
+      exit(1);
+      break;
+
+    default:	/* Parent - gdbserver */
+      close(fd[1]);	/* To get EOF properly */
+	  enable_async_io();
+	  /* To be able to stop the long output with ^C place 
+		 a fake process ID */
+	  if (current_inferior)
+		  inferior_pid = pid;
+      while (1)
+	{
+          if ((len = read(fd[0], buf, sizeof buf)) > 0)
+	    {
+		  ch = (char)len; /* We know it fit */
+	      write(remote_desc, &ch, 1);
+	      write(remote_desc, buf, len);
+	    }
+	  else if (len != -1 || errno != EINTR) 
+	      break;
+	  
+	}
+      write(remote_desc, &len, 1);	/* end mark (0) */
+      waitpid(pid, (void *)0, 0);
+      if (current_inferior)
+		  inferior_pid = saved_pid;
+      disable_async_io();
+    }
 }
+#endif
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-low.h gdb-5.2.1/gdb/gdbserver/linux-low.h
--- gdb-5.2.1-orig/gdb/gdbserver/linux-low.h	Wed Feb 27 08:07:39 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-low.h	Tue Sep  2 14:04:41 2003
@@ -18,20 +18,112 @@
    Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#ifdef HAVE_LINUX_USR_REGISTERS
-extern int regmap[];
-extern int num_regs;
-int cannot_fetch_register (int regno);
-int cannot_store_register (int regno);
-#endif
-
 #ifdef HAVE_LINUX_REGSETS
-typedef void (*regset_func) (void *);
+typedef void (*regset_fill_func) (void *);
+typedef void (*regset_store_func) (const void *);
+enum regset_type {
+  GENERAL_REGS,
+  FP_REGS,
+  EXTENDED_REGS,
+};
+
 struct regset_info
 {
   int get_request, set_request;
   int size;
-  regset_func fill_function, store_function;
+  enum regset_type type;
+  regset_fill_func fill_function;
+  regset_store_func store_function;
 };
 extern struct regset_info target_regsets[];
 #endif
+
+struct linux_target_ops
+{
+  int num_regs;
+  int *regmap;
+  int (*cannot_fetch_register) (int);
+
+  /* Returns 0 if we can store the register, 1 if we can not
+     store the register, and 2 if failure to store the register
+     is acceptable.  */
+  int (*cannot_store_register) (int);
+  CORE_ADDR (*get_pc) (void);
+  void (*set_pc) (CORE_ADDR newpc);
+  const char *breakpoint;
+  int breakpoint_len;
+  CORE_ADDR (*breakpoint_reinsert_addr) (void);
+
+
+  int decr_pc_after_break;
+  int (*breakpoint_at) (CORE_ADDR pc);
+};
+
+extern struct linux_target_ops the_low_target;
+
+#define get_process(inf) ((struct process_info *)(inf))
+#define get_thread_process(thr) (get_process (inferior_target_data (thr)))
+#define get_process_thread(proc) ((struct thread_info *) \
+                                 find_inferior_id (&all_threads, \
+                                 get_process (proc)->tid))
+
+struct process_info
+{
+  struct inferior_list_entry head;
+  int thread_known;
+  int lwpid;
+  int tid;
+
+  /* If this flag is set, the next SIGSTOP will be ignored (the process will
+     be immediately resumed).  */
+  int stop_expected;
+
+  /* If this flag is set, the process is known to be stopped right now (stop
+     event already received in a wait()).  */
+  int stopped;
+
+  /* If this flag is set, we have sent a SIGSTOP to this process and are
+     waiting for it to stop.  */
+  int sigstop_sent;
+
+  /* If this flag is set, STATUS_PENDING is a waitstatus that has not yet
+     been reported.  */
+  int status_pending_p;
+  int status_pending;
+
+  /* If this flag is set, the pending status is a (GDB-placed) breakpoint.  */
+  int pending_is_breakpoint;
+  CORE_ADDR pending_stop_pc;
+
+  /* If this is non-zero, it is a breakpoint to be reinserted at our next
+     stop (SIGTRAP stops only).  */
+  CORE_ADDR bp_reinsert;
+
+  /* If this flag is set, the last continue operation on this process
+     was a single-step.  */
+  int stepping;
+
+  /* If this is non-zero, it points to a chain of signals which need to
+     be delivered to this process.  */
+  struct pending_signals *pending_signals;
+};
+extern struct inferior_list all_processes;
+
+void linux_attach_lwp (int pid, int tid);
+#ifdef HAVE_TARGET_ATTACH
+void linux_detach_lwp (int pid, int tid);
+int thread_db_deinit (void);
+#endif
+#ifdef HAVE_TARGET_SHELL
+void exec_shellcmd(char *);
+#endif
+
+int thread_db_init (void);
+
+
+
+
+
+
+
+
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-m68k-low.c gdb-5.2.1/gdb/gdbserver/linux-m68k-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-m68k-low.c	Wed Feb 27 08:07:39 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-m68k-low.c	Tue Sep  2 14:04:41 2003
@@ -26,10 +26,10 @@
 #include <sys/reg.h>
 #endif
 
-int num_regs = 31;
+#define m68k_num_regs 31
 
 /* This table must line up with REGISTER_NAMES in tm-m68k.h */
-int regmap[] =
+static int m68k_regmap[] =
 {
 #ifdef PT_D0
   PT_D0 * 4, PT_D1 * 4, PT_D2 * 4, PT_D3 * 4,
@@ -52,14 +52,21 @@ int regmap[] =
 #endif
 };
 
-int
-cannot_store_register (int regno)
+static int
+m68k_cannot_store_register (int regno)
 {
-  return (regno >= num_regs);
+  return (regno >= m68k_num_regs);
 }
 
-int
-cannot_fetch_register (int regno)
+static int
+m68k_cannot_fetch_register (int regno)
 {
-  return (regno >= num_regs);
+  return (regno >= m68k_num_regs);
 }
+
+struct linux_target_ops the_low_target = {
+  m68k_num_regs,
+  m68k_regmap,
+  m68k_cannot_fetch_register,
+  m68k_cannot_store_register,
+};
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-mips-low.c gdb-5.2.1/gdb/gdbserver/linux-mips-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-mips-low.c	Wed Feb 27 08:07:39 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-mips-low.c	Tue Sep  2 14:04:41 2003
@@ -26,14 +26,14 @@
 #include <sys/reg.h>
 #endif
 
-int num_regs = 90;
+#define mips_num_regs 90
 
 #include <asm/ptrace.h>
 
 /* Return the ptrace ``address'' of register REGNO. */
 
 /* Matches mips_generic32_regs */
-int regmap[] = {
+static int mips_regmap[] = {
   0,  1,  2,  3,  4,  5,  6,  7,
   8,  9,  10, 11, 12, 13, 14, 15,
   16, 17, 18, 19, 20, 21, 22, 23,
@@ -63,10 +63,10 @@ int regmap[] = {
    ZERO_REGNUM.  We also can not set BADVADDR, CAUSE, or FCRIR via
    ptrace().  */
 
-int
-cannot_fetch_register (int regno)
+static int
+mips_cannot_fetch_register (int regno)
 {
-  if (regmap[regno] == -1)
+  if (mips_regmap[regno] == -1)
     return 1;
 
   if (find_regno ("zero") == regno)
@@ -75,10 +75,10 @@ cannot_fetch_register (int regno)
   return 0;
 }
 
-int
-cannot_store_register (int regno)
+static int
+mips_cannot_store_register (int regno)
 {
-  if (regmap[regno] == -1)
+  if (mips_regmap[regno] == -1)
     return 1;
 
   if (find_regno ("zero") == regno)
@@ -95,3 +95,61 @@ cannot_store_register (int regno)
 
   return 0;
 }
+
+static CORE_ADDR
+mips_get_pc ()
+{
+  unsigned long pc;
+  collect_register_by_name ("pc", &pc);
+  return pc;
+}
+
+static void
+mips_set_pc (CORE_ADDR pc)
+{
+  unsigned long newpc = pc;
+  supply_register_by_name ("pc", &newpc);
+}
+
+/* Correct in either endianness.  */
+static const unsigned long mips_breakpoint = 0x0005000d;
+#define mips_breakpoint_len 4
+
+/* We only place breakpoints in empty marker functions, and thread locking
+   is outside of the function.  So rather than importing software single-step,
+   we can just run until exit.  */
+static CORE_ADDR
+mips_reinsert_addr ()
+{
+  unsigned long pc;
+  collect_register_by_name ("ra", &pc);
+  return pc;
+}
+
+static int
+mips_breakpoint_at (CORE_ADDR where)
+{
+  unsigned long insn;
+
+  (*the_target->read_memory) (where, (char *) &insn, 4);
+  if (insn == mips_breakpoint)
+    return 1;
+
+  /* If necessary, recognize more trap instructions here.  GDB only uses the
+     one.  */
+  return 0;
+}
+
+struct linux_target_ops the_low_target = {
+  mips_num_regs,
+  mips_regmap,
+  mips_cannot_fetch_register,
+  mips_cannot_store_register,
+  mips_get_pc,
+  mips_set_pc,
+  (const char *) &mips_breakpoint,
+  mips_breakpoint_len,
+  mips_reinsert_addr,
+  0,
+  mips_breakpoint_at,
+};
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-ppc-low.c gdb-5.2.1/gdb/gdbserver/linux-ppc-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-ppc-low.c	Wed Feb 27 08:07:39 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-ppc-low.c	Tue Sep  2 14:04:41 2003
@@ -25,10 +25,10 @@
 
 #include <asm/ptrace.h>
 
-int num_regs = 71;
+#define ppc_num_regs 71
 
 /* Currently, don't check/send MQ.  */
-int regmap[] =
+static int ppc_regmap[] =
  {PT_R0 * 4,     PT_R1 * 4,     PT_R2 * 4,     PT_R3 * 4,
   PT_R4 * 4,     PT_R5 * 4,     PT_R6 * 4,     PT_R7 * 4,
   PT_R8 * 4,     PT_R9 * 4,     PT_R10 * 4,    PT_R11 * 4,
@@ -46,17 +46,71 @@ int regmap[] =
   PT_FPR0*4+192,  PT_FPR0*4+200,  PT_FPR0*4+208,  PT_FPR0*4+216,
   PT_FPR0*4+224,  PT_FPR0*4+232,  PT_FPR0*4+240,  PT_FPR0*4+248,
   PT_NIP * 4,    PT_MSR * 4,    PT_CCR * 4,    PT_LNK * 4,
-  PT_CTR * 4,    PT_XER * 4,    -1, };
+  PT_CTR * 4,    PT_XER * 4,    PT_FPSCR * 4, };
 
-int
-cannot_store_register (int regno)
+static int
+ppc_cannot_store_register (int regno)
+{
+  /* Some kernels do not allow us to store fpscr.  */
+  if (regno == find_regno ("fpscr"))
+    return 2;
+
+  return 0;
+}
+
+static int
+ppc_cannot_fetch_register (int regno)
 {
   return 0;
 }
 
-int
-cannot_fetch_register (int regno)
+static CORE_ADDR
+ppc_get_pc (void)
 {
+  unsigned long pc;
+
+  collect_register_by_name ("pc", &pc);
+  return (CORE_ADDR) pc;
+}
+
+static void
+ppc_set_pc (CORE_ADDR pc)
+{
+  unsigned long newpc = pc;
+
+  supply_register_by_name ("pc", &newpc);
+}
+
+/* Correct in either endianness.  Note that this file is
+   for PowerPC only, not PowerPC64.
+   This instruction is "twge r2, r2", which GDB uses as a software
+   breakpoint.  */
+static const unsigned long ppc_breakpoint = 0x7d821008;
+#define ppc_breakpoint_len 4
+
+static int
+ppc_breakpoint_at (CORE_ADDR where)
+{
+  unsigned long insn;
+
+  (*the_target->read_memory) (where, (char *) &insn, 4);
+  if (insn == ppc_breakpoint)
+    return 1;
+  /* If necessary, recognize more trap instructions here.  GDB only uses the
+     one.  */
   return 0;
 }
 
+struct linux_target_ops the_low_target = {
+  ppc_num_regs,
+  ppc_regmap,
+  ppc_cannot_fetch_register,
+  ppc_cannot_store_register,
+  ppc_get_pc,
+  ppc_set_pc,
+  (const char *) &ppc_breakpoint,
+  ppc_breakpoint_len,
+  NULL,
+  0,
+  ppc_breakpoint_at,
+};
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-s390-low.c gdb-5.2.1/gdb/gdbserver/linux-s390-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-s390-low.c	Thu Feb 28 17:58:14 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-s390-low.c	Tue Sep  2 14:04:41 2003
@@ -27,9 +27,9 @@
 
 #include <asm/ptrace.h>
 
-int num_regs = 67;
+#define s390_num_regs 67
 
-int regmap[] = {
+static int s390_regmap[] = {
   PT_PSWMASK, PT_PSWADDR,
 
   PT_GPR0, PT_GPR1, PT_GPR2, PT_GPR3,
@@ -62,20 +62,27 @@ int regmap[] = {
 #endif
 };
 
-int
-cannot_fetch_register (int regno)
+static int
+s390_cannot_fetch_register (int regno)
 {
-  if (regmap[regno] == -1)
+  if (s390_regmap[regno] == -1)
     return 1;
 
   return 0;
 }
 
-int
-cannot_store_register (int regno)
+static int
+s390_cannot_store_register (int regno)
 {
-  if (regmap[regno] == -1)
+  if (s390_regmap[regno] == -1)
     return 1;
 
   return 0;
 }
+
+struct linux_target_ops the_low_target = {
+  s390_num_regs,
+  s390_regmap,
+  s390_cannot_fetch_register,
+  s390_cannot_store_register,
+};
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-sh-low.c gdb-5.2.1/gdb/gdbserver/linux-sh-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-sh-low.c	Wed Feb 27 08:07:39 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-sh-low.c	Tue Sep  2 14:04:41 2003
@@ -28,10 +28,10 @@
 
 #include <asm/ptrace.h>
 
-int num_regs = 41;
+#define sh_num_regs 41
 
 /* Currently, don't check/send MQ.  */
-int regmap[] = {
+static int sh_regmap[] = {
  0,	4,	8,	12,	16,	20,	24,	28,
  32,	36,	40,	44,	48,	52,	56,	60,
 
@@ -45,15 +45,61 @@ int regmap[] = {
  REG_FPREG0+48,  REG_FPREG0+52,  REG_FPREG0+56,  REG_FPREG0+60,
 };
 
-int
-cannot_store_register (int regno)
+static int
+sh_cannot_store_register (int regno)
 {
   return 0;
 }
 
-int
-cannot_fetch_register (int regno)
+static int
+sh_cannot_fetch_register (int regno)
 {
   return 0;
 }
 
+static CORE_ADDR
+sh_get_pc ()
+{
+  unsigned long pc;
+  collect_register_by_name ("pc", &pc);
+  return pc;
+}
+
+static void
+sh_set_pc (CORE_ADDR pc)
+{
+  unsigned long newpc = pc;
+  supply_register_by_name ("pc", &newpc);
+}
+
+/* Correct in either endianness, obviously.  */
+static const unsigned short sh_breakpoint = 0xc3c3;
+#define sh_breakpoint_len 2
+
+static int
+sh_breakpoint_at (CORE_ADDR where)
+{
+  unsigned short insn;
+
+  (*the_target->read_memory) (where, (char *) &insn, 2);
+  if (insn == sh_breakpoint)
+    return 1;
+
+  /* If necessary, recognize more trap instructions here.  GDB only uses the
+     one.  */
+  return 0;
+}
+
+struct linux_target_ops the_low_target = {
+  sh_num_regs,
+  sh_regmap,
+  sh_cannot_fetch_register,
+  sh_cannot_store_register,
+  sh_get_pc,
+  sh_set_pc,
+  (const char *) &sh_breakpoint,
+  sh_breakpoint_len,
+  NULL,
+  0,
+  sh_breakpoint_at,
+};
diff -purN gdb-5.2.1-orig/gdb/gdbserver/linux-x86-64-low.c gdb-5.2.1/gdb/gdbserver/linux-x86-64-low.c
--- gdb-5.2.1-orig/gdb/gdbserver/linux-x86-64-low.c	Thu Mar  7 21:56:18 2002
+++ gdb-5.2.1/gdb/gdbserver/linux-x86-64-low.c	Tue Sep  2 14:04:41 2003
@@ -28,12 +28,15 @@
 #include <sys/procfs.h>
 #include <sys/ptrace.h>
 
-static int regmap[] = {
-  RAX, RDX, RCX, RBX,
+#define	X86_64_NUM_GREGS 22
+
+static int x86_64_regmap[X86_64_NUM_GREGS] = {
+  RAX, RBX, RCX, RDX,
   RSI, RDI, RBP, RSP,
   R8, R9, R10, R11,
   R12, R13, R14, R15,
-  RIP, EFLAGS
+  RIP, EFLAGS,
+  DS, ES, FS, GS
 };
 
 static void
@@ -41,8 +44,8 @@ x86_64_fill_gregset (void *buf)
 {
   int i;
 
-  for (i = 0; i < 18; i++)
-    collect_register (i, ((char *) buf) + regmap[i]);
+  for (i = 0; i < X86_64_NUM_GREGS; i++)
+    collect_register (i, ((char *) buf) + x86_64_regmap[i]);
 }
 
 static void
@@ -50,8 +53,8 @@ x86_64_store_gregset (void *buf)
 {
   int i;
 
-  for (i = 0; i < 18; i++)
-    supply_register (i, ((char *) buf) + regmap[i]);
+  for (i = 0; i < X86_64_NUM_GREGS; i++)
+    supply_register (i, ((char *) buf) + x86_64_regmap[i]);
 }
 
 static void
@@ -66,11 +69,19 @@ x86_64_store_fpregset (void *buf)
   i387_fxsave_to_cache (buf);
 }
 
-
 struct regset_info target_regsets[] = {
   { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
+    GENERAL_REGS,
     x86_64_fill_gregset, x86_64_store_gregset },
   { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
+    FP_REGS,
     x86_64_fill_fpregset, x86_64_store_fpregset },
-  { 0, 0, -1, NULL, NULL }
+  { 0, 0, -1, -1, NULL, NULL }
+};
+
+struct linux_target_ops the_low_target = {
+  -1,
+  NULL,
+  NULL,
+  NULL,
 };
diff -purN gdb-5.2.1-orig/gdb/gdbserver/low-linux.c gdb-5.2.1/gdb/gdbserver/low-linux.c
--- gdb-5.2.1-orig/gdb/gdbserver/low-linux.c	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/low-linux.c	Tue Sep  2 14:04:40 2003
@@ -0,0 +1,957 @@
+/* Low level interface to ptrace, for the remote server for GDB.
+   Copyright 1995, 1996, 1998, 1999, 2000, 2001
+   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 <sys/wait.h>
+#include "frame.h"
+#include "inferior.h"
+#include "nm.h"
+#include "xm.h"
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/ptrace.h>
+#include <sys/user.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+/***************Begin MY defs*********************/
+static char my_registers[REGISTER_BYTES];
+char *registers = my_registers;
+/***************End MY defs*********************/
+
+#ifdef HAVE_TARGET_ATTACH
+#ifdef GDB_TARGET_POWERPC
+#undef NUM_FREGS
+#undef NUM_REGS
+#define NUM_REGS	71
+#define NUM_FREGS       0
+
+static int regmap[] =
+{PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7,
+ PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_R13, PT_R14, PT_R15,
+ PT_R16, PT_R17, PT_R18, PT_R19, PT_R20, PT_R21, PT_R22, PT_R23,
+ PT_R24, PT_R25, PT_R26, PT_R27, PT_R28, PT_R29, PT_R30, PT_R31,
+ PT_FPR0, PT_FPR0 + 2, PT_FPR0 + 4, PT_FPR0 + 6, PT_FPR0 + 8, PT_FPR0 + 10, PT_FPR0 + 12, PT_FPR0 + 14,
+ PT_FPR0 + 16, PT_FPR0 + 18, PT_FPR0 + 20, PT_FPR0 + 22, PT_FPR0 + 24, PT_FPR0 + 26, PT_FPR0 + 28, PT_FPR0 + 30,
+ PT_FPR0 + 32, PT_FPR0 + 34, PT_FPR0 + 36, PT_FPR0 + 38, PT_FPR0 + 40, PT_FPR0 + 42, PT_FPR0 + 44, PT_FPR0 + 46,
+ PT_FPR0 + 48, PT_FPR0 + 50, PT_FPR0 + 52, PT_FPR0 + 54, PT_FPR0 + 56, PT_FPR0 + 58, PT_FPR0 + 60, PT_FPR0 + 62,
+ PT_NIP, PT_MSR, PT_CCR, PT_LNK, PT_CTR, PT_XER, PT_MQ};
+
+int 
+ppc_register_u_addr (int ustart, int regnum)
+{
+  return (ustart + 4 * regmap[regnum]);
+}
+
+static void
+initialize_arch ()
+{
+  return;
+}
+
+#elif defined(GDB_TARGET_POWERPC)
+static int regmap[] =
+ {PT_R0,     PT_R1,     PT_R2,     PT_R3,     PT_R4,     PT_R5,     PT_R6,	PT_R7,
+  PT_R8,     PT_R9,     PT_R10,    PT_R11,    PT_R12,    PT_R13,    PT_R14,	PT_R15,
+  PT_R16,    PT_R17,    PT_R18,    PT_R19,    PT_R20,    PT_R21,    PT_R22,	PT_R23,
+  PT_R24,    PT_R25,    PT_R26,    PT_R27,    PT_R28,    PT_R29,    PT_R30,	PT_R31,
+  PT_FPR0,   PT_FPR0+2, PT_FPR0+4, PT_FPR0+6, PT_FPR0+8, PT_FPR0+10,PT_FPR0+12,PT_FPR0+14,
+  PT_FPR0+16,PT_FPR0+18,PT_FPR0+20,PT_FPR0+22,PT_FPR0+24,PT_FPR0+26,PT_FPR0+28,PT_FPR0+30,
+  PT_FPR0+32,PT_FPR0+34,PT_FPR0+36,PT_FPR0+38,PT_FPR0+40,PT_FPR0+42,PT_FPR0+44,PT_FPR0+46,
+  PT_FPR0+48,PT_FPR0+50,PT_FPR0+52,PT_FPR0+54,PT_FPR0+56,PT_FPR0+58,PT_FPR0+60,PT_FPR0+62,
+  PT_NIP,    PT_MSR,    PT_CCR,    PT_LNK,    PT_CTR,    PT_XER,    PT_MQ };
+
+int ppc_register_u_addr(int ustart, int regnum)
+{
+    return (ustart + 4 * regmap[regnum]);
+}
+static void
+ initialize_arch ()
+{
+  return;
+}
+
+#undef HAVE_SYS_REG_H
+#endif
+#endif
+#ifdef HAVE_SYS_REG_H
+#include <sys/reg.h>
+#endif
+
+/* Default the type of the ptrace transfer to int.  */
+#ifndef PTRACE_XFER_TYPE
+#define PTRACE_XFER_TYPE int
+#endif
+
+extern int errno;
+
+static void initialize_arch (void);
+
+/* Start an inferior process and returns its pid.
+   ALLARGS is a vector of program-name and args. */
+
+int
+create_inferior (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 (void)
+{
+  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 (int pid)
+{
+  return 1;
+}
+
+/* Wait for process, returns status */
+
+unsigned char
+mywait (char *status)
+{
+  int pid;
+  union wait w;
+
+  enable_async_io ();
+#ifdef HAVE_TARGET_ATTACH
+  pid = wait (&w);
+#else
+  pid = waitpid (inferior_pid, &w, 0);
+#endif  
+  disable_async_io ();
+  if (pid != inferior_pid)
+#ifdef HAVE_TARGET_ATTACH
+  {
+	  if (errno) perror_with_name ("wait");
+	  inferior_pid=pid;
+  }
+#else
+    perror_with_name ("wait");
+#endif    
+
+  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 (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
+
+#ifdef I386_GNULINUX_TARGET
+/* This module only supports access to the general purpose registers.
+   Adjust the relevant constants accordingly.
+
+   FIXME: kettenis/2001-03-28: We should really use PTRACE_GETREGS to
+   get at the registers.  Better yet, we should try to share code with
+   i386-linux-nat.c.  */
+#undef NUM_FREGS
+#define NUM_FREGS 0
+#undef NUM_REGS
+#define NUM_REGS NUM_GREGS
+
+/* This stuff comes from i386-tdep.c.  */
+
+/* i386_register_byte[i] is the offset into the register file of the
+   start of register number i.  We initialize this from
+   i386_register_raw_size.  */
+int i386_register_byte[MAX_NUM_REGS];
+
+/* i386_register_raw_size[i] is the number of bytes of storage in
+   GDB's register array occupied by register i.  */
+int i386_register_raw_size[MAX_NUM_REGS] = {
+   4,  4,  4,  4,
+   4,  4,  4,  4,
+   4,  4,  4,  4,
+   4,  4,  4,  4,
+  10, 10, 10, 10,
+  10, 10, 10, 10,
+   4,  4,  4,  4,
+   4,  4,  4,  4,
+  16, 16, 16, 16,
+  16, 16, 16, 16,
+   4
+};
+
+static void
+initialize_arch (void)
+{
+  /* Initialize the table saying where each register starts in the
+     register file.  */
+  {
+    int i, offset;
+
+    offset = 0;
+    for (i = 0; i < MAX_NUM_REGS; i++)
+      {
+	i386_register_byte[i] = offset;
+	offset += i386_register_raw_size[i];
+      }
+  }
+}
+
+/* This stuff comes from i386-linux-nat.c.  */
+
+/* Mapping between the general-purpose registers in `struct user'
+   format and GDB's register array layout.  */
+static int regmap[] = 
+{
+  EAX, ECX, EDX, EBX,
+  UESP, EBP, ESI, EDI,
+  EIP, EFL, CS, SS,
+  DS, ES, FS, GS
+};
+
+/* Return the address of register REGNUM.  BLOCKEND is the value of
+   u.u_ar0, which should point to the registers.  */
+
+CORE_ADDR
+register_u_addr (CORE_ADDR blockend, int regnum)
+{
+  return (blockend + 4 * regmap[regnum]);
+}
+#elif defined(TARGET_M68K)
+static void
+initialize_arch (void)
+{
+  return;
+}
+
+/* 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 (int blockend, int regnum)
+{
+  return (blockend + 4 * regmap[regnum]);
+}
+#elif defined(IA64_GNULINUX_TARGET)
+#undef NUM_FREGS
+#define NUM_FREGS 0
+
+#include <asm/ptrace_offsets.h>
+
+static int u_offsets[] =
+  {
+    /* general registers */
+    -1,		/* gr0 not available; i.e, it's always zero */
+    PT_R1,
+    PT_R2,
+    PT_R3,
+    PT_R4,
+    PT_R5,
+    PT_R6,
+    PT_R7,
+    PT_R8,
+    PT_R9,
+    PT_R10,
+    PT_R11,
+    PT_R12,
+    PT_R13,
+    PT_R14,
+    PT_R15,
+    PT_R16,
+    PT_R17,
+    PT_R18,
+    PT_R19,
+    PT_R20,
+    PT_R21,
+    PT_R22,
+    PT_R23,
+    PT_R24,
+    PT_R25,
+    PT_R26,
+    PT_R27,
+    PT_R28,
+    PT_R29,
+    PT_R30,
+    PT_R31,
+    /* gr32 through gr127 not directly available via the ptrace interface */
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    /* Floating point registers */
+    -1, -1,	/* f0 and f1 not available (f0 is +0.0 and f1 is +1.0) */
+    PT_F2,
+    PT_F3,
+    PT_F4,
+    PT_F5,
+    PT_F6,
+    PT_F7,
+    PT_F8,
+    PT_F9,
+    PT_F10,
+    PT_F11,
+    PT_F12,
+    PT_F13,
+    PT_F14,
+    PT_F15,
+    PT_F16,
+    PT_F17,
+    PT_F18,
+    PT_F19,
+    PT_F20,
+    PT_F21,
+    PT_F22,
+    PT_F23,
+    PT_F24,
+    PT_F25,
+    PT_F26,
+    PT_F27,
+    PT_F28,
+    PT_F29,
+    PT_F30,
+    PT_F31,
+    PT_F32,
+    PT_F33,
+    PT_F34,
+    PT_F35,
+    PT_F36,
+    PT_F37,
+    PT_F38,
+    PT_F39,
+    PT_F40,
+    PT_F41,
+    PT_F42,
+    PT_F43,
+    PT_F44,
+    PT_F45,
+    PT_F46,
+    PT_F47,
+    PT_F48,
+    PT_F49,
+    PT_F50,
+    PT_F51,
+    PT_F52,
+    PT_F53,
+    PT_F54,
+    PT_F55,
+    PT_F56,
+    PT_F57,
+    PT_F58,
+    PT_F59,
+    PT_F60,
+    PT_F61,
+    PT_F62,
+    PT_F63,
+    PT_F64,
+    PT_F65,
+    PT_F66,
+    PT_F67,
+    PT_F68,
+    PT_F69,
+    PT_F70,
+    PT_F71,
+    PT_F72,
+    PT_F73,
+    PT_F74,
+    PT_F75,
+    PT_F76,
+    PT_F77,
+    PT_F78,
+    PT_F79,
+    PT_F80,
+    PT_F81,
+    PT_F82,
+    PT_F83,
+    PT_F84,
+    PT_F85,
+    PT_F86,
+    PT_F87,
+    PT_F88,
+    PT_F89,
+    PT_F90,
+    PT_F91,
+    PT_F92,
+    PT_F93,
+    PT_F94,
+    PT_F95,
+    PT_F96,
+    PT_F97,
+    PT_F98,
+    PT_F99,
+    PT_F100,
+    PT_F101,
+    PT_F102,
+    PT_F103,
+    PT_F104,
+    PT_F105,
+    PT_F106,
+    PT_F107,
+    PT_F108,
+    PT_F109,
+    PT_F110,
+    PT_F111,
+    PT_F112,
+    PT_F113,
+    PT_F114,
+    PT_F115,
+    PT_F116,
+    PT_F117,
+    PT_F118,
+    PT_F119,
+    PT_F120,
+    PT_F121,
+    PT_F122,
+    PT_F123,
+    PT_F124,
+    PT_F125,
+    PT_F126,
+    PT_F127,
+    /* predicate registers - we don't fetch these individually */
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    /* branch registers */
+    PT_B0,
+    PT_B1,
+    PT_B2,
+    PT_B3,
+    PT_B4,
+    PT_B5,
+    PT_B6,
+    PT_B7,
+    /* virtual frame pointer and virtual return address pointer */
+    -1, -1,
+    /* other registers */
+    PT_PR,
+    PT_CR_IIP,	/* ip */
+    PT_CR_IPSR, /* psr */
+    PT_CFM,	/* cfm */
+    /* kernel registers not visible via ptrace interface (?) */
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    /* hole */
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    PT_AR_RSC,
+    PT_AR_BSP,
+    PT_AR_BSPSTORE,
+    PT_AR_RNAT,
+    -1,
+    -1,		/* Not available: FCR, IA32 floating control register */
+    -1, -1,
+    -1,		/* Not available: EFLAG */
+    -1,		/* Not available: CSD */
+    -1,		/* Not available: SSD */
+    -1,		/* Not available: CFLG */
+    -1,		/* Not available: FSR */
+    -1,		/* Not available: FIR */
+    -1,		/* Not available: FDR */
+    -1,
+    PT_AR_CCV,
+    -1, -1, -1,
+    PT_AR_UNAT,
+    -1, -1, -1,
+    PT_AR_FPSR,
+    -1, -1, -1,
+    -1,		/* Not available: ITC */
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    PT_AR_PFS,
+    PT_AR_LC,
+    -1,		/* Not available: EC, the Epilog Count register */
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1,
+    /* nat bits - not fetched directly; instead we obtain these bits from
+       either rnat or unat or from memory. */
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,
+  };
+
+int
+ia64_register_u_addr (int blockend, int regnum)
+{
+  int addr;
+
+  if (regnum < 0 || regnum >= NUM_REGS)
+    error ("Invalid register number %d.", regnum);
+
+  addr = u_offsets[regnum];
+  if (addr == -1)
+    addr = 0;
+
+  return addr;
+}
+
+static void
+initialize_arch (void)
+{
+  return;
+}
+#elif defined (ARM_GNULINUX_TARGET)
+static void
+    initialize_arch()
+    {
+      return;
+    }
+int arm_linux_register_u_addr(int blockend, int regnum)
+{
+    return blockend + REGISTER_BYTE (regnum);
+}
+#endif
+
+CORE_ADDR
+register_addr (int regno, CORE_ADDR blockend)
+{
+  CORE_ADDR addr;
+
+  if (regno < 0 || regno >= NUM_REGS)
+    error ("Invalid register number %d.", regno);
+
+  REGISTER_U_ADDR (addr, blockend, regno);
+
+  return addr;
+}
+
+/* Fetch one register.  */
+
+static void
+fetch_register (int regno)
+{
+  CORE_ADDR 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 (PTRACE_XFER_TYPE))
+    {
+      errno = 0;
+      *(PTRACE_XFER_TYPE *) &registers[REGISTER_BYTE (regno) + i] =
+	ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0);
+      regaddr += sizeof (PTRACE_XFER_TYPE);
+      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 (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 (int regno)
+{
+  CORE_ADDR regaddr;
+  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_POKEUSER, 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 (CORE_ADDR memaddr, char *myaddr, int len)
+{
+  register int i;
+  /* Round starting address down to longword boundary.  */
+  register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
+  /* Round ending address up; get number of longwords that makes.  */
+  register int count 
+    = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) 
+      / sizeof (PTRACE_XFER_TYPE);
+  /* Allocate buffer of that many longwords.  */
+  register PTRACE_XFER_TYPE *buffer 
+    = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
+
+  /* Read all the longwords */
+  for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+    {
+      buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, addr, 0);
+    }
+
+  /* Copy appropriate bytes out of the buffer.  */
+  memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 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 (CORE_ADDR memaddr, char *myaddr, int len)
+{
+  register int i;
+  /* Round starting address down to longword boundary.  */
+  register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
+  /* Round ending address up; get number of longwords that makes.  */
+  register int count
+  = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE);
+  /* Allocate buffer of that many longwords.  */
+  register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
+  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 (PTRACE_XFER_TYPE), 0);
+    }
+
+  /* Copy data to be written over corresponding part of buffer */
+
+  memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), myaddr, len);
+
+  /* Write the entire buffer.  */
+
+  for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+    {
+      errno = 0;
+      ptrace (PTRACE_POKETEXT, inferior_pid, addr, buffer[i]);
+      if (errno)
+	return errno;
+    }
+
+  return 0;
+}
+
+void
+initialize_low (void)
+{
+  initialize_arch ();
+}
+#ifdef HAVE_TARGET_ATTACH
+int
+process_attach (int pid)
+{
+  if (remote_debug)
+	printf("process_attach: pid=%d\n\r", pid);
+
+  if (pid == getpid())
+    return -1;
+
+  errno = 0;
+  ptrace(PTRACE_ATTACH, pid, (PTRACE_ARG3_TYPE)0, 0);
+  return errno ? -1 : pid;
+}
+
+int
+process_detach(int sig)
+{
+  memset(registers, 0, sizeof(registers));
+
+  if (remote_debug)
+   printf("process_detach: pid=%d, signal = %d\n\r",inferior_pid,sig);
+
+  if (!inferior_pid)
+    return -1;
+  fprintf(stderr, "Detaching process %d with signal %d...\n",inferior_pid, sig);
+  ptrace(PTRACE_DETACH, inferior_pid, (PTRACE_ARG3_TYPE)sig, 0);
+  inferior_pid = 0;
+  return 0;
+}
+
+#endif
+
+#ifdef HAVE_TARGET_SHELL
+extern int remote_desc;
+static void
+my_perror(char *s)
+{
+  const char *err;
+
+  if (errno < sys_nerr)
+    err = sys_errlist[errno];
+  else
+    err = "unknown error";
+  fprintf(stderr, "%s: ", s);
+  error(err);
+}
+
+void
+exec_shellcmd(char *args)
+{
+ int fd[2];
+ int pid, saved_pid = inferior_pid;
+ char len;
+ char buf[100];	/* must be <128 */
+ char **shell, *argv[100], **argp, *p;
+ static char *shells[] = {
+	"/bin/sh", "/bin/bash", "/bin/tcsh",
+	"/usr/bin/sh", "/usr/bin/bash", "/usr/bin/tsch", (char *)0};
+
+  if (pipe(fd))
+    perror_with_name("opening pipe");
+
+  switch (pid = fork())
+    {
+    case -1:
+      perror_with_name("forking exec shell");
+      break;
+
+    case 0:
+      /* disable stdin */
+      close(0);
+      open("/dev/null", O_RDONLY);
+
+      /* redirect stdout and stderr to pipe */
+      if (dup2(fd[1], 1) != 1 || dup2(fd[1], 2) != 2)
+	{
+          my_perror("dup in exec shell");
+	  exit(1);
+	}
+
+      /* which shell? */
+      for (shell = shells; *shell; shell++)
+	if (access(*shell, X_OK) == 0)
+	  break;
+      if (*shell)
+        execlp(*shell, *shell, "-c", args, (char *)0);
+      else
+	{/* No shell installed. Exec it directly */
+	  for (p = args, argp = argv;
+		*p && argp < &argv[sizeof(argv)/sizeof(argv[0])] - 1; )
+	    {
+	      *argp++ = p;
+	      while (*p && !isspace(*p))
+		p++;	/* skip word */
+	      if (!*p)
+		break;	/* no more chars */
+	      *p++ = '\0';
+	      while (isspace(*p))
+		p++;	/* skip delimiting spaces */
+	      if (!*p)
+		break;	/* no more chars */
+	    }
+	  *argp = (char *)0;
+          execvp(*argv, argv);
+	}
+
+      my_perror("exec shell");
+      exit(1);
+      break;
+
+    default:	/* Parent - gdbserver */
+      close(fd[1]);	/* To get EOF properly */
+      enable_async_io();
+      inferior_pid = pid;		/* fake process ID */
+      while (1)
+	{
+          if ((len = read(fd[0], buf, sizeof buf)) > 0)
+	    {
+	      write(remote_desc, &len, 1);
+	      write(remote_desc, buf, len);
+	    }
+	  else if (len != -1 || errno != EINTR)
+	    break;
+	}
+      write(remote_desc, &len, 1);	/* end mark (0) */
+      waitpid(pid, (void *)0, 0);
+      inferior_pid = saved_pid;
+      disable_async_io();
+    }
+}
+#endif
diff -purN gdb-5.2.1-orig/gdb/gdbserver/mem-break.c gdb-5.2.1/gdb/gdbserver/mem-break.c
--- gdb-5.2.1-orig/gdb/gdbserver/mem-break.c	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/mem-break.c	Tue Sep  2 14:04:41 2003
@@ -0,0 +1,280 @@
+/* Memory breakpoint operations for the remote server for GDB.
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   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"
+
+const char *breakpoint_data;
+int breakpoint_len;
+
+#define MAX_BREAKPOINT_LEN 8
+
+struct breakpoint
+{
+  struct breakpoint *next;
+  CORE_ADDR pc;
+  unsigned char old_data[MAX_BREAKPOINT_LEN];
+
+  /* Non-zero iff we are stepping over this breakpoint.  */
+  int reinserting;
+
+  /* Non-NULL iff this breakpoint was inserted to step over
+     another one.  Points to the other breakpoint (which is also
+     in the *next chain somewhere).  */
+  struct breakpoint *breakpoint_to_reinsert;
+
+  /* Function to call when we hit this breakpoint.  */
+  void (*handler) (CORE_ADDR);
+};
+
+struct breakpoint *breakpoints;
+
+void
+set_breakpoint_at (CORE_ADDR where, void (*handler) (CORE_ADDR))
+{
+  struct breakpoint *bp;
+
+  if (breakpoint_data == NULL)
+    error ("Target does not support breakpoints.");
+
+  bp = malloc (sizeof (struct breakpoint));
+  memset (bp, 0, sizeof (struct breakpoint));
+
+  (*the_target->read_memory) (where, bp->old_data,
+			      breakpoint_len);
+  (*the_target->write_memory) (where, breakpoint_data,
+			       breakpoint_len);
+
+  bp->pc = where;
+  bp->handler = handler;
+
+  bp->next = breakpoints;
+  breakpoints = bp;
+}
+
+void
+delete_breakpoint (struct breakpoint *bp)
+{
+  struct breakpoint *cur;
+
+  if (breakpoints == bp)
+    {
+      breakpoints = bp->next;
+      (*the_target->write_memory) (bp->pc, bp->old_data,
+				   breakpoint_len);
+      free (bp);
+      return;
+    }
+  cur = breakpoints;
+  while (cur->next)
+    {
+      if (cur->next == bp)
+	{
+	  cur->next = bp->next;
+	  (*the_target->write_memory) (bp->pc, bp->old_data,
+				       breakpoint_len);
+	  free (bp);
+	  return;
+	}
+    }
+  warning ("Could not find breakpoint in list.");
+}
+
+struct breakpoint *
+find_breakpoint_at (CORE_ADDR where)
+{
+  struct breakpoint *bp = breakpoints;
+
+  while (bp != NULL)
+    {
+      if (bp->pc == where)
+	return bp;
+      bp = bp->next;
+    }
+
+  return NULL;
+}
+
+static void
+reinsert_breakpoint_handler (CORE_ADDR stop_pc)
+{
+  struct breakpoint *stop_bp, *orig_bp;
+
+  stop_bp = find_breakpoint_at (stop_pc);
+  if (stop_bp == NULL)
+    error ("lost the stopping breakpoint.");
+
+  orig_bp = stop_bp->breakpoint_to_reinsert;
+  if (orig_bp == NULL)
+    error ("no breakpoint to reinsert");
+
+  (*the_target->write_memory) (orig_bp->pc, breakpoint_data,
+			       breakpoint_len);
+  orig_bp->reinserting = 0;
+  delete_breakpoint (stop_bp);
+}
+
+void
+reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at)
+{
+  struct breakpoint *bp, *orig_bp;
+
+  set_breakpoint_at (stop_at, reinsert_breakpoint_handler);
+
+  orig_bp = find_breakpoint_at (stop_pc);
+  if (orig_bp == NULL)
+    error ("Could not find original breakpoint in list.");
+
+  bp = find_breakpoint_at (stop_at);
+  if (bp == NULL)
+    error ("Could not find breakpoint in list (reinserting by breakpoint).");
+  bp->breakpoint_to_reinsert = orig_bp;
+
+  (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data,
+			       breakpoint_len);
+  orig_bp->reinserting = 1;
+}
+
+void
+uninsert_breakpoint (CORE_ADDR stopped_at)
+{
+  struct breakpoint *bp;
+
+  bp = find_breakpoint_at (stopped_at);
+  if (bp == NULL)
+    error ("Could not find breakpoint in list (uninserting).");
+
+  (*the_target->write_memory) (bp->pc, bp->old_data,
+			       breakpoint_len);
+  bp->reinserting = 1;
+}
+
+void
+reinsert_breakpoint (CORE_ADDR stopped_at)
+{
+  struct breakpoint *bp;
+
+  bp = find_breakpoint_at (stopped_at);
+  if (bp == NULL)
+    error ("Could not find breakpoint in list (uninserting).");
+  if (! bp->reinserting)
+    error ("Breakpoint already inserted at reinsert time.");
+
+  (*the_target->write_memory) (bp->pc, breakpoint_data,
+			       breakpoint_len);
+  bp->reinserting = 0;
+}
+
+int
+check_breakpoints (CORE_ADDR stop_pc)
+{
+  struct breakpoint *bp;
+
+  bp = find_breakpoint_at (stop_pc);
+  if (bp == NULL)
+    return 0;
+  if (bp->reinserting)
+    {
+      warning ("Hit a removed breakpoint?");
+      return 0;
+    }
+
+  (*bp->handler) (bp->pc);
+  return 1;
+}
+
+void
+set_breakpoint_data (const char *bp_data, int bp_len)
+{
+  breakpoint_data = bp_data;
+  breakpoint_len = bp_len;
+}
+
+void
+check_mem_read (CORE_ADDR mem_addr, char *buf, int mem_len)
+{
+  struct breakpoint *bp = breakpoints;
+  CORE_ADDR mem_end = mem_addr + mem_len;
+
+  for (; bp != NULL; bp = bp->next)
+    {
+      CORE_ADDR bp_end = bp->pc + breakpoint_len;
+      CORE_ADDR start, end;
+      int copy_offset, copy_len, buf_offset;
+
+      if (mem_addr >= bp_end)
+	continue;
+      if (bp->pc >= mem_end)
+	continue;
+
+      start = bp->pc;
+      if (mem_addr > start)
+	start = mem_addr;
+
+      end = bp_end;
+      if (end > mem_end)
+	end = mem_end;
+
+      copy_len = end - start;
+      copy_offset = start - bp->pc;
+      buf_offset = start - mem_addr;
+
+      memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
+    }
+}
+
+void
+check_mem_write (CORE_ADDR mem_addr, char *buf, int mem_len)
+{
+  struct breakpoint *bp = breakpoints;
+  CORE_ADDR mem_end = mem_addr + mem_len;
+
+  for (; bp != NULL; bp = bp->next)
+    {
+      CORE_ADDR bp_end = bp->pc + breakpoint_len;
+      CORE_ADDR start, end;
+      int copy_offset, copy_len, buf_offset;
+
+      if (mem_addr >= bp_end)
+	continue;
+      if (bp->pc >= mem_end)
+	continue;
+
+      start = bp->pc;
+      if (mem_addr > start)
+	start = mem_addr;
+
+      end = bp_end;
+      if (end > mem_end)
+	end = mem_end;
+
+      copy_len = end - start;
+      copy_offset = start - bp->pc;
+      buf_offset = start - mem_addr;
+
+      memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
+      if (bp->reinserting == 0)
+	memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
+    }
+}
+
+
diff -purN gdb-5.2.1-orig/gdb/gdbserver/mem-break.h gdb-5.2.1/gdb/gdbserver/mem-break.h
--- gdb-5.2.1-orig/gdb/gdbserver/mem-break.h	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/mem-break.h	Tue Sep  2 14:04:41 2003
@@ -0,0 +1,76 @@
+/* Memory breakpoint interfaces for the remote server for GDB.
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   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.  */
+
+#ifndef MEM_BREAK_H
+#define MEM_BREAK_H
+
+/* Breakpoints are opaque.  */
+
+/* Create a new breakpoint at WHERE, and call HANDLER when
+   it is hit.  */
+
+void set_breakpoint_at (CORE_ADDR where,
+			void (*handler) (CORE_ADDR));
+
+#ifdef HAVE_TARGET_ATTACH
+struct breakpoint *find_breakpoint_at (CORE_ADDR where);
+void delete_breakpoint (struct breakpoint *bp);
+#endif
+
+/* Create a reinsertion breakpoint at STOP_AT for the breakpoint
+   currently at STOP_PC (and temporarily remove the breakpoint at
+   STOP_PC).  */
+
+void reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at);
+
+/* Change the status of the breakpoint at WHERE to inserted.  */
+
+void reinsert_breakpoint (CORE_ADDR where);
+
+/* Change the status of the breakpoint at WHERE to uninserted.  */
+
+void uninsert_breakpoint (CORE_ADDR where);
+
+/* See if any breakpoint claims ownership of STOP_PC.  Call the handler for
+   the breakpoint, if found.  */
+
+int check_breakpoints (CORE_ADDR stop_pc);
+
+/* See if any breakpoints shadow the target memory area from MEM_ADDR
+   to MEM_ADDR + MEM_LEN.  Update the data already read from the target
+   (in BUF) if necessary.  */
+
+void check_mem_read (CORE_ADDR mem_addr, char *buf, int mem_len);
+
+/* See if any breakpoints shadow the target memory area from MEM_ADDR
+   to MEM_ADDR + MEM_LEN.  Update the data to be written to the target
+   (in BUF) if necessary, as well as the original data for any breakpoints.  */
+
+void check_mem_write (CORE_ADDR mem_addr, char *buf, int mem_len);
+
+/* Set the byte pattern to insert for memory breakpoints.  This function
+   must be called before any breakpoints are set.  */
+
+void set_breakpoint_data (const char *bp_data, int bp_len);
+
+#endif /* MEM_BREAK_H */
diff -purN gdb-5.2.1-orig/gdb/gdbserver/proc-service.c gdb-5.2.1/gdb/gdbserver/proc-service.c
--- gdb-5.2.1-orig/gdb/gdbserver/proc-service.c	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/proc-service.c	Tue Sep  2 14:04:41 2003
@@ -0,0 +1,256 @@
+/* libthread_db helper functions for the remote server for GDB.
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   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"
+
+/* This file is currently tied to GNU/Linux.  It should scale well to
+   another libthread_db implementation, with the approriate gdbserver
+   hooks, but for now this means we can use GNU/Linux's target data.  */
+
+#include "linux-low.h"
+
+/* Correct for all GNU/Linux targets (for quite some time).  */
+#define GDB_GREGSET_T elf_gregset_t
+#define GDB_FPREGSET_T elf_fpregset_t
+
+#ifndef HAVE_ELF_FPREGSET_T
+/* Make sure we have said types.  Not all platforms bring in <linux/elf.h>
+   via <sys/procfs.h>.  */
+#ifdef HAVE_LINUX_ELF_H
+#include <linux/elf.h>
+#endif
+#endif
+
+#include "../gdb_proc_service.h"
+
+typedef struct ps_prochandle *gdb_ps_prochandle_t;
+typedef void *gdb_ps_read_buf_t;
+typedef const void *gdb_ps_write_buf_t;
+typedef size_t gdb_ps_size_t;
+
+/* FIXME redo this right */
+#if 0
+#ifndef HAVE_LINUX_REGSETS
+#error HAVE_LINUX_REGSETS required!
+#else
+static struct regset_info *
+gregset_info(void)
+{
+  int i = 0;
+
+  while (target_regsets[i].size != -1)
+    {
+      if (target_regsets[i].type == GENERAL_REGS)
+       break;
+      i++;
+    }
+
+  return &target_regsets[i];
+}
+
+static struct regset_info *
+fpregset_info(void)
+{
+  int i = 0;
+
+  while (target_regsets[i].size != -1)
+    {
+      if (target_regsets[i].type == FP_REGS)
+       break;
+      i++;
+    }
+
+  return &target_regsets[i];
+}
+#endif
+#endif
+
+/* Search for the symbol named NAME within the object named OBJ within
+   the target process PH.  If the symbol is found the address of the
+   symbol is stored in SYM_ADDR.  */
+
+ps_err_e
+ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj,
+                  const char *name, paddr_t *sym_addr)
+{
+  CORE_ADDR addr;
+
+  if (look_up_one_symbol (name, &addr) == 0)
+    return PS_NOSYM;
+
+  *sym_addr = (paddr_t) (unsigned long) addr;
+  return PS_OK;
+}
+
+/* Read SIZE bytes from the target process PH at address ADDR and copy
+   them into BUF.  */
+
+ps_err_e
+ps_pdread (gdb_ps_prochandle_t ph, paddr_t addr,
+          gdb_ps_read_buf_t buf, gdb_ps_size_t size)
+{
+  read_inferior_memory (addr, buf, size);
+  return PS_OK;
+}
+
+/* Write SIZE bytes from BUF into the target process PH at address ADDR.  */
+
+ps_err_e
+ps_pdwrite (gdb_ps_prochandle_t ph, paddr_t addr,
+           gdb_ps_write_buf_t buf, gdb_ps_size_t size)
+{
+  return write_inferior_memory (addr, buf, size);
+}
+
+/* Get the general registers of LWP LWPID within the target process PH
+   and store them in GREGSET.  */
+
+ps_err_e
+ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
+{
+#if 0
+  struct thread_info *reg_inferior, *save_inferior;
+  void *regcache;
+
+  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads,
+                                                         lwpid);
+  if (reg_inferior == NULL)
+    return PS_ERR;
+
+  save_inferior = current_inferior;
+  current_inferior = reg_inferior;
+
+  regcache = new_register_cache ();
+  the_target->fetch_registers (0, regcache);
+  gregset_info()->fill_function (gregset, regcache);
+  free_register_cache (regcache);
+
+  current_inferior = save_inferior;
+  return PS_OK;
+#endif
+  /* FIXME */
+  return PS_ERR;
+}
+
+/* Set the general registers of LWP LWPID within the target process PH
+   from GREGSET.  */
+
+ps_err_e
+ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset)
+{
+#if 0
+  struct thread_info *reg_inferior, *save_inferior;
+  void *regcache;
+
+  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+  if (reg_inferior == NULL)
+    return PS_ERR;
+
+  save_inferior = current_inferior;
+  current_inferior = reg_inferior;
+
+  regcache = new_register_cache ();
+  gregset_info()->store_function (gregset, regcache);
+  the_target->store_registers (0, regcache);
+  free_register_cache (regcache);
+
+  current_inferior = save_inferior;
+
+  return PS_OK;
+#endif
+  /* FIXME */
+  return PS_ERR;
+}
+
+/* Get the floating-point registers of LWP LWPID within the target
+   process PH and store them in FPREGSET.  */
+
+ps_err_e
+ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+              gdb_prfpregset_t *fpregset)
+{
+#if 0
+  struct thread_info *reg_inferior, *save_inferior;
+  void *regcache;
+
+  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+  if (reg_inferior == NULL)
+    return PS_ERR;
+
+  save_inferior = current_inferior;
+  current_inferior = reg_inferior;
+
+  regcache = new_register_cache ();
+  the_target->fetch_registers (0, regcache);
+  fpregset_info()->fill_function (fpregset, regcache);
+  free_register_cache (regcache);
+
+  current_inferior = save_inferior;
+
+  return PS_OK;
+#endif
+  /* FIXME */
+  return PS_ERR;
+}
+
+/* Set the floating-point registers of LWP LWPID within the target
+   process PH from FPREGSET.  */
+
+ps_err_e
+ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+              const gdb_prfpregset_t *fpregset)
+{
+#if 0
+  struct thread_info *reg_inferior, *save_inferior;
+  void *regcache;
+
+  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+  if (reg_inferior == NULL)
+    return PS_ERR;
+
+  save_inferior = current_inferior;
+  current_inferior = reg_inferior;
+
+  regcache = new_register_cache ();
+  fpregset_info()->store_function (fpregset, regcache);
+  the_target->store_registers (0, regcache);
+  free_register_cache (regcache);
+
+  current_inferior = save_inferior;
+
+  return PS_OK;
+#endif
+  /* FIXME */
+  return PS_ERR;
+}
+
+/* Return overall process id of the target PH.  Special for GNU/Linux
+   -- not used on Solaris.  */
+
+pid_t
+ps_getpid (gdb_ps_prochandle_t ph)
+{
+  return ph->pid;
+}
+
+
diff -purN gdb-5.2.1-orig/gdb/gdbserver/regcache.c gdb-5.2.1/gdb/gdbserver/regcache.c
--- gdb-5.2.1-orig/gdb/gdbserver/regcache.c	Wed Feb 27 08:07:39 2002
+++ gdb-5.2.1/gdb/gdbserver/regcache.c	Tue Sep  2 14:04:41 2003
@@ -25,7 +25,12 @@
 #include <stdlib.h>
 #include <string.h>
 
-static char *registers;
+struct inferior_regcache_data
+{
+  int registers_valid;
+  char *registers;
+};
+
 static int register_bytes;
 
 static struct reg *reg_defs;
@@ -33,12 +38,84 @@ static int num_registers;
 
 const char **gdbserver_expedite_regs;
 
+static struct inferior_regcache_data *
+get_regcache (struct thread_info *inf, int fetch)
+{
+  struct inferior_regcache_data *regcache;
+
+  regcache = (struct inferior_regcache_data *) inferior_regcache_data (inf);
+
+  if (regcache == NULL)
+    fatal ("no register cache");
+
+  /* FIXME - fetch registers for INF */
+  if (fetch && regcache->registers_valid == 0)
+    {
+      fetch_inferior_registers (0);
+      regcache->registers_valid = 1;
+    }
+
+  return regcache;
+}
+
+void
+regcache_invalidate_one (struct inferior_list_entry *entry)
+{
+  struct thread_info *thread = (struct thread_info *) entry;
+  struct inferior_regcache_data *regcache;
+
+  regcache = (struct inferior_regcache_data *) inferior_regcache_data (thread);
+
+  if (regcache->registers_valid)
+    {
+      struct thread_info *saved_inferior = current_inferior;
+
+      current_inferior = thread;
+      store_inferior_registers (-1);
+      current_inferior = saved_inferior;
+    }
+
+  regcache->registers_valid = 0;
+}
+
+void
+regcache_invalidate ()
+{
+  for_each_inferior (&all_threads, regcache_invalidate_one);
+}
+
 int
 registers_length (void)
 {
   return 2 * register_bytes;
 }
 
+void *
+new_register_cache (void)
+{
+  struct inferior_regcache_data *regcache;
+
+  regcache = malloc (sizeof (*regcache));
+
+  regcache->registers = malloc (register_bytes);
+  if (regcache->registers == NULL)
+    fatal ("Could not allocate register cache.");
+
+  regcache->registers_valid = 0;
+
+  return regcache;
+}
+
+void
+free_register_cache (void *regcache_p)
+{
+  struct inferior_regcache_data *regcache
+    = (struct inferior_regcache_data *) regcache_p;
+
+  free (regcache->registers);
+  free (regcache);
+}
+
 void
 set_register_cache (struct reg *regs, int n)
 {
@@ -55,14 +132,13 @@ set_register_cache (struct reg *regs, in
     }
 
   register_bytes = offset / 8;
-  registers = malloc (offset / 8);
-  if (!registers)
-    fatal ("Could not allocate register cache.");
 }
 
 void
 registers_to_string (char *buf)
 {
+  char *registers = get_regcache (current_inferior, 1)->registers;
+
   convert_int_to_ascii (registers, buf, register_bytes);
 }
 
@@ -70,6 +146,7 @@ void
 registers_from_string (char *buf)
 {
   int len = strlen (buf);
+  char *registers = get_regcache (current_inferior, 1)->registers;
 
   if (len != register_bytes * 2)
     {
@@ -116,32 +193,40 @@ register_size (int n)
   return reg_defs[n].size / 8;
 }
 
-char *
-register_data (int n)
+static char *
+register_data (int n, int fetch)
 {
+  char *registers = get_regcache (current_inferior, fetch)->registers;
+
   return registers + (reg_defs[n].offset / 8);
 }
 
 void
-supply_register (int n, const char *buf)
+supply_register (int n, const void *buf)
 {
-  memcpy (register_data (n), buf, register_size (n));
+  memcpy (register_data (n, 0), buf, register_size (n));
 }
 
 void
-supply_register_by_name (const char *name, const char *buf)
+supply_register_by_name (const char *name, const void *buf)
 {
   supply_register (find_regno (name), buf);
 }
 
 void
-collect_register (int n, char *buf)
+collect_register (int n, void *buf)
+{
+  memcpy (buf, register_data (n, 1), register_size (n));
+}
+
+void
+collect_register_as_string (int n, char *buf)
 {
-  memcpy (buf, register_data (n), register_size (n));
+  convert_int_to_ascii (register_data (n, 1), buf, register_size (n));
 }
 
 void
-collect_register_by_name (const char *name, char *buf)
+collect_register_by_name (const char *name, void *buf)
 {
   collect_register (find_regno (name), buf);
 }
diff -purN gdb-5.2.1-orig/gdb/gdbserver/regcache.h gdb-5.2.1/gdb/gdbserver/regcache.h
--- gdb-5.2.1-orig/gdb/gdbserver/regcache.h	Thu Feb 14 07:21:22 2002
+++ gdb-5.2.1/gdb/gdbserver/regcache.h	Tue Sep  2 14:04:41 2003
@@ -21,6 +21,21 @@
 #ifndef REGCACHE_H
 #define REGCACHE_H
 
+struct inferior_list_entry;
+
+/* Create a new register cache for INFERIOR.  */
+
+void *new_register_cache (void);
+
+/* Release all memory associated with the register cache for INFERIOR.  */
+
+void free_register_cache (void *regcache);
+
+/* Invalidate cached registers for one or all threads.  */
+
+void regcache_invalidate_one (struct inferior_list_entry *);
+void regcache_invalidate (void);
+
 /* Convert all registers to a string in the currently specified remote
    format.  */
 
@@ -38,12 +53,20 @@ int registers_length (void);
 
 struct reg *find_register_by_number (int n);
 
-char *register_data (int n);
-
 int register_size (int n);
 
 int find_regno (const char *name);
 
 extern const char **gdbserver_expedite_regs;
 
+void supply_register (int n, const void *buf);
+
+void supply_register_by_name (const char *name, const void *buf);
+
+void collect_register (int n, void *buf);
+
+void collect_register_as_string (int n, char *buf);
+
+void collect_register_by_name (const char *name, void *buf);
+
 #endif /* REGCACHE_H */
diff -purN gdb-5.2.1-orig/gdb/gdbserver/regdef.h gdb-5.2.1/gdb/gdbserver/regdef.h
--- gdb-5.2.1-orig/gdb/gdbserver/regdef.h	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/regdef.h	Tue Sep  2 14:04:41 2003
@@ -0,0 +1,46 @@
+/* Register protocol definition structures for the GNU Debugger
+   Copyright 2001, 2002 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.  */
+
+#ifndef REGDEF_H
+#define REGDEF_H
+
+struct reg
+{
+  /* The name of this register - NULL for pad entries.  */
+  const char *name;
+
+  /* At the moment, both of the following bit counts must be divisible
+     by eight (to match the representation as two hex digits) and divisible
+     by the size of a byte (to match the layout of each register in
+     memory).  */
+
+  /* The offset (in bits) of the value of this register in the buffer.  */
+  int offset;
+
+  /* The size (in bits) of the value of this register, as transmitted.  */
+  int size;
+};
+
+/* Set the current remote protocol and register cache according to the array
+   ``regs'', with ``n'' elements.  */
+
+void set_register_cache (struct reg *regs, int n);
+
+#endif /* REGDEF_H */
diff -purN gdb-5.2.1-orig/gdb/gdbserver/remote-utils.c gdb-5.2.1/gdb/gdbserver/remote-utils.c
--- gdb-5.2.1-orig/gdb/gdbserver/remote-utils.c	Fri Mar 29 20:03:34 2002
+++ gdb-5.2.1/gdb/gdbserver/remote-utils.c	Tue Sep  2 14:04:41 2003
@@ -35,11 +35,19 @@
 #include <fcntl.h>
 #include <sys/time.h>
 #include <unistd.h>
+#include <arpa/inet.h>
 
 int remote_debug = 0;
 struct ui_file *gdb_stdlog;
 
+#ifdef HAVE_TARGET_ATTACH
+int remote_desc;
+#else
 static int remote_desc;
+#endif
+/* FIXME headerize? */
+extern int using_threads;
+extern int debug_threads;
 
 /* Open a connection to a remote debugger.
    NAME is the filename used for communication.  */
@@ -185,6 +193,42 @@ fromhex (int a)
   return 0;
 }
 
+int
+unhexify (char *bin, const char *hex, int count)
+{
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      if (hex[0] == 0 || hex[1] == 0)
+        {
+          /* Hex string is short, or of uneven length.
+             Return the count that has been converted so far. */
+          return i;
+        }
+      *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
+      hex += 2;
+    }
+  return i;
+}
+
+static void
+decode_address (CORE_ADDR *addrp, const char *start, int len)
+{
+  CORE_ADDR addr;
+  char ch;
+  int i;
+
+  addr = 0;
+  for (i = 0; i < len; i++)
+    {
+      ch = start[i];
+      addr = addr << 4;
+      addr = addr | (fromhex (ch) & 0x0f);
+    }
+  *addrp = addr;
+}
+
 /* Convert number NIB to a hex digit.  */
 
 static int
@@ -196,6 +240,24 @@ tohex (int nib)
     return 'a' + nib - 10;
 }
 
+int
+hexify (char *hex, const char *bin, int count)
+{
+  int i;
+
+  /* May use a length, or a nul-terminated string as input. */
+  if (count == 0)
+    count = strlen (bin);
+
+  for (i = 0; i < count; i++)
+    {
+      *hex++ = tohex ((*bin >> 4) & 0xf);
+      *hex++ = tohex (*bin++ & 0xf);
+    }
+  *hex = 0;
+  return i;
+}
+
 /* Send a packet to the remote machine, with error checking.
    The data of the packet is in BUF.  Returns >= 0 on success, -1 otherwise. */
 
@@ -241,10 +303,18 @@ putpkt (char *buf)
 	}
 
       if (remote_debug)
-	printf ("putpkt (\"%s\"); [looking for ack]\n", buf2);
+       {
+         fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2);
+         fflush (stderr);
+       }
+
       cc = read (remote_desc, buf3, 1);
       if (remote_debug)
-	printf ("[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
+       {
+         fprintf (stderr, "[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
+         fflush (stderr);
+       }
+
       if (cc <= 0)
 	{
 	  if (cc == 0)
@@ -255,6 +325,11 @@ putpkt (char *buf)
 	  free (buf2);
 	  return -1;
 	}
+
+      /* Check for an input interrupt while we're here.  */
+      if (buf3[0] == '\003')
+       kill ((*the_target->signal_pid) (), SIGINT);
+
     }
   while (buf3[0] != '+');
 
@@ -291,7 +366,7 @@ input_interrupt (int unused)
 	  return;
 	}
       
-      kill (inferior_pid, SIGINT);
+      kill ((*the_target->signal_pid) (), SIGINT);
     }
 }
 
@@ -356,7 +431,11 @@ getpkt (char *buf)
 	  if (c == '$')
 	    break;
 	  if (remote_debug)
-	    printf ("[getpkt: discarding char '%c']\n", c);
+           {
+             fprintf (stderr, "[getpkt: discarding char '%c']\n", c);
+             fflush (stderr);
+           }
+
 	  if (c < 0)
 	    return -1;
 	}
@@ -386,12 +465,19 @@ getpkt (char *buf)
     }
 
   if (remote_debug)
-    printf ("getpkt (\"%s\");  [sending ack] \n", buf);
+    {
+      fprintf (stderr, "getpkt (\"%s\");  [sending ack] \n", buf);
+      fflush (stderr);
+    }
 
   write (remote_desc, "+", 1);
 
   if (remote_debug)
-    printf ("[sent ack]\n");
+    {
+      fprintf (stderr, "[sent ack]\n");
+      fflush (stderr);
+    }
+
   return bp - buf;
 }
 
@@ -444,8 +530,6 @@ convert_ascii_to_int (char *from, char *
 static char *
 outreg (int regno, char *buf)
 {
-  int regsize = register_size (regno);
-
   if ((regno >> 12) != 0)
     *buf++ = tohex ((regno >> 12) & 0xf);
   if ((regno >> 8) != 0)
@@ -453,14 +537,39 @@ outreg (int regno, char *buf)
   *buf++ = tohex ((regno >> 4) & 0xf);
   *buf++ = tohex (regno & 0xf);
   *buf++ = ':';
-  convert_int_to_ascii (register_data (regno), buf, regsize);
-  buf += 2 * regsize;
+  collect_register_as_string (regno, buf);
+  buf += 2 * register_size (regno);
   *buf++ = ';';
 
   return buf;
 }
 
 void
+new_thread_notify (int id)
+{
+  char own_buf[256];
+
+  if (server_waiting == 0)
+    return;
+
+  sprintf (own_buf, "n%x", id);
+  disable_async_io ();
+  putpkt (own_buf);
+  enable_async_io ();
+}
+
+void
+dead_thread_notify (int id)
+{
+  char own_buf[256];
+
+  sprintf (own_buf, "x%x", id);
+  disable_async_io ();
+  putpkt (own_buf);
+  enable_async_io ();
+}
+
+void
 prepare_resume_reply (char *buf, char status, unsigned char signo)
 {
   int nib, sig;
@@ -483,12 +592,23 @@ prepare_resume_reply (char *buf, char st
 	  regp ++;
 	}
 
-      /* 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)
+      /* Formerly, if the debugger had not used any thread features we would not
+        burden it with a thread status response.  This was for the benefit of
+        GDB 4.13 and older.  However, in recent GDB versions the check
+        (``if (cont_thread != 0)'') does not have the desired effect because of
+        sillyness in the way that the remote protocol handles specifying a thread.
+        Since thread support relies on qSymbol support anyway, assume GDB can handle
+        threads.  */
+
+      if (using_threads)
 	{
+         /* FIXME right place to set this? */
+         thread_from_wait = ((struct inferior_list_entry *)current_inferior)->id;
+         if (debug_threads)
+           fprintf (stderr, "Writing resume reply for %d\n\n", thread_from_wait);
 	  if (old_thread_from_wait != thread_from_wait)
 	    {
+              general_thread = thread_from_wait;
 	      sprintf (buf, "thread:%x;", thread_from_wait);
 	      buf += strlen (buf);
 	      old_thread_from_wait = thread_from_wait;
@@ -543,3 +663,46 @@ decode_M_packet (char *from, CORE_ADDR *
 
   convert_ascii_to_int (&from[i++], to, *len_ptr);
 }
+
+int
+look_up_one_symbol (const char *name, CORE_ADDR *addrp)
+{
+  char own_buf[266], *p, *q;
+  int len;
+
+  /* Send the request.  */
+  strcpy (own_buf, "qSymbol:");
+  hexify (own_buf + strlen ("qSymbol:"), name, strlen (name));
+  if (putpkt (own_buf) < 0)
+    return -1;
+
+  /* FIXME:  Eventually add buffer overflow checking (to getpkt?)  */
+  len = getpkt (own_buf);
+  if (len < 0)
+    return -1;
+
+  if (strncmp (own_buf, "qSymbol:", strlen ("qSymbol:")) != 0)
+    {
+      /* Malformed response.  */
+      if (remote_debug)
+       {
+         fprintf (stderr, "Malformed response to qSymbol, ignoring.\n");
+         fflush (stderr);
+       }
+
+      return -1;
+    }
+
+  p = own_buf + strlen ("qSymbol:");
+  q = p;
+  while (*q && *q != ':')
+    q++;
+
+  /* Make sure we found a value for the symbol.  */
+  if (p == q || *q == '\0')
+    return 0;
+
+  decode_address (addrp, p, q - p);
+  return 1;
+}
+
diff -purN gdb-5.2.1-orig/gdb/gdbserver/server.c gdb-5.2.1/gdb/gdbserver/server.c
--- gdb-5.2.1-orig/gdb/gdbserver/server.c	Fri Mar 29 20:03:34 2002
+++ gdb-5.2.1/gdb/gdbserver/server.c	Tue Sep  2 14:04:41 2003
@@ -23,20 +23,27 @@
 
 int cont_thread;
 int general_thread;
+int step_thread;
 int thread_from_wait;
 int old_thread_from_wait;
 int extended_protocol;
+int server_waiting;
+
+static int active = 0;
 jmp_buf toplevel;
-int inferior_pid;
 
 static unsigned char
 start_inferior (char *argv[], char *statusptr)
 {
-  inferior_pid = create_inferior (argv[0], argv);
-  fprintf (stderr, "Process %s created; pid = %d\n", argv[0], inferior_pid);
+  /* FIXME Check error? Or turn to void.  */
+  create_inferior (argv[0], argv);
+
+  fprintf (stderr, "Process %s created; pid = %d\n", argv[0],
+          all_threads.head->id);
 
+  active = 1;
   /* Wait till we are at 1st instruction in program, return signal number.  */
-  return mywait (statusptr);
+  return mywait (statusptr, 0);
 }
 
 static int
@@ -47,26 +54,105 @@ attach_inferior (int pid, char *statuspt
   if (myattach (pid) != 0)
     return -1;
 
-  inferior_pid = pid;
-
-  *sigptr = mywait (statusptr);
-
+  *sigptr = mywait (statusptr, 0);
+#ifdef HAVE_TARGET_ATTACH
+  active = 1;
+#endif
   return 0;
 }
 
+#ifdef HAVE_TARGET_ATTACH
+static int
+detach_inferior (void)
+{
+  mydetach (1);
+  active = 0;
+  return 0;
+}
+#endif
 extern int remote_debug;
 
+/* Handle all of the extended 'q' packets.  */
+void
+handle_query (char *own_buf)
+{
+  static struct inferior_list_entry *thread_ptr;
+
+  if (strcmp ("qSymbol::", own_buf) == 0)
+    {
+      if (the_target->look_up_symbols != NULL)
+	(*the_target->look_up_symbols) ();
+
+      strcpy (own_buf, "OK");
+      return;
+    }
+
+  if (strcmp ("qfThreadInfo", own_buf) == 0)
+    {
+      thread_ptr = all_threads.head;
+      sprintf (own_buf, "m%x", thread_ptr->id);
+      thread_ptr = thread_ptr->next;
+      return;
+    }
+
+  if (strcmp ("qsThreadInfo", own_buf) == 0)
+    {
+      if (thread_ptr != NULL)
+       {
+         sprintf (own_buf, "m%x", thread_ptr->id);
+         thread_ptr = thread_ptr->next;
+         return;
+       }
+      else
+       {
+         sprintf (own_buf, "l");
+         return;
+       }
+    }
+
+  /* Otherwise we didn't know what packet it was.  Say we didn't
+     understand it.  */
+  own_buf[0] = 0;
+}
+
+static int attached;
+
+#ifdef HAVE_TARGET_ATTACH
+static void
+gdbserver_usage (void)
+{
+  error ("Usage:\tgdbserver [-d] COMM PROG [ARGS ...]\n"
+	 "\tgdbserver [-d] COMM --attach PID\n"
+	 "\tgdbserver [-d] COMM\n"
+	 "\n"
+	 "COMM may either be a tty device (for serial debugging), or \n"
+	 "HOST:PORT to listen for a TCP connection.\n");
+}
+#else
+static void
+gdbserver_usage (void)
+{
+  error ("Usage:\tgdbserver COMM PROG [ARGS ...]\n"
+	 "\tgdbserver COMM --attach PID\n"
+	 "\n"
+	 "COMM may either be a tty device (for serial debugging), or \n"
+	 "HOST:PORT to listen for a TCP connection.\n");
+}
+#endif
+
 int
 main (int argc, char *argv[])
 {
   char ch, status, *own_buf, mem_buf[2000];
   int i = 0;
+#ifdef HAVE_TARGET_ATTACH
+  int argmax = 3;
+#endif
   unsigned char signal;
   unsigned int len;
   CORE_ADDR mem_addr;
-  int bad_attach = 0;
-  int pid = 0;
-  int attached = 0;
+  int bad_attach;
+  int pid;
   char *arg_end;
 
   if (setjmp (toplevel))
@@ -75,10 +161,71 @@ main (int argc, char *argv[])
       exit (1);
     }
 
+  bad_attach = 0;
+  pid = 0;
+  attached = 0;
+#ifdef HAVE_TARGET_ATTACH
+  if (argc >= 2) {
+	  if (*argv[1] == '-') {
+		  if (argc == 2)
+			  gdbserver_usage();
+		  if (strcmp (argv[1], "-d") == 0) {
+			  remote_debug = 1;
+			  argmax++;
+		  } else
+              gdbserver_usage();
+	  }
+  } else
+	  gdbserver_usage();
+
+  if (argc >= argmax && strcmp (argv[argmax-1], "--attach") == 0)
+    {
+		if (argc == (argmax+1)
+ 	  && argv[argmax] != '\0'
+	  && (pid = strtoul (argv[argmax], &arg_end, 10)) != 0
+	  && *arg_end == '\0')
+	{
+	  ;
+	}
+      else
+		  gdbserver_usage();
+    }
+
+  initialize_low ();
+  own_buf = malloc (PBUFSIZ);
+
+  if (argc < argmax) {
+      status = 'I';	/* idle */
+      signal = 0;
+      fprintf (stderr, "Ready to attach to a process\n");
+	  goto loop;
+  }
+
+  if (pid == 0)
+    {
+      /* Wait till we are at first instruction in program.  */
+		if (argc >= argmax && argv[argmax-1] != '\0')
+      signal = start_inferior (&argv[argmax-1], &status);
+      /* We are now stopped at the first instruction of the target process */
+    }
+  else
+    {
+      switch (attach_inferior (pid, &status, &signal))
+	{
+	case -1:
+	  error ("Attaching not supported on this target");
+	  break;
+	default:
+	  attached = 1;
+	  break;
+	}
+    }
+ loop:
+#else
   if (argc >= 3 && strcmp (argv[2], "--attach") == 0)
     {
       if (argc == 4
-	  && argv[3] != '\0'
+ 	  && argv[3] != '\0'
 	  && (pid = strtoul (argv[3], &arg_end, 10)) != 0
 	  && *arg_end == '\0')
 	{
@@ -89,8 +236,7 @@ main (int argc, char *argv[])
     }
 
   if (argc < 3 || bad_attach)
-    error ("Usage:\tgdbserver tty prog [args ...]\n"
-		 "\tgdbserver tty --attach pid");
+    gdbserver_usage();
 
   initialize_low ();
 
@@ -115,10 +261,15 @@ main (int argc, char *argv[])
 	  break;
 	}
     }
+#endif
 
   while (1)
     {
+#ifdef HAVE_TARGET_ATTACH
+      remote_open (argv[argmax-2]);
+#else
       remote_open (argv[1]);
+#endif
 
     restart:
       setjmp (toplevel);
@@ -129,6 +280,9 @@ main (int argc, char *argv[])
 	  ch = own_buf[i++];
 	  switch (ch)
 	    {
+	    case 'q':
+	      handle_query (own_buf);
+	      break;
 	    case 'd':
 	      remote_debug = !remote_debug;
 	      break;
@@ -147,20 +301,33 @@ main (int argc, char *argv[])
 		}
 	      break;
 	    case '?':
+#ifdef HAVE_TARGET_ATTACH
+		if (!active) signal = 0;
+#endif
 	      prepare_resume_reply (own_buf, status, signal);
 	      break;
 	    case 'H':
 	      switch (own_buf[1])
 		{
 		case 'g':
+#ifdef HAVE_TARGET_ATTACH
+		 if (!active) {
+		     write_enn (own_buf);	      
+		     break;
+		 }
+#endif
 		  general_thread = strtol (&own_buf[2], NULL, 16);
 		  write_ok (own_buf);
-		  fetch_inferior_registers (0);
+		  set_desired_inferior (1);
 		  break;
 		case 'c':
 		  cont_thread = strtol (&own_buf[2], NULL, 16);
 		  write_ok (own_buf);
 		  break;
+               case 's':
+                 step_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.  */
@@ -169,19 +336,32 @@ main (int argc, char *argv[])
 		}
 	      break;
 	    case 'g':
+#ifdef HAVE_TARGET_ATTACH
+	      if (!active) goto silent;	/* no registers yet */
+#endif
+	      set_desired_inferior (1);
 	      registers_to_string (own_buf);
 	      break;
 	    case 'G':
+#ifdef HAVE_TARGET_ATTACH
+	      if (!active) goto silent;	/* no registers yet */
+#endif
+	      set_desired_inferior (1);
 	      registers_from_string (&own_buf[1]);
-	      store_inferior_registers (-1);
 	      write_ok (own_buf);
 	      break;
 	    case 'm':
+#ifdef HAVE_TARGET_ATTACH
+	      if (!active) goto silent;	/* no registers yet */
+#endif
 	      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':
+#ifdef HAVE_TARGET_ATTACH
+	      if (!active) goto silent;	/* no registers yet */
+#endif
 	      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);
@@ -189,33 +369,49 @@ main (int argc, char *argv[])
 		write_enn (own_buf);
 	      break;
 	    case 'C':
+#ifdef HAVE_TARGET_ATTACH
+	      if (!active) goto silent;	/* no registers yet */
+#endif
 	      convert_ascii_to_int (own_buf + 1, &sig, 1);
 	      if (target_signal_to_host_p (sig))
 		signal = target_signal_to_host (sig);
 	      else
 		signal = 0;
+	      set_desired_inferior (0);
 	      myresume (0, signal);
-	      signal = mywait (&status);
+	      signal = mywait (&status, 1);
 	      prepare_resume_reply (own_buf, status, signal);
 	      break;
 	    case 'S':
+#ifdef HAVE_TARGET_ATTACH
+	      if (!active) goto silent;	/* no registers yet */
+#endif
 	      convert_ascii_to_int (own_buf + 1, &sig, 1);
 	      if (target_signal_to_host_p (sig))
 		signal = target_signal_to_host (sig);
 	      else
 		signal = 0;
+	      set_desired_inferior (0);
 	      myresume (1, signal);
-	      signal = mywait (&status);
+	      signal = mywait (&status, 1);
 	      prepare_resume_reply (own_buf, status, signal);
 	      break;
 	    case 'c':
+#ifdef HAVE_TARGET_ATTACH
+	      if (!active) goto silent;	/* no registers yet */
+#endif
+	      set_desired_inferior (0);
 	      myresume (0, 0);
-	      signal = mywait (&status);
+	      signal = mywait (&status, 1);
 	      prepare_resume_reply (own_buf, status, signal);
 	      break;
 	    case 's':
+#ifdef HAVE_TARGET_ATTACH
+	      if (!active) goto silent;	/* no registers yet */
+#endif
+	      set_desired_inferior (0);
 	      myresume (1, 0);
-	      signal = mywait (&status);
+	      signal = mywait (&status, 1);
 	      prepare_resume_reply (own_buf, status, signal);
 	      break;
 	    case 'k':
@@ -230,7 +426,11 @@ main (int argc, char *argv[])
 		  fprintf (stderr, "GDBserver restarting\n");
 
 		  /* Wait till we are at 1st instruction in prog.  */
+#ifdef HAVE_TARGET_ATTACH
+		  signal = start_inferior (&argv[argmax-1], &status);
+#else
 		  signal = start_inferior (&argv[2], &status);
+#endif
 		  goto restart;
 		  break;
 		}
@@ -255,7 +455,11 @@ main (int argc, char *argv[])
 		  fprintf (stderr, "GDBserver restarting\n");
 
 		  /* Wait till we are at 1st instruction in prog.  */
+#ifdef HAVE_TARGET_ATTACH
+		  signal = start_inferior (&argv[argmax-1], &status);
+#else
 		  signal = start_inferior (&argv[2], &status);
+#endif
 		  goto restart;
 		  break;
 		}
@@ -267,10 +471,51 @@ main (int argc, char *argv[])
 		  own_buf[0] = '\0';
 		  break;
 		}
+#ifdef HAVE_TARGET_ATTACH
+	    case 'U': /* attach a process */
+	      if (sscanf(&own_buf[i], "%x", &pid) == 1 &&
+		  (attach_inferior(pid, &status, &signal) == 0)) {
+		  attached = 1;
+		  set_desired_inferior (0);
+		  prepare_resume_reply (own_buf, status, signal);
+	      }
+	      else
+		write_enn (own_buf);
+	      break;
+
+	   case 'Z': 	      /* Z-packet support  - No*/
+	      own_buf[0]=0;
+	      break;
+
+	   case 'X':		/* binary download support */
+   	      own_buf[0]=0;
+	      break;
+
+	   case 'D':		/* detach a process */
+		   if (detach_inferior() == -1) 
+			   write_enn (own_buf);
+		   else {
+			   status = 'I';
+			   write_ok (own_buf);
+		   }
+		   break;
+
+	    case 'K':		/* close communication */
+            goto comm_closed;
+	      
+#endif
+#ifdef HAVE_TARGET_SHELL
+	    case 'E':	/* exec remote command */
+	      exec_shellcmd(&own_buf[1]);
+	      continue;	/* No replying packet */
+#endif
 	    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.  */
+#ifdef HAVE_TARGET_ATTACH
+	    silent:
+#endif
 	      own_buf[0] = '\0';
 	      break;
 	    }
@@ -292,11 +537,18 @@ main (int argc, char *argv[])
 		  fprintf (stderr, "GDBserver restarting\n");
 
 		  /* Wait till we are at 1st instruction in prog.  */
+#ifdef HAVE_TARGET_ATTACH		  
+		  signal = start_inferior (&argv[argmax-1], &status);
+#else
 		  signal = start_inferior (&argv[2], &status);
+#endif
 		  goto restart;
 		  break;
 		}
 	      else
+#ifdef HAVE_TARGET_ATTACH
+		  if (!attached)
+#endif
 		{
 		  fprintf (stderr, "GDBserver exiting\n");
 		  exit (0);
@@ -311,6 +563,9 @@ main (int argc, char *argv[])
 
          For the traditional remote protocol close the connection,
          and re-open it at the top of the loop.  */
+#ifdef HAVE_TARGET_ATTACH
+comm_closed:    
+#endif        
       if (extended_protocol)
 	{
 	  remote_close ();
@@ -321,6 +576,9 @@ main (int argc, char *argv[])
 	  fprintf (stderr, "Remote side has terminated connection.  "
 			   "GDBserver will reopen the connection.\n");
 	  remote_close ();
+#ifdef HAVE_TARGET_ATTACH
+	  status = 'I';
+#endif
 	}
     }
 }
diff -purN gdb-5.2.1-orig/gdb/gdbserver/server.h gdb-5.2.1/gdb/gdbserver/server.h
--- gdb-5.2.1-orig/gdb/gdbserver/server.h	Fri Mar 29 20:03:34 2002
+++ gdb-5.2.1/gdb/gdbserver/server.h	Tue Sep  2 14:04:41 2003
@@ -23,48 +23,101 @@
 #define SERVER_H
 
 #include "config.h"
+
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <setjmp.h>
+#include <ctype.h> /* For isspace */
 
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifndef ATTR_NORETURN
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
+#define ATTR_NORETURN __attribute__ ((noreturn))
+#else
+#define ATTR_NORETURN           /* nothing */
+#endif
+#endif
+
+#ifndef ATTR_FORMAT
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 4))
+#define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y)))
+#else
+#define ATTR_FORMAT(type, x, y) /* nothing */
+#endif
+#endif
 
-/* FIXME:  Both of these should be autoconf'd for.  */
-#define NORETURN
+/* FIXME: This should probably be autoconf'd for.  It's an integer type at
+   least the size of a (void *).  */
 typedef long long CORE_ADDR;
 
+/* Generic information for tracking a list of ``inferiors'' - threads,
+   processes, etc.  */
+struct inferior_list
+{
+  struct inferior_list_entry *head;
+  struct inferior_list_entry *tail;
+};
+struct inferior_list_entry
+{
+  int id;
+  struct inferior_list_entry *next;
+};
+
+/* Opaque type for user-visible threads.  */
+struct thread_info;
+
 #include "regcache.h"
-#include "gdb/signals.h"
+#include "signals.h"
 
-#include <setjmp.h>
+#include "target.h"
+#include "mem-break.h"
 
 /* Target-specific functions */
 
-int create_inferior (char *program, char **allargs);
-void kill_inferior (void);
-void fetch_inferior_registers (int regno);
-void store_inferior_registers (int regno);
-int mythread_alive (int pid);
-void myresume (int step, int signo);
-unsigned char mywait (char *status);
-void read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
-int write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
-int create_inferior ();
 void initialize_low ();
 
-/* Target-specific variables */
+/* From inferiors.c.  */
 
-extern char *registers;
+extern struct inferior_list all_threads;
+void add_inferior_to_list (struct inferior_list *list,
+                          struct inferior_list_entry *new_inferior);
+void for_each_inferior (struct inferior_list *list,
+                       void (*action) (struct inferior_list_entry *));
+extern struct thread_info *current_inferior;
+void remove_inferior (struct inferior_list *list,
+                     struct inferior_list_entry *entry);
+void remove_thread (struct thread_info *thread);
+void add_thread (int thread_id, void *target_data);
+void clear_inferiors (void);
+struct inferior_list_entry *find_inferior
+     (struct inferior_list *,
+      int (*func) (struct inferior_list_entry *,
+                  void *),
+      void *arg);
+struct inferior_list_entry *find_inferior_id (struct inferior_list *list,
+                                             int id);
+void *inferior_target_data (struct thread_info *);
+void set_inferior_target_data (struct thread_info *, void *);
+void *inferior_regcache_data (struct thread_info *);
+void set_inferior_regcache_data (struct thread_info *, void *);
+void change_inferior_id (struct inferior_list *list,
+                        int new_id);
 
 /* Public variables in server.c */
 
 extern int cont_thread;
 extern int general_thread;
+extern int step_thread;
 extern int thread_from_wait;
 extern int old_thread_from_wait;
+extern int server_waiting;
 
 extern jmp_buf toplevel;
-extern int inferior_pid;
 
 /* Functions from remote-utils.c */
 
@@ -78,6 +131,8 @@ void enable_async_io (void);
 void disable_async_io (void);
 void convert_ascii_to_int (char *from, char *to, int n);
 void convert_int_to_ascii (char *from, char *to, int n);
+void new_thread_notify (int id);
+void dead_thread_notify (int id);
 void prepare_resume_reply (char *buf, char status, unsigned char sig);
 
 void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr,
@@ -85,6 +140,11 @@ void decode_m_packet (char *from, CORE_A
 void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr,
 		      unsigned int *len_ptr, char *to);
 
+int unhexify (char *bin, const char *hex, int count);
+int hexify (char *hex, const char *bin, int count);
+
+int look_up_one_symbol (const char *name, CORE_ADDR *addrp);
+
 /* Functions from ``signals.c''.  */
 enum target_signal target_signal_from_host (int hostsig);
 int target_signal_to_host_p (enum target_signal oursig);
@@ -93,11 +153,18 @@ int target_signal_to_host (enum target_s
 /* Functions from utils.c */
 
 void perror_with_name (char *string);
-void error (const char *string,...);
-void fatal (const char *string,...);
+void error (const char *string,...) ATTR_NORETURN;
+void fatal (const char *string,...) ATTR_NORETURN;
 void warning (const char *string,...);
 
+/* Functions from the register cache definition.  */
+
+void init_registers (void);
 
+#ifdef HAVE_TARGET_SHELL
+/* Function from linux-low.c */
+void exec_shellcmd(char *);
+#endif
 
 /* Maximum number of bytes to read/write at once.  The value here
    is chosen to fill up a packet (the headers account for the 32).  */
diff -purN gdb-5.2.1-orig/gdb/gdbserver/signals.h gdb-5.2.1/gdb/gdbserver/signals.h
--- gdb-5.2.1-orig/gdb/gdbserver/signals.h	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/signals.h	Tue Sep  2 14:04:41 2003
@@ -0,0 +1,237 @@
+/* Target signal numbers for GDB and the GDB remote protocol.
+   Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+   1997, 1998, 1999, 2000, 2001, 2002
+   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.  */
+
+#ifndef GDB_SIGNALS_H
+#define GDB_SIGNALS_H
+
+/* The numbering of these signals is chosen to match traditional unix
+   signals (insofar as various unices use the same numbers, anyway).
+   It is also the numbering of the GDB remote protocol.  Other remote
+   protocols, if they use a different numbering, should make sure to
+   translate appropriately.
+
+   Since these numbers have actually made it out into other software
+   (stubs, etc.), you mustn't disturb the assigned numbering.  If you
+   need to add new signals here, add them to the end of the explicitly
+   numbered signals, at the comment marker.  Add them unconditionally,
+   not within any #if or #ifdef.
+
+   This is based strongly on Unix/POSIX signals for several reasons:
+   (1) This set of signals represents a widely-accepted attempt to
+   represent events of this sort in a portable fashion, (2) we want a
+   signal to make it from wait to child_wait to the user intact, (3) many
+   remote protocols use a similar encoding.  However, it is
+   recognized that this set of signals has limitations (such as not
+   distinguishing between various kinds of SIGSEGV, or not
+   distinguishing hitting a breakpoint from finishing a single step).
+   So in the future we may get around this either by adding additional
+   signals for breakpoint, single-step, etc., or by adding signal
+   codes; the latter seems more in the spirit of what BSD, System V,
+   etc. are doing to address these issues.  */
+
+/* For an explanation of what each signal means, see
+   target_signal_to_string.  */
+
+enum target_signal
+  {
+    /* Used some places (e.g. stop_signal) to record the concept that
+       there is no signal.  */
+    TARGET_SIGNAL_0 = 0,
+    TARGET_SIGNAL_FIRST = 0,
+    TARGET_SIGNAL_HUP = 1,
+    TARGET_SIGNAL_INT = 2,
+    TARGET_SIGNAL_QUIT = 3,
+    TARGET_SIGNAL_ILL = 4,
+    TARGET_SIGNAL_TRAP = 5,
+    TARGET_SIGNAL_ABRT = 6,
+    TARGET_SIGNAL_EMT = 7,
+    TARGET_SIGNAL_FPE = 8,
+    TARGET_SIGNAL_KILL = 9,
+    TARGET_SIGNAL_BUS = 10,
+    TARGET_SIGNAL_SEGV = 11,
+    TARGET_SIGNAL_SYS = 12,
+    TARGET_SIGNAL_PIPE = 13,
+    TARGET_SIGNAL_ALRM = 14,
+    TARGET_SIGNAL_TERM = 15,
+    TARGET_SIGNAL_URG = 16,
+    TARGET_SIGNAL_STOP = 17,
+    TARGET_SIGNAL_TSTP = 18,
+    TARGET_SIGNAL_CONT = 19,
+    TARGET_SIGNAL_CHLD = 20,
+    TARGET_SIGNAL_TTIN = 21,
+    TARGET_SIGNAL_TTOU = 22,
+    TARGET_SIGNAL_IO = 23,
+    TARGET_SIGNAL_XCPU = 24,
+    TARGET_SIGNAL_XFSZ = 25,
+    TARGET_SIGNAL_VTALRM = 26,
+    TARGET_SIGNAL_PROF = 27,
+    TARGET_SIGNAL_WINCH = 28,
+    TARGET_SIGNAL_LOST = 29,
+    TARGET_SIGNAL_USR1 = 30,
+    TARGET_SIGNAL_USR2 = 31,
+    TARGET_SIGNAL_PWR = 32,
+    /* Similar to SIGIO.  Perhaps they should have the same number.  */
+    TARGET_SIGNAL_POLL = 33,
+    TARGET_SIGNAL_WIND = 34,
+    TARGET_SIGNAL_PHONE = 35,
+    TARGET_SIGNAL_WAITING = 36,
+    TARGET_SIGNAL_LWP = 37,
+    TARGET_SIGNAL_DANGER = 38,
+    TARGET_SIGNAL_GRANT = 39,
+    TARGET_SIGNAL_RETRACT = 40,
+    TARGET_SIGNAL_MSG = 41,
+    TARGET_SIGNAL_SOUND = 42,
+    TARGET_SIGNAL_SAK = 43,
+    TARGET_SIGNAL_PRIO = 44,
+    TARGET_SIGNAL_REALTIME_33 = 45,
+    TARGET_SIGNAL_REALTIME_34 = 46,
+    TARGET_SIGNAL_REALTIME_35 = 47,
+    TARGET_SIGNAL_REALTIME_36 = 48,
+    TARGET_SIGNAL_REALTIME_37 = 49,
+    TARGET_SIGNAL_REALTIME_38 = 50,
+    TARGET_SIGNAL_REALTIME_39 = 51,
+    TARGET_SIGNAL_REALTIME_40 = 52,
+    TARGET_SIGNAL_REALTIME_41 = 53,
+    TARGET_SIGNAL_REALTIME_42 = 54,
+    TARGET_SIGNAL_REALTIME_43 = 55,
+    TARGET_SIGNAL_REALTIME_44 = 56,
+    TARGET_SIGNAL_REALTIME_45 = 57,
+    TARGET_SIGNAL_REALTIME_46 = 58,
+    TARGET_SIGNAL_REALTIME_47 = 59,
+    TARGET_SIGNAL_REALTIME_48 = 60,
+    TARGET_SIGNAL_REALTIME_49 = 61,
+    TARGET_SIGNAL_REALTIME_50 = 62,
+    TARGET_SIGNAL_REALTIME_51 = 63,
+    TARGET_SIGNAL_REALTIME_52 = 64,
+    TARGET_SIGNAL_REALTIME_53 = 65,
+    TARGET_SIGNAL_REALTIME_54 = 66,
+    TARGET_SIGNAL_REALTIME_55 = 67,
+    TARGET_SIGNAL_REALTIME_56 = 68,
+    TARGET_SIGNAL_REALTIME_57 = 69,
+    TARGET_SIGNAL_REALTIME_58 = 70,
+    TARGET_SIGNAL_REALTIME_59 = 71,
+    TARGET_SIGNAL_REALTIME_60 = 72,
+    TARGET_SIGNAL_REALTIME_61 = 73,
+    TARGET_SIGNAL_REALTIME_62 = 74,
+    TARGET_SIGNAL_REALTIME_63 = 75,
+
+    /* Used internally by Solaris threads.  See signal(5) on Solaris.  */
+    TARGET_SIGNAL_CANCEL = 76,
+
+    /* Yes, this pains me, too.  But LynxOS didn't have SIG32, and now
+       GNU/Linux does, and we can't disturb the numbering, since it's
+       part of the remote protocol.  Note that in some GDB's
+       TARGET_SIGNAL_REALTIME_32 is number 76.  */
+    TARGET_SIGNAL_REALTIME_32,
+    /* Yet another pain, IRIX 6 has SIG64. */
+    TARGET_SIGNAL_REALTIME_64,
+    /* Yet another pain, GNU/Linux MIPS might go up to 128. */
+    TARGET_SIGNAL_REALTIME_65,
+    TARGET_SIGNAL_REALTIME_66,
+    TARGET_SIGNAL_REALTIME_67,
+    TARGET_SIGNAL_REALTIME_68,
+    TARGET_SIGNAL_REALTIME_69,
+    TARGET_SIGNAL_REALTIME_70,
+    TARGET_SIGNAL_REALTIME_71,
+    TARGET_SIGNAL_REALTIME_72,
+    TARGET_SIGNAL_REALTIME_73,
+    TARGET_SIGNAL_REALTIME_74,
+    TARGET_SIGNAL_REALTIME_75,
+    TARGET_SIGNAL_REALTIME_76,
+    TARGET_SIGNAL_REALTIME_77,
+    TARGET_SIGNAL_REALTIME_78,
+    TARGET_SIGNAL_REALTIME_79,
+    TARGET_SIGNAL_REALTIME_80,
+    TARGET_SIGNAL_REALTIME_81,
+    TARGET_SIGNAL_REALTIME_82,
+    TARGET_SIGNAL_REALTIME_83,
+    TARGET_SIGNAL_REALTIME_84,
+    TARGET_SIGNAL_REALTIME_85,
+    TARGET_SIGNAL_REALTIME_86,
+    TARGET_SIGNAL_REALTIME_87,
+    TARGET_SIGNAL_REALTIME_88,
+    TARGET_SIGNAL_REALTIME_89,
+    TARGET_SIGNAL_REALTIME_90,
+    TARGET_SIGNAL_REALTIME_91,
+    TARGET_SIGNAL_REALTIME_92,
+    TARGET_SIGNAL_REALTIME_93,
+    TARGET_SIGNAL_REALTIME_94,
+    TARGET_SIGNAL_REALTIME_95,
+    TARGET_SIGNAL_REALTIME_96,
+    TARGET_SIGNAL_REALTIME_97,
+    TARGET_SIGNAL_REALTIME_98,
+    TARGET_SIGNAL_REALTIME_99,
+    TARGET_SIGNAL_REALTIME_100,
+    TARGET_SIGNAL_REALTIME_101,
+    TARGET_SIGNAL_REALTIME_102,
+    TARGET_SIGNAL_REALTIME_103,
+    TARGET_SIGNAL_REALTIME_104,
+    TARGET_SIGNAL_REALTIME_105,
+    TARGET_SIGNAL_REALTIME_106,
+    TARGET_SIGNAL_REALTIME_107,
+    TARGET_SIGNAL_REALTIME_108,
+    TARGET_SIGNAL_REALTIME_109,
+    TARGET_SIGNAL_REALTIME_110,
+    TARGET_SIGNAL_REALTIME_111,
+    TARGET_SIGNAL_REALTIME_112,
+    TARGET_SIGNAL_REALTIME_113,
+    TARGET_SIGNAL_REALTIME_114,
+    TARGET_SIGNAL_REALTIME_115,
+    TARGET_SIGNAL_REALTIME_116,
+    TARGET_SIGNAL_REALTIME_117,
+    TARGET_SIGNAL_REALTIME_118,
+    TARGET_SIGNAL_REALTIME_119,
+    TARGET_SIGNAL_REALTIME_120,
+    TARGET_SIGNAL_REALTIME_121,
+    TARGET_SIGNAL_REALTIME_122,
+    TARGET_SIGNAL_REALTIME_123,
+    TARGET_SIGNAL_REALTIME_124,
+    TARGET_SIGNAL_REALTIME_125,
+    TARGET_SIGNAL_REALTIME_126,
+    TARGET_SIGNAL_REALTIME_127,
+
+    TARGET_SIGNAL_INFO,
+
+    /* Some signal we don't know about.  */
+    TARGET_SIGNAL_UNKNOWN,
+
+    /* Use whatever signal we use when one is not specifically specified
+       (for passing to proceed and so on).  */
+    TARGET_SIGNAL_DEFAULT,
+
+    /* Mach exceptions.  In versions of GDB before 5.2, these were just before
+       TARGET_SIGNAL_INFO if you were compiling on a Mach host (and missing
+       otherwise).  */
+    TARGET_EXC_BAD_ACCESS,
+    TARGET_EXC_BAD_INSTRUCTION,
+    TARGET_EXC_ARITHMETIC,
+    TARGET_EXC_EMULATION,
+    TARGET_EXC_SOFTWARE,
+    TARGET_EXC_BREAKPOINT,
+
+    /* If you are adding a new signal, add it just above this comment.  */
+
+    /* Last and unused enum value, for sizing arrays, etc.  */
+    TARGET_SIGNAL_LAST
+  };
+
+#endif /* #ifndef GDB_SIGNALS_H */
diff -purN gdb-5.2.1-orig/gdb/gdbserver/target.c gdb-5.2.1/gdb/gdbserver/target.c
--- gdb-5.2.1-orig/gdb/gdbserver/target.c	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/target.c	Tue Sep  2 14:04:41 2003
@@ -0,0 +1,113 @@
+/* Target operations for the remote server for GDB.
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   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 "linux-low.h"
+struct target_ops *the_target;
+
+void
+set_desired_inferior (int use_general)
+{
+  struct thread_info *found;
+
+  if (use_general == 1)
+    {
+      found = (struct thread_info *) find_inferior_id (&all_threads,
+                                                      general_thread);
+    }
+  else
+    {
+      found = NULL;
+
+      /* If we are continuing any (all) thread(s), use step_thread
+        to decide which thread to step and/or send the specified
+        signal to.  */
+      if (step_thread > 0 && (cont_thread == 0 || cont_thread == -1))
+       found = (struct thread_info *) find_inferior_id (&all_threads,
+                                                        step_thread);
+
+      if (found == NULL)
+       found = (struct thread_info *) find_inferior_id (&all_threads,
+                                                        cont_thread);
+    }
+
+  if (found == NULL) {
+	  /* Do not default it to initial thread, leave current. */
+    if (!current_inferior) current_inferior = 
+							  (struct thread_info *) all_threads.head;
+  }
+  else
+    current_inferior = found;
+}
+
+void
+read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
+{
+  (*the_target->read_memory) (memaddr, myaddr, len);
+  check_mem_read (memaddr, myaddr, len);
+}
+
+int
+write_inferior_memory (CORE_ADDR memaddr, const char *myaddr, int len)
+{
+  /* Lacking cleanups, there is some potential for a memory leak if the
+     write fails and we go through error().  Make sure that no more than
+     one buffer is ever pending by making BUFFER static.  */
+  static char *buffer = 0;
+  int res;
+
+  if (buffer != NULL)
+    free (buffer);
+
+  buffer = malloc (len);
+  memcpy (buffer, myaddr, len);
+  check_mem_write (memaddr, buffer, len);
+  res = (*the_target->write_memory) (memaddr, buffer, len);
+  free (buffer);
+  buffer = NULL;
+
+  return res;
+}
+
+unsigned char
+mywait (char *statusp, int connected_wait)
+{
+  unsigned char ret;
+
+  if (connected_wait)
+    server_waiting = 1;
+
+  ret = (*the_target->wait) (statusp);
+
+  if (connected_wait)
+    server_waiting = 0;
+
+  return ret;
+}
+
+void
+set_target_ops (struct target_ops *target)
+{
+  the_target = (struct target_ops *) malloc (sizeof (*the_target));
+  memcpy (the_target, target, sizeof (*the_target));
+}
diff -purN gdb-5.2.1-orig/gdb/gdbserver/target.h gdb-5.2.1/gdb/gdbserver/target.h
--- gdb-5.2.1-orig/gdb/gdbserver/target.h	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/target.h	Tue Sep  2 14:04:41 2003
@@ -0,0 +1,156 @@
+/* Target operations for the remote server for GDB.
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   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.  */
+
+#ifndef TARGET_H
+#define TARGET_H
+
+struct target_ops
+{
+  /* Start a new process.
+
+     PROGRAM is a path to the program to execute.
+     ARGS is a standard NULL-terminated array of arguments,
+     to be passed to the inferior as ``argv''.
+
+     Returns 0 on success, -1 on failure.  Registers the new
+     process with the process list.  */
+
+  int (*create_inferior) (char *program, char **args);
+
+  /* Attach to a running process.
+
+     PID is the process ID to attach to, specified by the user
+     or a higher layer.  */
+
+  int (*attach) (int pid);
+
+#ifdef HAVE_TARGET_ATTACH
+  int (*detach) (int pid);
+#endif
+
+  /* Kill all inferiors.  */
+
+  void (*kill) (void);
+
+  /* Return 1 iff the thread with process ID PID is alive.  */
+
+  int (*thread_alive) (int pid);
+
+  /* Resume the inferior process.
+
+     If STEP is non-zero, we want to single-step.
+
+     If SIGNAL is nonzero, send the process that signal as we resume it.
+   */
+
+  void (*resume) (int step, int signo);
+
+  /* Wait for the inferior process to change state.
+
+     STATUSP will be filled in with a response code to send to GDB.
+
+     Returns the signal which caused the process to stop.  */
+
+  unsigned char (*wait) (char *status);
+
+  /* Fetch registers from the inferior process.
+
+     If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO.  */
+
+  void (*fetch_registers) (int regno);
+  
+  /* Store registers to the inferior process.
+
+     If REGNO is -1, store all registers; otherwise, store at least REGNO.  */
+
+  void (*store_registers) (int regno);
+
+  /* Read memory from the inferior process.  This should generally be
+     called through read_inferior_memory, which handles breakpoint shadowing.
+
+     Read LEN bytes at MEMADDR into a buffer at MYADDR.  */
+
+  void (*read_memory) (CORE_ADDR memaddr, char *myaddr, int len);
+
+  /* Write memory to the inferior process.  This should generally be
+     called through write_inferior_memory, which handles breakpoint shadowing.
+
+     Write LEN bytes from the buffer at MYADDR to MEMADDR.
+
+     Returns 0 on success and errno on failure.  */
+
+  int (*write_memory) (CORE_ADDR memaddr, const char *myaddr, int len);
+
+  /* Query GDB for the values of any symbols we're interested in.
+     This function is called whenever we receive a "qSymbols::"
+     query, which corresponds to every time more symbols (might)
+     become available.  NULL if we aren't interested in any
+     symbols.  */
+
+  void (*look_up_symbols) (void);
+
+  /* Return the PID we should send a signal to.  Used for asynchronous
+     interrupts (user hitting Control-C).  */
+
+  int (*signal_pid) (void);
+};
+
+extern struct target_ops *the_target;
+
+void set_target_ops (struct target_ops *);
+
+#define create_inferior(program, args) \
+  (*the_target->create_inferior) (program, args)
+
+#define myattach(pid) \
+  (*the_target->attach) (pid)
+
+#ifdef HAVE_TARGET_ATTACH
+#define mydetach(pid) \
+  (*the_target->detach) (pid)
+#endif
+
+#define kill_inferior() \
+  (*the_target->kill) ()
+
+#define mythread_alive(pid) \
+  (*the_target->thread_alive) (pid)
+
+#define myresume(step,signo) \
+  (*the_target->resume) (step, signo)
+
+#define fetch_inferior_registers(regno) \
+  (*the_target->fetch_registers) (regno)
+
+#define store_inferior_registers(regno) \
+  (*the_target->store_registers) (regno)
+
+unsigned char mywait (char *statusp, int connected_wait);
+
+void read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
+
+int write_inferior_memory (CORE_ADDR memaddr, const char *myaddr, int len);
+
+void set_desired_inferior (int id);
+
+#endif /* TARGET_H */
diff -purN gdb-5.2.1-orig/gdb/gdbserver/thread-db.c gdb-5.2.1/gdb/gdbserver/thread-db.c
--- gdb-5.2.1-orig/gdb/gdbserver/thread-db.c	Thu Jan  1 01:00:00 1970
+++ gdb-5.2.1/gdb/gdbserver/thread-db.c	Tue Sep  2 14:04:41 2003
@@ -0,0 +1,369 @@
+/* Thread management interface, for the remote server for GDB.
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   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 "linux-low.h"
+
+extern int debug_threads;
+#ifdef HAVE_TARGET_ATTACH
+static CORE_ADDR td_create_bp_addr;
+#endif
+
+#ifdef HAVE_THREAD_DB_H
+#include <thread_db.h>
+#endif
+
+/* Correct for all GNU/Linux targets (for quite some time).  */
+#define GDB_GREGSET_T elf_gregset_t
+#define GDB_FPREGSET_T elf_fpregset_t
+
+#ifndef HAVE_ELF_FPREGSET_T
+/* Make sure we have said types.  Not all platforms bring in <linux/elf.h>
+   via <sys/procfs.h>.  */
+#ifdef HAVE_LINUX_ELF_H
+#include <linux/elf.h>
+#endif
+#endif
+
+#include "../gdb_proc_service.h"
+
+/* Structure that identifies the child process for the
+   <proc_service.h> interface.  */
+static struct ps_prochandle proc_handle;
+
+/* Connection to the libthread_db library.  */
+static td_thragent_t *thread_agent;
+
+static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
+
+static char *
+thread_db_err_str (td_err_e err)
+{
+  static char buf[64];
+
+  switch (err)
+    {
+    case TD_OK:
+      return "generic 'call succeeded'";
+    case TD_ERR:
+      return "generic error";
+    case TD_NOTHR:
+      return "no thread to satisfy query";
+    case TD_NOSV:
+      return "no sync handle to satisfy query";
+    case TD_NOLWP:
+      return "no LWP to satisfy query";
+    case TD_BADPH:
+      return "invalid process handle";
+    case TD_BADTH:
+      return "invalid thread handle";
+    case TD_BADSH:
+      return "invalid synchronization handle";
+    case TD_BADTA:
+      return "invalid thread agent";
+    case TD_BADKEY:
+      return "invalid key";
+    case TD_NOMSG:
+      return "no event message for getmsg";
+    case TD_NOFPREGS:
+      return "FPU register set not available";
+    case TD_NOLIBTHREAD:
+      return "application not linked with libthread";
+    case TD_NOEVENT:
+      return "requested event is not supported";
+    case TD_NOCAPAB:
+      return "capability not available";
+    case TD_DBERR:
+      return "debugger service failed";
+    case TD_NOAPLIC:
+      return "operation not applicable to";
+    case TD_NOTSD:
+      return "no thread-specific data for this thread";
+    case TD_MALLOC:
+      return "malloc failed";
+    case TD_PARTIALREG:
+      return "only part of register set was written/read";
+    case TD_NOXREGS:
+      return "X register set not available for this thread";
+    default:
+      snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
+      return buf;
+    }
+}
+
+#if 0
+static char *
+thread_db_state_str (td_thr_state_e state)
+{
+  static char buf[64];
+
+  switch (state)
+    {
+    case TD_THR_STOPPED:
+      return "stopped by debugger";
+    case TD_THR_RUN:
+      return "runnable";
+    case TD_THR_ACTIVE:
+      return "active";
+    case TD_THR_ZOMBIE:
+      return "zombie";
+    case TD_THR_SLEEP:
+      return "sleeping";
+    case TD_THR_STOPPED_ASLEEP:
+      return "stopped by debugger AND blocked";
+    default:
+      snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
+      return buf;
+    }
+}
+#endif
+
+static void
+thread_db_create_event (CORE_ADDR where)
+{
+  td_event_msg_t msg;
+  td_err_e err;
+  struct inferior_linux_data *tdata;
+
+  if (debug_threads)
+    fprintf (stderr, "Thread creation event.\n");
+
+  tdata = inferior_target_data (current_inferior);
+
+  /* FIXME: This assumes we don't get another event.
+     In the LinuxThreads implementation, this is safe,
+     because all events come from the manager thread
+     (except for its own creation, of course).  */
+  err = td_ta_event_getmsg (thread_agent, &msg);
+  if (err != TD_OK)
+    fprintf (stderr, "thread getmsg err: %s\n",
+            thread_db_err_str (err));
+
+  /* msg.event == TD_EVENT_CREATE */
+
+  find_new_threads_callback (msg.th_p, NULL);
+}
+
+#if 0
+static void
+thread_db_death_event (CORE_ADDR where)
+{
+  if (debug_threads)
+    fprintf (stderr, "Thread death event.\n");
+}
+#endif
+
+static int
+thread_db_enable_reporting ()
+{
+  td_thr_events_t events;
+  td_notify_t notify;
+  td_err_e err;
+
+  /* Set the process wide mask saying which events we're interested in.  */
+  td_event_emptyset (&events);
+  td_event_addset (&events, TD_CREATE);
+
+#if 0
+  /* This is reported to be broken in glibc 2.1.3.  A different approach
+     will be necessary to support that.  */
+  td_event_addset (&events, TD_DEATH);
+#endif
+
+  err = td_ta_set_event (thread_agent, &events);
+  if (err != TD_OK)
+    {
+      warning ("Unable to set global thread event mask: %s",
+               thread_db_err_str (err));
+      return 0;
+    }
+
+  /* Get address for thread creation breakpoint.  */
+  err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
+  if (err != TD_OK)
+    {
+      warning ("Unable to get location for thread creation breakpoint: %s",
+              thread_db_err_str (err));
+      return 0;
+    }
+  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
+                    thread_db_create_event);
+
+#ifdef HAVE_TARGET_ATTACH
+  td_create_bp_addr = (CORE_ADDR) (unsigned long) notify.u.bptaddr;
+#endif
+#if 0
+  /* Don't concern ourselves with reported thread deaths, only
+     with actual thread deaths (via wait).  */
+
+  /* Get address for thread death breakpoint.  */
+  err = td_ta_event_addr (thread_agent, TD_DEATH, &notify);
+  if (err != TD_OK)
+    {
+      warning ("Unable to get location for thread death breakpoint: %s",
+              thread_db_err_str (err));
+      return;
+    }
+  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
+                    thread_db_death_event);
+#endif
+
+  return 1;
+}
+
+static void
+maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
+{
+  td_err_e err;
+  struct thread_info *inferior;
+  struct process_info *process;
+
+  /* If we are attaching to our first thread, things are a little
+     different.  */
+  if (all_threads.head == all_threads.tail)
+    {
+      inferior = (struct thread_info *) all_threads.head;
+      process = get_thread_process (inferior);
+      if (process->thread_known == 0)
+       {
+         /* Switch to indexing the threads list by TID.  */
+         change_inferior_id (&all_threads, ti_p->ti_tid);
+         goto found;
+       }
+    }
+
+  inferior = (struct thread_info *) find_inferior_id (&all_threads,
+                                                     ti_p->ti_tid);
+  if (inferior != NULL)
+    return;
+
+  if (debug_threads)
+    fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
+            ti_p->ti_tid, ti_p->ti_lid);
+  linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid);
+  inferior = (struct thread_info *) find_inferior_id (&all_threads,
+                                                     ti_p->ti_tid);
+  if (inferior == NULL)
+    {
+      warning ("Could not attach to thread %ld (LWP %d)\n",
+              ti_p->ti_tid, ti_p->ti_lid);
+      return;
+    }
+
+  process = inferior_target_data (inferior);
+
+found:
+  new_thread_notify (ti_p->ti_tid);
+
+  process->tid = ti_p->ti_tid;
+  process->lwpid = ti_p->ti_lid;
+
+  process->thread_known = 1;
+  err = td_thr_event_enable (th_p, 1);
+  if (err != TD_OK)
+    error ("Cannot enable thread event reporting for %d: %s",
+           ti_p->ti_lid, thread_db_err_str (err));
+}
+
+static int
+find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
+{
+  td_thrinfo_t ti;
+  td_err_e err;
+
+  err = td_thr_get_info (th_p, &ti);
+  if (err != TD_OK)
+    error ("Cannot get thread info: %s", thread_db_err_str (err));
+
+  /* Check for zombies.  */
+  if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
+    return 0;
+
+  maybe_attach_thread (th_p, &ti);
+
+  return 0;
+}
+
+static void
+thread_db_find_new_threads (void)
+{
+  td_err_e err;
+
+  /* Iterate over all user-space threads to discover new threads.  */
+  err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
+                       TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+                       TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+  if (err != TD_OK)
+    error ("Cannot find new threads: %s", thread_db_err_str (err));
+}
+
+int
+thread_db_init ()
+{
+  int err;
+
+  proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
+
+  err = td_ta_new (&proc_handle, &thread_agent);
+  switch (err)
+    {
+    case TD_NOLIBTHREAD:
+      /* No thread library was detected.  */
+      return 0;
+
+    case TD_OK:
+      /* The thread library was detected.  */
+
+      if (thread_db_enable_reporting () == 0)
+       return 0;
+      thread_db_find_new_threads ();
+      return 1;
+
+    default:
+      warning ("error initializing thread_db library.");
+    }
+
+  return 0;
+}
+
+#ifdef HAVE_TARGET_ATTACH
+static int
+thread_db_disable_reporting ()
+{
+  td_thr_events_t events;
+  struct breakpoint *thr_bp;
+
+  td_event_emptyset (&events);
+  td_ta_set_event (thread_agent, &events);
+  /* delete thread event breakpoints */
+  thr_bp = find_breakpoint_at (td_create_bp_addr);
+  delete_breakpoint (thr_bp);
+  return 0;
+}
+
+int thread_db_deinit(void)
+{
+  return thread_db_disable_reporting();
+}
+#endif
diff -purN gdb-5.2.1-orig/gdb/gdbserver/utils.c gdb-5.2.1/gdb/gdbserver/utils.c
--- gdb-5.2.1-orig/gdb/gdbserver/utils.c	Thu Feb 14 07:21:22 2002
+++ gdb-5.2.1/gdb/gdbserver/utils.c	Tue Sep  2 14:04:41 2003
@@ -57,7 +57,7 @@ perror_with_name (char *string)
    STRING is the error message, used as a fprintf string,
    and ARG is passed as an argument to it.  */
 
-NORETURN void
+void
 error (const char *string,...)
 {
   extern jmp_buf toplevel;
@@ -74,7 +74,7 @@ error (const char *string,...)
    STRING and ARG are passed to fprintf.  */
 
 /* VARARGS */
-NORETURN void
+void
 fatal (const char *string,...)
 {
   va_list args;
diff -pu gdb-5.2.1-orig/gdb/regformats/reg-ppc.dat gdb-5.2.1/gdb/regformats/reg-ppc.dat
--- gdb-5.2.1-orig/gdb/regformats/reg-ppc.dat	Fri Feb  1 23:05:28 2002
+++ gdb-5.2.1/gdb/regformats/reg-ppc.dat	Thu Sep 11 18:43:39 2003
@@ -73,4 +73,4 @@ expedite:r1,pc
 32:lr
 32:ctr
 32:xer
-0:
+32:fpscr
