Subject: toolchain/21710: Add support for remote debugging of PowerPC targets
To: None <gnats-bugs@gnats.netbsd.org>
From: None <john_94501@yahoo.com>
List: netbsd-bugs
Date: 05/29/2003 08:45:45
>Number:         21710
>Category:       toolchain
>Synopsis:       Add support  for remote debugging of PowerPC targets
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    toolchain-manager
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Thu May 29 08:46:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator:     John Gordon
>Release:        -current (5/27/2003)
>Organization:
blueDonkey.org
>Environment:
N/A
>Description:
The current version of gdbserver does not have support for PowerPC, nor does it have support for threads.
>How-To-Repeat:
N/A
>Fix:
The patch below adds support for PowerPC to gdbserver, and also adds supports for pthreads using the pthread_dbg library (this was based on the code in gdb itself for native debugging of threaded applications).

More information about this can be found at: http://www.bluedonkey.org/cgi-bin/twiki/bin/view/Netbsd/RemoteDebugging

One additional file is needed in the tree, src/gnu/usr.bin/gdb/arch/powerpc/gdbserver.mk, the content of which is as follows:

G_INTERNAL_CFLAGS=-g     -I. -I.. -I${DIST}/gdb/gdbserver -I${DIST}/gdb/gdbserver/.. -I${DIST}/gdb/gdbserver/../config -I${DIST}/gdb/gdbserver/../../include -I../../bfd -I${DIST}/gdb/gdbserver/../../bfd -DGDBSERVER
G_OBS=utils.o low-nbsd.o server.o remote-utils.o

This file can be downloaded from http://www.bluedonkey.org/twiki/pub/Netbsd/RemoteDebugging/gdbserver.mk

The patch can be downloaded from: http://www.bluedonkey.org/twiki/pub/Netbsd/RemoteDebugging/gdbserver-20030527.patch

It is also pasted here:

? gnu/usr.bin/gdb/arch/powerpc/gdbserver.mk
Index: gnu/dist/toolchain/gdb/remote.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/remote.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 remote.c
--- gnu/dist/toolchain/gdb/remote.c	2000/07/26 00:32:58	1.1.1.1
+++ gnu/dist/toolchain/gdb/remote.c	2003/05/29 06:54:15
@@ -91,6 +91,8 @@
 static void extended_remote_open PARAMS ((char *name, int from_tty));
 static void extended_remote_async_open PARAMS ((char *name, int from_tty));
 
+static void remote_check_symbols PARAMS ((struct objfile *objfile));
+
 static void remote_open_1 PARAMS ((char *, int, struct target_ops *,
 				   int extended_p));
 static void remote_async_open_1 PARAMS ((char *, int, struct target_ops *,
@@ -185,6 +187,8 @@
 
 static void record_currthread PARAMS ((int currthread));
 
+static int hex2bin PARAMS ((const char *hex, char *bin, int count));
+
 /* exported functions */
 
 extern int fromhex PARAMS ((int a));
@@ -1595,10 +1599,16 @@
   char *buf = alloca (PBUFSIZ);
   char *bufp;
   int tid;
+  static int threading_initialised = 0;
 
   if (remote_desc == 0)		/* paranoia */
     error ("Command can only be used when connected to the remote target.");
 
+  if (!threading_initialised)
+    {
+    remote_check_symbols(symfile_objfile);
+    }
+
   if (use_threadinfo_query)
     {
       putpkt ("qfThreadInfo");
@@ -1606,12 +1616,21 @@
       getpkt (bufp, PBUFSIZ, 0);
       if (bufp[0] != '\0')		/* q packet recognized */
 	{	
+	  if (bufp[0] == 'l')
+	    return;
+
+	  threading_initialised = 1;	/* threading is now ready */
+	  
 	  while (*bufp++ == 'm')	/* reply contains one or more TID */
 	    {
 	      do
 		{
 		  tid = strtol (bufp, &bufp, 16);
+#if 0
 		  if (tid != 0 && !in_thread_list (tid))
+#else
+		  if (!in_thread_list (tid))
+#endif
 		    add_thread (tid);
 		}
 	      while (*bufp++ == ',');	/* comma-separated list */
@@ -2004,6 +2023,61 @@
   remote_async_open_1 (name, from_tty, &extended_async_remote_ops, 1 /*extended_p */ );
 }
 
+/* Hex/numeric conversion */
+
+static int
+hex2bin (const char *hex, char *bin, 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;
+}
+
+/* Symbol lookup support */
+
+static void
+remote_check_symbols (struct objfile *objfile)
+{
+  char *msg, *reply, *tmp;
+  struct minimal_symbol *sym;
+  int end;
+
+  msg   = alloca (PBUFSIZ);
+  reply = alloca (PBUFSIZ);
+
+  /* Invite target to request symbol lookups. */
+
+  putpkt ("qSymbol::");
+  getpkt (reply, PBUFSIZ, 0);
+
+  while (strncmp (reply, "qSymbol:", 8) == 0)
+    {
+      tmp = &reply[8];
+      end = hex2bin (tmp, msg, strlen (tmp) / 2);
+      msg[end] = '\0';
+      sym = lookup_minimal_symbol (msg, NULL, NULL);
+      if (sym == NULL)
+        sprintf (msg, "qSymbol::%s", &reply[8]);
+      else
+        sprintf (msg, "qSymbol:%s:%s", 
+                 paddr_nz (SYMBOL_VALUE_ADDRESS (sym)),
+                 &reply[8]);
+      putpkt (msg);
+      getpkt (reply, PBUFSIZ, 0);
+    }
+}
+
 /* Generic code for opening a connection to a remote target.  */
 
 static DCACHE *remote_dcache;
@@ -2015,6 +2089,10 @@
      struct target_ops *target;
      int extended_p;
 {
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+  extern bfd *exec_bfd;
+#endif
+
   if (name == 0)
     error ("To open a remote debug connection, you need to specify what\n\
 serial device is attached to the remote system\n\
@@ -2096,6 +2174,20 @@
       putpkt ("!");
       getpkt (buf, PBUFSIZ, 0);
     }
+
+  /* Deal with any symbols that the target side needs */
+
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+  if (exec_bfd)
+    {
+      struct minimal_symbol *start;
+      struct target_waitstatus status;
+      CORE_ADDR _start_addr;
+      char saved [BREAKPOINT_MAX];
+
+      SOLIB_CREATE_INFERIOR_HOOK (inferior_pid);
+    }
+#endif
 }
 
 /* Just like remote_open but with asynchronous support. */
@@ -5597,6 +5689,8 @@
 #if 0
   init_remote_threadtests ();
 #endif
+
+  init_thread_list ();
 
   add_prefix_cmd ("remote", class_maintenance, set_remote_cmd, "\
 Remote protocol specific variables\n\
Index: gnu/dist/toolchain/gdb/solib.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/solib.c,v
retrieving revision 1.5
diff -u -r1.5 solib.c
--- gnu/dist/toolchain/gdb/solib.c	2002/01/18 04:15:02	1.5
+++ gnu/dist/toolchain/gdb/solib.c	2003/05/29 06:54:19
@@ -19,6 +19,10 @@
    Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+/*
+ * Enable debug output
+ */
+#undef DEBUG
 
 #include "defs.h"
 
@@ -1809,6 +1813,7 @@
       CORE_ADDR load_addr;
       bfd *tmp_bfd;
       CORE_ADDR sym_addr = 0;
+      char * tmp_buf;
 
       /* Read the contents of the .interp section into a local buffer;
          the contents specify the dynamic linker this program uses.  */
@@ -1825,10 +1830,40 @@
          to find any magic formula to find it for Solaris (appears to
          be trivial on GNU/Linux).  Therefore, we have to try an alternate
          mechanism to find the dynamic linker's base address.  */
-      tmp_bfd = bfd_openr (buf, gnutarget);
+
+      /* If the absolute prefix is set, use it */
+
+      if (solib_absolute_prefix != NULL)
+        {
+	  tmp_buf = xmalloc (strlen (buf) + strlen (solib_absolute_prefix) + 1);
+
+	  if (tmp_buf)
+	    {
+	      strcpy (tmp_buf, solib_absolute_prefix);
+	      strcat (tmp_buf, buf);
+	    }
+	}
+      else
+        {
+	  tmp_buf = buf;
+	}
+	      
+      tmp_bfd = bfd_openr (tmp_buf, gnutarget);
+#ifdef DEBUG
+      fprintf (stderr, "bfd_openr ('%s', '%s') == %p\n", tmp_buf, gnutarget,
+               tmp_bfd);
+#endif
+
       if (tmp_bfd == NULL)
-	goto bkpt_at_symbol;
+        {
+	  goto bkpt_at_symbol;
+	}
+
+      /* Free the buffer we allocated, if we did allocate one */
 
+      if ((solib_absolute_prefix != NULL) && (tmp_buf))
+        free (tmp_buf);
+
       /* Make sure the dynamic linker's really a useful object.  */
       if (!bfd_check_format (tmp_bfd, bfd_object))
 	{
@@ -1861,10 +1896,21 @@
 	    interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
 	}
 
+#ifdef DEBUG
+      fprintf (stderr, "interp_text_sect_low  = %#x\n", interp_text_sect_low);
+      fprintf (stderr, "interp_text_sect_high = %#x\n", interp_text_sect_high);
+      fprintf (stderr, "interp_plt_sect_low   = %#x\n", interp_plt_sect_low);
+      fprintf (stderr, "interp_plt_sect_high  = %#x\n", interp_plt_sect_high);
+#endif
+
       /* Now try to set a breakpoint in the dynamic linker.  */
       for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++)
 	{
 	  sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep);
+#ifdef DEBUG
+	  fprintf (stderr, "bfd_lookup_symbol (%p, '%s') = %#x\n", tmp_bfd,
+	           *bkpt_namep, sym_addr);
+#endif
 	  if (sym_addr != 0)
 	    break;
 	}
Index: gnu/dist/toolchain/gdb/config/powerpc/nbsd.mt
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/config/powerpc/nbsd.mt,v
retrieving revision 1.3
diff -u -r1.3 nbsd.mt
--- gnu/dist/toolchain/gdb/config/powerpc/nbsd.mt	2002/01/22 12:25:57	1.3
+++ gnu/dist/toolchain/gdb/config/powerpc/nbsd.mt	2003/05/29 06:54:21
@@ -1,5 +1,5 @@
 # Target: Big-endian PowerPC running NetBSD
-TDEPFILES= rs6000-tdep.o
+TDEPFILES= rs6000-tdep.o solib.o
 TM_FILE= tm-nbsd.h
 
 SIM_OBS = remote-sim.o
Index: gnu/dist/toolchain/gdb/config/powerpc/tm-nbsd.h
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/config/powerpc/tm-nbsd.h,v
retrieving revision 1.3
diff -u -r1.3 tm-nbsd.h
--- gnu/dist/toolchain/gdb/config/powerpc/tm-nbsd.h	2003/03/04 21:12:32	1.3
+++ gnu/dist/toolchain/gdb/config/powerpc/tm-nbsd.h	2003/05/29 06:54:21
@@ -27,6 +27,13 @@
 
 #define SOLIB_BKPT_NAME "_start"
 
+#if !defined(NO_SOLIB)
+#ifndef SVR4_SHARED_LIBS
+#define SVR4_SHARED_LIBS
+#include "solib.h"
+#endif
+#endif
+
 #define CANNOT_FETCH_REGISTER(regno) (regno == PS_REGNUM || regno >= MQ_REGNUM)
 #define CANNOT_STORE_REGISTER(regno) (regno == PS_REGNUM || regno >= MQ_REGNUM)
 
Index: gnu/dist/toolchain/gdb/gdbserver/low-nbsd.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/gdbserver/low-nbsd.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 low-nbsd.c
--- gnu/dist/toolchain/gdb/gdbserver/low-nbsd.c	2000/07/26 00:33:51	1.1.1.1
+++ gnu/dist/toolchain/gdb/gdbserver/low-nbsd.c	2003/05/29 06:54:23
@@ -17,6 +17,11 @@
 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 <pthread.h>
+#include <pthread_dbg.h>
+
 #include "defs.h"
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -35,11 +40,51 @@
    register N.  */
 
 char buf2[MAX_REGISTER_RAW_SIZE];
+
+/* Thread support */
+
+static td_proc_t *main_ta;
+/* static int cached_thread; */
+
+struct td_proc_callbacks_t nbsd_thread_callbacks;
+
+/* Size of the string passed back to host to describe a thread */
+#define THREAD_INFO_DESC_SIZE	160
+
 /***************End MY defs*********************/
 
 #include <sys/ptrace.h>
 #include <machine/reg.h>
 
+/*
+ * Enable lots of debug output - use with care!
+ */
+#undef DEBUG
+
+/* Very minimal symbol table needed for thread support */
+
+struct nbsd_symtbl
+  {
+    char *	name;
+    CORE_ADDR	addr;
+  } pthread_syms[]	= {
+	{"pthread__dbg", NULL},
+	{"pthread__allqueue", NULL},
+	{"pthread__maxlwps", NULL},
+	{"pthread__tsd_alloc", NULL},
+	{"pthread__tsd_destructors", NULL},
+	{NULL, NULL}
+};
+
+/* Thread state strings */
+
+static const char *syncnames[] = {"unknown",
+                           "mutex",
+                           "cond var",
+                           "spinlock",
+                           "joining thread"};
+
+
 extern int sys_nerr;
 // extern char **sys_errlist;
 extern char **environ;
@@ -84,7 +129,330 @@
 
 #endif
 
+#ifdef __powerpc__
+
+void
+supply_register (regno, val)
+     int regno;
+     char *val;
+{
+  if (val)
+    memcpy (&registers[REGISTER_BYTE (regno)], val, REGISTER_RAW_SIZE (regno));
+  else
+    memset (&registers[REGISTER_BYTE (regno)], '\000', REGISTER_RAW_SIZE (regno));
+}
+
+supply_regs (regs)
+     char *regs;
+{
+  int i;
+
+  for (i = 0; i < 32; i++)
+    supply_register (GP0_REGNUM + i, regs + (i * 4));
+
+  supply_register (LR_REGNUM,  regs + (32 * 4));
+  supply_register (CR_REGNUM,  regs + (33 * 4));
+  supply_register (XER_REGNUM, regs + (34 * 4));
+  supply_register (CTR_REGNUM, regs + (35 * 4));
+  supply_register (PC_REGNUM,  regs + (36 * 4));
+  i = 0;
+  supply_register (PS_REGNUM,  (char *) &i);
+}
+
+static void
+unsupply_regs (regs)
+     struct reg *regs;
+{
+  memcpy (regs->fixreg, &registers[REGISTER_BYTE (GP0_REGNUM)],
+          sizeof (regs->fixreg));
+  memcpy (&regs->pc, &registers[REGISTER_BYTE (PC_REGNUM)],
+          sizeof (regs->pc));
+  memcpy (&regs->cr, &registers[REGISTER_BYTE (CR_REGNUM)],
+          sizeof (regs->cr));
+  memcpy (&regs->lr, &registers[REGISTER_BYTE (LR_REGNUM)],
+          sizeof (regs->lr));
+  memcpy (&regs->ctr, &registers[REGISTER_BYTE (CTR_REGNUM)],
+          sizeof (regs->ctr));
+  memcpy (&regs->xer, &registers[REGISTER_BYTE (XER_REGNUM)],
+          sizeof (regs->xer));
+
+}
+
+static void
+supply_fpregs (fregs)
+     char *fregs;
+{
+  int i;
+
+  for (i = 0; i < 32; i++)
+    supply_register (FP0_REGNUM + i, fregs + (i * 8));
+}
+
+static void
+unsupply_fpregs (fregs)
+     struct fpreg *fregs;
+{
+  memset (fregs, 0, sizeof (*fregs));
+  memcpy (fregs->fpreg, &registers[REGISTER_BYTE (FP0_REGNUM)], sizeof (fregs->fpreg));
+}
+
+static void
+nbsd_reg_to_internal (regs)
+     char *regs;
+{
+  supply_regs (regs);
+}
+
+static void
+nbsd_fpreg_to_internal (fregs)
+     char *fregs;
+{
+  supply_fpregs (fregs);
+}
+
+static void
+nbsd_internal_to_reg (regs)
+     char *regs;
+{
+  unsupply_regs (regs);
+}
+
+
+static void
+nbsd_internal_to_fpreg (regs)
+     char *regs;
+{
+  unsupply_fpregs (regs);
+}
+
+static void
+initialize_arch()
+{
+}
+
+#endif	/* __powerpc__ */
+
+/* Internal symbol management (mainly for thread support) */
+
+static void
+mysymbol (char * own_buf)
+{
+  static int i;
+  char * p;
+  char * q;
+
+  if (strcmp ("qSymbol::", own_buf) == 0)
+    {
+      /* First step in the process, reset the counter */
+
+      i = 0;
+    }
+  else
+    {
+      p = own_buf + strlen ("qSymbol:");
+      q = p;
+      while (*q && (*q != ':'))
+        q++;
+
+      if ((p != q) && (*q != '\0'))
+        {
+          /* Found a value */
+    
+          decode_address (&pthread_syms[i].addr, p, q - p);
+        }
+
+      i++;
+    }
+
+  if (pthread_syms[i].name != NULL)
+    {
+      strcpy (own_buf, "qSymbol:");
+      hexify (own_buf + strlen (own_buf), pthread_syms[i].name,
+              strlen (pthread_syms[i].name));
+    }
+  else
+    {
+      strcpy (own_buf, "OK");
+    }
+  return;
+}
+
+struct string_map
+  {
+    int num;
+    char *str;
+  };
+
+static char *
+td_err_string (errcode)
+     int errcode;
+{
+  static struct string_map
+    td_err_table[] =
+  {
+    {TD_ERR_OK, "generic \"call succeeded\""},
+    {TD_ERR_ERR, "generic error."},
+    {TD_ERR_NOSYM, "symbol not found"},
+    {TD_ERR_NOOBJ, "no object can be found to satisfy query"},
+    {TD_ERR_BADTHREAD, "thread can not answer request"},
+    {TD_ERR_INUSE, "debugging interface already in use for this process"},
+    {TD_ERR_NOLIB, "process is not using libpthread"},
+    {TD_ERR_NOMEM, "out of memory"},
+    {TD_ERR_IO, "process callback error"},
+    {TD_ERR_INVAL, "invalid argument"},
+  };
+  const int td_err_size = sizeof td_err_table / sizeof (struct string_map);
+  int i;
+  static char buf[90];
+
+  for (i = 0; i < td_err_size; i++)
+    if (td_err_table[i].num == errcode)
+      return td_err_table[i].str;
+
+  sprintf (buf, "Unknown thread_db error code: %d", errcode);
+
+  return buf;
+}
+
+/* Thread support routines */
+
+nbsd_thread_proc_read (void *arg, caddr_t addr, void *buf, size_t size)
+{
+  read_inferior_memory ((CORE_ADDR)addr, buf, size);
+  return 0;
+}
+
+static int
+nbsd_thread_proc_write (void *arg, caddr_t addr, void *buf, size_t size)
+{
+  int val;
+
+  val = write_inferior_memory ((CORE_ADDR)addr, buf, size);
+
+  if (val == 0)
+    return 0;
+  else
+    return TD_ERR_IO;
+}
+
+static int
+nbsd_thread_proc_lookup (void *arg, char *sym, caddr_t *addr)
+{
+  int i = 0;
+
+  while (pthread_syms[i].name != NULL)
+    {
+      if (strcmp (pthread_syms[i].name, sym) == 0)
+        {
+	  if (pthread_syms[i].addr)
+	    {
+              *addr = (caddr_t) pthread_syms[i].addr;
+	      return 0;
+	    }
+	  break;
+        }
+      i++;
+    }
+
+  /*
+   * If we get here, then either the symbol wasn't in the table,
+   * or it had no value associated with it (yet).
+   */
+
+#ifdef DEBUG
+  fprintf (stderr, "lookup failed for %s\n", sym);
+#endif
+
+  return TD_ERR_NOSYM;
+}
 
+static int
+nbsd_thread_proc_regsize (void *arg, int regset, size_t *size)
+{
+  switch (regset)
+    {
+    case 0:
+      *size = sizeof (struct reg);
+      break;
+    case 1:
+      *size = sizeof (struct fpreg);
+      break;
+    default:
+      return TD_ERR_INVAL;
+    }
+
+  return 0;
+}
+
+static int
+nbsd_thread_proc_getregs (void *arg, int regset, int lwp, void *buf)
+{
+  struct reg gregs;
+  struct fpreg fpregs;
+  int saved_tid = general_thread;
+  int ret;
+
+  /* Build the thread ID for this LWP within the main process */
+
+  general_thread = lwp;
+
+  fetch_inferior_registers (0);
+
+  ret = 0;
+  switch (regset)
+    {
+    case 0:
+      nbsd_internal_to_reg (&gregs);
+      memcpy (buf, &gregs, sizeof (struct reg));
+      break;
+    case 1:
+      nbsd_internal_to_fpreg (&fpregs);
+      memcpy (buf, &fpregs, sizeof (struct fpreg));
+      break;
+    default: /* XXX need to handle other reg sets: SSE, AltiVec, etc. */
+      ret = TD_ERR_INVAL;
+    }
+
+  /* Restore the thread process ID */
+
+  general_thread = saved_tid;
+
+  return ret;
+}
+
+static int
+nbsd_thread_proc_setregs (void *arg, int regset, int lwp, void *buf)
+{
+  struct reg gregs;
+  struct fpreg fpregs;
+  int saved_tid = general_thread;
+  int ret;
+
+  ret = 0;
+
+  switch (regset)
+    {
+    case 0:
+      memcpy (&gregs, buf, sizeof (struct reg));
+      nbsd_reg_to_internal (&gregs);
+      break;
+    case 1:
+      memcpy (&fpregs, buf, sizeof (struct fpreg));
+      nbsd_fpreg_to_internal (&fpregs);
+      break;
+    default: /* XXX need to handle other reg sets: SSE, AltiVec, etc. */
+      ret = TD_ERR_INVAL;
+    }
+
+  general_thread = lwp;
+
+  store_inferior_registers (0);
+
+  general_thread = saved_tid;
+
+  return ret;
+}
+
 /* Start an inferior process and returns its pid.
    ALLARGS is a vector of program-name and args.
    ENV is the environment vector to pass.  */
@@ -112,6 +480,14 @@
       _exit (0177);
     }
 
+#ifdef DEBUG
+  fprintf (stderr, "create_inferior ('%s', ...) = %d\n", program, pid);
+#endif /* DEBUG */
+
+  /* Record the main thread as the current inferior thread too */
+
+  general_thread = GET_THREAD(pid);
+
   return pid;
 }
 
@@ -120,9 +496,15 @@
 void
 kill_inferior ()
 {
+#ifdef DEBUG
+  fprintf (stderr, "kill_inferior() called [inferior_pid = %#x]\n",
+           inferior_pid);
+#endif	/* DEBUG */
+
   if (inferior_pid == 0)
     return;
-  ptrace (PT_KILL, inferior_pid, 0, 0);
+  general_thread = 0;
+  ptrace (PT_KILL, GET_PROCESS (inferior_pid), 0, 0);
   wait (0);
   /*************inferior_died ();****VK**************/
 }
@@ -131,10 +513,275 @@
 int
 mythread_alive (pid)
      int pid;
+{
+  td_thread_t * thread;
+  td_thread_info_t ti;
+
+#ifdef DEBUG
+  fprintf (stderr, "mythread_alive(%d) called\n", pid);
+#endif	/* DEBUG */
+
+  if (threads_active)
+    {
+      if (td_map_id2thr (main_ta, pid, &thread) == 0)
+        {
+	  if (td_thr_info (thread, &ti) == 0)
+	    {
+	      /* Found thread OK => must be alive */
+	    
+	      return 1;
+	    }
+	}
+
+      /* Not found */
+      return 0;
+    }
+  else
+    return 1;	/* Not threading, or request for main thread */
+}
+
+/* Find active thread */
+
+int
+myfind_active_thread()
+{
+  int val;
+  td_thread_t * thread;
+  td_thread_info_t ti;
+
+  if (!threads_active)
+    return -1;
+
+  if ((val = td_map_lwps (main_ta)) != 0)
+    {
+      fprintf (stderr, "myfind_active_threads: td_map_lwps error = %s\n",
+               td_err_string (val));
+      return -1;
+    }
+
+  if ((val = td_map_lwp2thr (main_ta, 0, &thread)) != 0)
+    {
+      fprintf (stderr, "myfind_active_threads: td_map_lwp2thr error = %s\n",
+               td_err_string (val));
+      return -1;
+    }
+
+  if ((val = td_thr_info (thread, &ti)) != 0)
+    {
+      fprintf (stderr, "myfind_active_threads: td_thr_info error = %s\n",
+               td_err_string (val));
+      return -1;
+    }
+
+  return ti.thread_id;
+}
+
+/* Obtain information about a thread */
+
+static int
+waiter_cb (td_thread_t * thr, void * d)
+{
+  td_thread_info_t ti;
+  char * desc = (char *) d;
+
+  if (td_thr_info (thr, &ti) == 0)
+    {
+      sprintf (desc + strlen(desc), " %d", ti.thread_id);
+    }
+
+  return 0;
+}
+
+char *
+mythread_info (int tid)
+{
+  /*
+   * This is not very secure... should have a better technique to
+   * allocate this string really
+   */
+  static char desc [THREAD_INFO_DESC_SIZE];
+  int val;
+  char name [32];
+  td_thread_t * thread;
+  td_thread_info_t ti, ti2;
+  td_sync_t * ts;
+  td_sync_info_t tsi;
+
+#ifdef DEBUG
+  fprintf (stderr, "mythread_info (%d) called\n", tid);
+#endif
+
+  if ((val = td_map_id2thr (main_ta, tid, &thread)) != 0)
+    {
+      fprintf (stderr, "mythread_info: td_map_id2thr error = %s\n",
+               td_err_string (val));
+      return NULL;
+    }
+
+  if ((val = td_thr_info (thread, &ti)) != 0)
+    {
+      fprintf (stderr, "mythread_info: td_thr_info error = %s\n",
+               td_err_string (val));
+      return NULL;
+    }
+
+  if (ti.thread_type != TD_TYPE_USER)
+    return NULL;
+
+  td_thr_getname (thread, name, 32);
+
+  if (name[0] != '\0')
+    sprintf (desc, "%s: ", name);
+  else
+    strcpy (desc, "<no name>: ");
+
+  switch (ti.thread_state)
+    {
+      default:
+      case TD_STATE_UNKNOWN:
+        strcat (desc, "<unknown state> ");
+	break;
+
+      case TD_STATE_RUNNING:
+        strcat (desc, "running ");
+	break;
+
+      case TD_STATE_RUNNABLE:
+        strcat (desc, "active ");
+	break;
+
+      case TD_STATE_BLOCKED:
+        strcat (desc, "in kernel ");
+	break;
+
+      case TD_STATE_SLEEPING:
+        strcat (desc, "sleeping ");
+	break;
+
+      case TD_STATE_ZOMBIE:
+        strcat (desc, "zombie ");
+	break;
+    }
+
+  if (ti.thread_state == TD_STATE_SLEEPING)
+    {
+      td_thr_sleepinfo (thread, &ts);
+      td_sync_info (ts, &tsi);
+      if (tsi.sync_type == TD_SYNC_JOIN)
+        {
+	  td_thr_info (tsi.sync_data.join.thread, &ti2);
+	  sprintf (desc + strlen(desc), "joining thread %d ", ti2.thread_id);
+	}
+      else
+        {
+	  sprintf (desc + strlen(desc), "on %s at %p ",
+	           syncnames[tsi.sync_type], (void *) tsi.sync_addr);
+          if (tsi.sync_type == TD_SYNC_MUTEX)
+	    {
+	      td_thr_info (tsi.sync_data.mutex.owner, &ti2);
+	      sprintf (desc + strlen (desc), "owned by %d ", ti2.thread_id);
+	    }
+	}
+    }
+
+  if (ti.thread_hasjoiners)
+    {
+      strcat (desc, "[being joined by");
+      td_thr_join_iter (thread, waiter_cb, desc);
+      strcat (desc, "]");
+    }
+
+  return desc;
+}
+
+/* Enable thread support, if possible */
+
+void
+mythread_activate ()
+{
+  int val;
+
+  val = td_open (&nbsd_thread_callbacks, NULL, &main_ta);
+
+  if (val != 0)
+    {
+      fprintf (stderr, "mythread_activate: td_open() error = %s\n",
+               td_err_string (val));
+      return;
+    }
+
+  threads_active = 1;
+
+#ifdef DEBUG
+  fprintf (stderr, "Thread support activated...\n");
+#endif
+
+  myfind_new_threads ();
+
+  val = myfind_active_thread();
+  if (val == -1)
+    {
+      fprintf (stderr, "Unable to find active thread\n");
+    }
+  else
+    {
+      general_thread = val;
+    }
+  return;
+}
+
+/* Find all the threads in the current process */
+
+static int
+nbsd_find_new_threads_callback (th, ignored)
+     td_thread_t *th;
+     void *ignored;
 {
-  return 1;
+  int retval;
+  td_thread_info_t ti;
+  int pid;
+
+  if ((retval = td_thr_info (th, &ti)) != 0)
+      return -1;
+
+  pid = BUILD_THREAD (ti.thread_id, inferior_pid);
+
+#ifdef DEBUG
+      fprintf (stderr, "tid = %#x, pid = %#x\n", ti.thread_id, pid);
+#endif
+
+  if (ti.thread_type == TD_TYPE_USER &&
+      ti.thread_state != TD_STATE_ZOMBIE &&
+      !in_thread_list (pid))
+    {
+      add_thread (pid);
+#ifdef DEBUG
+      fprintf (stderr, "Added thread ID = %#x\n", pid);
+#endif
+    }
+
+  return 0;
 }
 
+void
+myfind_new_threads ()
+{
+  int retval;
+
+  if (threads_active == 0)
+    {
+#ifdef DEBUG
+      fprintf (stderr, "myfind_new_threads: thread support not active\n");
+#endif
+      return;
+    }
+
+  retval = td_thr_iter (main_ta, nbsd_find_new_threads_callback, (void *) 0);
+  if (retval != 0)
+    fprintf (stderr, "nbsd_find_new_threads: td_thr_iter: %s",
+          td_err_string (retval));
+}
+
 /* Wait for process, returns status */
 
 unsigned char
@@ -144,6 +791,10 @@
   int pid;
   int w;
 
+#ifdef DEBUG
+  fprintf (stderr, "mywait() called\n");
+#endif	/* DEBUG */
+
   pid = wait (&w);
   if (pid != inferior_pid)
     perror_with_name ("wait");
@@ -161,6 +812,21 @@
       return ((unsigned char) WTERMSIG (w));
     }
 
+  if (threads_active)
+    {
+      int tid;
+
+      if ((tid = myfind_active_thread ()) != -1)
+        {
+	  if (!in_thread_list (tid))
+	    add_thread (tid);
+#ifdef DEBUG
+          fprintf (stderr, "mywait: Setting general thread to %d\n", tid);
+#endif
+	  general_thread = tid;
+        }
+    }
+
   fetch_inferior_registers (0);
 
   *status = 'T';
@@ -176,8 +842,12 @@
      int step;
      int signal;
 {
+#ifdef DEBUG
+  fprintf (stderr, "myresume (%d, %d) called\n", step, signal);
+#endif /* DEBUG */
+
   errno = 0;
-  ptrace (step ? PT_STEP : PT_CONTINUE, inferior_pid, 
+  ptrace (step ? PT_STEP : PT_CONTINUE, GET_PROCESS (inferior_pid), 
 	  (PTRACE_ARG3_TYPE) 1, signal);
   if (errno)
     perror_with_name ("ptrace");
@@ -194,17 +864,62 @@
   struct reg inferior_registers;
   struct fpreg inferior_fp_registers;
 
-  ptrace (PT_GETREGS, inferior_pid,
-	  (PTRACE_ARG3_TYPE) &inferior_registers, 0);
-  memcpy (&registers[REGISTER_BYTE(0)], &inferior_registers, 
-	  sizeof(inferior_registers));
-
-#if 0 /* def FP0_REGNUM */
-  ptrace (PT_GETFPREGS, inferior_pid,
-	  (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
-  memcpy (&registers[REGISTER_BYTE(FP0_REGNUM)], &inferior_fp_registers,
-	  sizeof(inferior_fp_registers));
-#endif
+#ifdef DEBUG
+  fprintf (stderr, "fetch_inferior_registers() called\n");
+  fprintf (stderr, "    inferior_pid = %#x\n", inferior_pid);
+  fprintf (stderr, "    general_thread = %#x\n", general_thread);
+#endif /* DEBUG */
+
+  if (threads_active && general_thread != 0)
+    {
+      td_thread_t *thread;
+      int          val;
+
+      if ((val = td_map_id2thr (main_ta, general_thread, &thread)) != 0)
+        {
+	fprintf (stderr, "fetch_inferior_registers: td_map_id2thr -> %s\n",
+	         td_err_string (val));
+	return;
+	}
+      if ((val = td_thr_getregs (thread, 0, &inferior_registers)) != 0)
+        {
+	fprintf (stderr, "fetch_inferior_registers: td_thr_getregs(0) -> %s\n",
+	         td_err_string (val));
+	return;
+	}
+      if ((val = td_thr_getregs (thread, 1, &inferior_fp_registers)) != 0)
+        {
+	fprintf (stderr, "fetch_inferior_registers: td_thr_getregs(1) -> %s\n",
+	         td_err_string (val));
+	return;
+	}
+      supply_regs ((char *) &inferior_registers);
+      supply_fpregs ((char *) &inferior_fp_registers);
+    }
+  else
+    {
+      ptrace (PT_GETREGS, inferior_pid,
+	      (PTRACE_ARG3_TYPE) &inferior_registers, general_thread);
+      supply_regs ((char *) &inferior_registers);
+  
+      ptrace (PT_GETFPREGS, inferior_pid,
+	      (PTRACE_ARG3_TYPE) &inferior_fp_registers, general_thread);
+      supply_fpregs ((char *) &inferior_fp_registers);
+    }
+#ifdef DEBUG
+    {
+	int r;
+	for (r=0; r < 32; r++) {
+	    fprintf (stderr, "R%-2d = %#08x\n",r,inferior_registers.fixreg[r]);
+	}
+	fprintf (stderr, "lr  = %#08x\n", inferior_registers.lr);
+	fprintf (stderr, "cr  = %#08x\n", inferior_registers.cr);
+	fprintf (stderr, "xer = %#08x\n", inferior_registers.xer);
+	fprintf (stderr, "ctr = %#08x\n", inferior_registers.ctr);
+	fprintf (stderr, "pc  = %#08x\n", inferior_registers.pc);
+    }
+#endif	/* DEBUG */
+
 }
 
 /* Store our register values back into the inferior.
@@ -218,17 +933,50 @@
   struct reg inferior_registers;
   struct fpreg inferior_fp_registers;
 
-  memcpy (&inferior_registers, &registers[REGISTER_BYTE(0)], 
-	  sizeof(inferior_registers));
-  ptrace (PT_SETREGS, inferior_pid,
-	  (PTRACE_ARG3_TYPE) &inferior_registers, 0);
-
-#if 0 /* def FP0_REGNUM */
-  memcpy (&inferior_fp_registers, &registers[REGISTER_BYTE (FP0_REGNUM)],
-	  sizeof (inferior_fp_registers));
-  ptrace (PT_SETFPREGS, inferior_pid,
-	  (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
+#ifdef DEBUG
+  fprintf (stderr, "store_inferior_registers() called\n");
+  fprintf (stderr, "    inferior_pid = %#x\n", inferior_pid);
+  fprintf (stderr, "    general_thread = %#x\n", general_thread);
 #endif
+
+  if (threads_active && general_thread != 0)
+    {
+      td_thread_t *thread;
+      int          val;
+
+      if ((val = td_map_id2thr (main_ta, general_thread, &thread)) != 0)
+        {
+	fprintf (stderr, "fetch_inferior_registers: td_map_id2thr -> %s\n",
+	         td_err_string (val));
+	return;
+	}
+
+      unsupply_regs ((char *) &inferior_registers);
+      unsupply_fpregs ((char *) &inferior_fp_registers);
+
+      if ((val = td_thr_setregs (thread, 0, &inferior_registers)) != 0)
+        {
+	fprintf (stderr, "fetch_inferior_registers: td_thr_getregs(0) -> %s\n",
+	         td_err_string (val));
+	return;
+	}
+      if ((val = td_thr_setregs (thread, 1, &inferior_fp_registers)) != 0)
+        {
+	fprintf (stderr, "fetch_inferior_registers: td_thr_getregs(1) -> %s\n",
+	         td_err_string (val));
+	return;
+	}
+    }
+  else
+    {
+      unsupply_regs ((char *) &inferior_registers);
+      ptrace (PT_SETREGS, inferior_pid,
+	      (PTRACE_ARG3_TYPE) &inferior_registers, general_thread);
+
+      unsupply_fpregs ((char *) &inferior_fp_registers);
+      ptrace (PT_SETFPREGS, inferior_pid,
+	      (PTRACE_ARG3_TYPE) &inferior_fp_registers, general_thread);
+    }
 }
 
 /* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
@@ -240,6 +988,7 @@
 /* Copy LEN bytes from inferior's memory starting at MEMADDR
    to debugger memory starting at MYADDR.  */
 
+void
 read_inferior_memory (memaddr, myaddr, len)
      CORE_ADDR memaddr;
      char *myaddr;
@@ -254,10 +1003,15 @@
   /* Allocate buffer of that many longwords.  */
   register int *buffer = (int *) alloca (count * sizeof (int));
 
+#ifdef DEBUG
+  fprintf (stderr, "read_inferior_memory (%p, %p, %d)\n", memaddr, myaddr, len);
+#endif /* DEBUG */
+
   /* Read all the longwords */
   for (i = 0; i < count; i++, addr += sizeof (int))
     {
-      buffer[i] = ptrace (PT_READ_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0);
+      buffer[i] = ptrace (PT_READ_D, inferior_pid,
+                          (PTRACE_ARG3_TYPE) addr, 0);
     }
 
   /* Copy appropriate bytes out of the buffer.  */
@@ -285,15 +1039,19 @@
   register int *buffer = (int *) alloca (count * sizeof (int));
   extern int errno;
 
+#ifdef DEBUG
+  fprintf (stderr, "read_inferior_memory (%p, %p, %d)\n", memaddr, myaddr, len);
+#endif	/* DEBUG */
+
   /* Fill start and end extra bytes of buffer with existing memory data.  */
 
-  buffer[0] = ptrace (PT_READ_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0);
+  buffer[0] = ptrace (PT_READ_D, inferior_pid,
+                      (PTRACE_ARG3_TYPE) addr, 0);
 
   if (count > 1)
     {
-      buffer[count - 1]
-	= ptrace (PT_READ_D, inferior_pid,
-		  (PTRACE_ARG3_TYPE) addr + (count - 1) * sizeof (int), 0);
+      buffer[count - 1] = ptrace (PT_READ_D, inferior_pid,
+		      (PTRACE_ARG3_TYPE) addr + (count - 1) * sizeof (int), 0);
     }
 
   /* Copy data to be written over corresponding part of buffer */
@@ -305,7 +1063,8 @@
   for (i = 0; i < count; i++, addr += sizeof (int))
     {
       errno = 0;
-      ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
+      ptrace (PT_WRITE_D, inferior_pid,
+      	      (PTRACE_ARG3_TYPE) addr, buffer[i]);
       if (errno)
 	return errno;
     }
@@ -317,4 +1076,13 @@
 initialize_low ()
 {
   initialize_arch ();
+
+  nbsd_thread_callbacks.proc_read = nbsd_thread_proc_read;
+  nbsd_thread_callbacks.proc_write = nbsd_thread_proc_write;
+  nbsd_thread_callbacks.proc_lookup = nbsd_thread_proc_lookup;
+  nbsd_thread_callbacks.proc_regsize = nbsd_thread_proc_regsize;
+  nbsd_thread_callbacks.proc_getregs = nbsd_thread_proc_getregs;
+  nbsd_thread_callbacks.proc_setregs = nbsd_thread_proc_setregs;
+
+  mysymbol_hook = mysymbol;
 }
Index: gnu/dist/toolchain/gdb/gdbserver/remote-utils.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/gdbserver/remote-utils.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 remote-utils.c
--- gnu/dist/toolchain/gdb/gdbserver/remote-utils.c	2000/07/26 00:33:51	1.1.1.1
+++ gnu/dist/toolchain/gdb/gdbserver/remote-utils.c	2003/05/29 06:54:23
@@ -192,6 +192,42 @@
     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;
+}
+
+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;
+}
+
+
 /* Send a packet to the remote machine, with error checking.
    The data of the packet is in BUF.  Returns >= 0 on success, -1 otherwise. */
 
Index: gnu/dist/toolchain/gdb/gdbserver/server.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/gdbserver/server.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 server.c
--- gnu/dist/toolchain/gdb/gdbserver/server.c	2000/07/26 00:33:51	1.1.1.1
+++ gnu/dist/toolchain/gdb/gdbserver/server.c	2003/05/29 06:54:24
@@ -20,6 +20,11 @@
 
 #include "server.h"
 
+/*
+ * Enable server debug
+ */
+#undef DEBUG
+
 int cont_thread;
 int general_thread;
 int thread_from_wait;
@@ -27,6 +32,10 @@
 int extended_protocol;
 jmp_buf toplevel;
 int inferior_pid;
+int threads_active;
+struct thread_list_element * thread_list_head;
+
+void (*mysymbol_hook) PARAMS ((char * own_buf));
 
 static unsigned char
 start_inferior (argv, statusptr)
@@ -40,6 +49,187 @@
   return mywait (statusptr);
 }
 
+void
+add_thread (int id)
+{
+  struct thread_list_element * new_thread;
+
+  if ((new_thread = malloc (sizeof (struct thread_list_element))) == NULL)
+    return;
+
+  new_thread->id   = id;
+  new_thread->next = thread_list_head;
+  thread_list_head = new_thread;
+
+  return;
+}
+
+void
+delete_thread (int id)
+{
+  struct thread_list_element * thread_ptr = thread_list_head;
+  struct thread_list_element ** previous = &thread_list_head;
+
+  while (thread_ptr != NULL)
+    {
+      if (thread_ptr->id == id)
+        {
+          *previous = thread_ptr->next;
+	  free (thread_ptr);
+	  return;
+        }
+      previous = &(thread_ptr->next);
+      thread_ptr = thread_ptr->next;
+    }
+  return;
+}
+
+int
+in_thread_list (int id)
+{
+   struct thread_list_element * thread_ptr = thread_list_head;
+
+   while (thread_ptr != NULL)
+     {
+       if (thread_ptr->id == id)
+         return 1;
+       thread_ptr = thread_ptr->next;
+     }
+
+   /* If we get here, the thread ID was not in the list */
+
+   return 0;
+}
+
+/* -- Handle all of the extended 'q' packets. */
+void
+handle_query (own_buf)
+     char* own_buf;
+{
+  static struct thread_list_element * thread_ptr;
+  int tid;
+
+  /* Current thread ID */
+
+  if (strcmp ("qC", own_buf) == 0)
+    {
+      if ((tid = myfind_active_thread()) == -1)
+        sprintf (own_buf, "QC0");
+      else
+        sprintf (own_buf, "QC%x", tid);
+
+#ifdef DEBUG
+      fprintf (stderr, "Sending: %s\n", own_buf);
+#endif
+
+      return;
+    }
+
+  /*
+   * Symbol resolution
+   */
+
+  if (strncmp ("qSymbol:", own_buf, 8) == 0)
+    {
+    if (mysymbol_hook != NULL)
+        (*mysymbol_hook)(own_buf);
+    return;
+    }
+
+  if (strcmp ("qfThreadInfo", own_buf) == 0)
+    {
+      if (!threads_active)
+        {
+#ifdef DEBUG
+          fprintf (stderr, "Trying to activate thread support\n");
+#endif
+          mythread_activate();
+	}
+
+      /*
+       * Check again in case the previous call failed to activate thread
+       * support
+       */
+
+      if (threads_active)
+        {
+#ifdef DEBUG
+	  fprintf (stderr, "Checking for new threads\n");
+#endif
+	  myfind_new_threads ();
+
+	  thread_ptr = thread_list_head;
+	  sprintf (own_buf, "m%x", GET_THREAD(thread_ptr->id));
+	  thread_ptr = thread_ptr->next;
+	}
+      else
+        {
+	  /* Threads not active yet, just return an empty list */
+	   
+	  strcpy (own_buf, "l");
+	}
+
+#ifdef DEBUG
+      fprintf (stderr, "Sending: %s\n", own_buf);
+#endif
+
+      return;
+    }
+
+  if (strcmp ("qsThreadInfo", own_buf) == 0)
+    {
+      if (thread_ptr != NULL)
+        {
+	  sprintf (own_buf, "m%x", GET_THREAD(thread_ptr->id));
+	  thread_ptr = thread_ptr->next;
+	}
+      else
+        {
+          strcpy (own_buf, "l");
+	}
+
+#ifdef DEBUG
+      fprintf (stderr, "Sending: %s\n", own_buf);
+#endif
+
+      return;
+    }
+
+  if (strncmp ("qThreadExtraInfo,", own_buf, 17) == 0)
+    {
+      char * info;
+      int tid;
+
+      tid = strtol (&own_buf[17], NULL, 16);
+
+#ifdef DEBUG
+      fprintf (stderr, "Request for info on thread %d\n", tid);
+#endif
+
+      if ((info = mythread_info (tid)) != NULL)
+        {
+	  hexify (own_buf, info, strlen (info));
+#ifdef DEBUG
+          fprintf (stderr, "Thread Info (%d chars): '%s'\n",
+	           strlen (info), info);
+          fprintf (stderr, "Sending: '%s'\n", own_buf);
+#endif
+	  return;
+	}
+      own_buf[0] = '\0';
+      return;
+    }
+
+  /* Don't understand the query... */
+
+#ifdef DEBUG
+  fprintf (stderr, "Unknown query %s\n", own_buf);
+#endif
+
+  own_buf[0] = '\0';
+  return;
+}
+
 extern int remote_debug;
 
 int
@@ -80,8 +270,16 @@
 	  unsigned char sig;
 	  i = 0;
 	  ch = own_buf[i++];
+
+#ifdef DEBUG
+	  fprintf (stderr, "Command: %s\n", own_buf);
+#endif /* DEBUG */
+
 	  switch (ch)
 	    {
+	    case 'q':
+	      handle_query (own_buf);
+	      break;
 	    case 'd':
 	      remote_debug = !remote_debug;
 	      break;
@@ -206,6 +404,10 @@
 	      /* 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 DEBUG
+	      fprintf (stderr, "Unknown request (%s)\n", own_buf);
+#endif	/* DEBUG */
+
 	      own_buf[0] = '\0';
 	      break;
 	    }
Index: gnu/dist/toolchain/gdb/gdbserver/server.h
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/gdbserver/server.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 server.h
--- gnu/dist/toolchain/gdb/gdbserver/server.h	2000/07/26 00:33:51	1.1.1.1
+++ gnu/dist/toolchain/gdb/gdbserver/server.h	2003/05/29 06:54:24
@@ -21,13 +21,24 @@
 #include "defs.h"
 #include <setjmp.h>
 
+/* Thread list element type */
+
+struct thread_list_element
+  {
+    int					id;
+    struct thread_list_element *	next;
+  };
+
 /* Target-specific functions */
 
 int create_inferior PARAMS ((char *program, char **allargs));
 void kill_inferior PARAMS ((void));
 void fetch_inferior_registers PARAMS ((int regno));
 void store_inferior_registers PARAMS ((int regno));
+void mythread_activate PARAMS ((void));
+void myfind_new_threads PARAMS ((void));
 int mythread_alive PARAMS ((int pid));
+char * mythread_info PARAMS ((int tid));
 void myresume PARAMS ((int step, int signo));
 unsigned char mywait PARAMS ((char *status));
 void read_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
@@ -35,10 +46,18 @@
 int create_inferior ();
 void initialize_low ();
 
+extern void (*mysymbol_hook) PARAMS ((char * own_buf));
+
 /* Target-specific variables */
 
 extern char *registers;
 
+/* Public functions in server.c */
+
+void add_thread PARAMS ((int id));
+void delete_thread PARAMS ((int id));
+int in_thread_list PARAMS ((int id));
+
 /* Public variables in server.c */
 
 extern int cont_thread;
@@ -48,6 +67,8 @@
 
 extern jmp_buf toplevel;
 extern int inferior_pid;
+extern int threads_active;
+extern struct thread_list_element * thread_list_head;
 
 /* Functions from remote-utils.c */
 
@@ -68,6 +89,8 @@
 void decode_M_packet PARAMS ((char *from, CORE_ADDR * mem_addr_ptr,
 			      unsigned int *len_ptr, char *to));
 
+int hexify PARAMS ((char *hex, const char *bin, int count));
+void decode_address PARAMS ((CORE_ADDR *addrp, const char *start, int len));
 
 /* Functions from utils.c */
 
Index: gnu/usr.bin/gdb/Makefile
===================================================================
RCS file: /cvsroot/src/gnu/usr.bin/gdb/Makefile,v
retrieving revision 1.53
diff -u -r1.53 Makefile
--- gnu/usr.bin/gdb/Makefile	2002/09/22 12:58:23	1.53
+++ gnu/usr.bin/gdb/Makefile	2003/05/29 06:54:43
@@ -1,5 +1,13 @@
 #	$NetBSD: Makefile,v 1.53 2002/09/22 12:58:23 wiz Exp $
 
+#
+# Set the environment variable MKGDBSERVER to yes to build the gdbserver binary
+#
+
+.if (${MKGDBSERVER} == "yes")
+SUBDIR=		gdb gdbserver # gdbreplay
+.else
 SUBDIR=		gdb # gdbreplay gdbserver
+.endif
 
 .include <bsd.subdir.mk>
Index: gnu/usr.bin/gdb/gdbserver/Makefile
===================================================================
RCS file: /cvsroot/src/gnu/usr.bin/gdb/gdbserver/Makefile,v
retrieving revision 1.2
diff -u -r1.2 Makefile
--- gnu/usr.bin/gdb/gdbserver/Makefile	2002/09/19 03:09:37	1.2
+++ gnu/usr.bin/gdb/gdbserver/Makefile	2003/05/29 06:54:43
@@ -14,6 +14,8 @@
 		${G_INTERNAL_CFLAGS:M-[ID]*:N*readline*:N*intl*:N-I.*} \
 		-I${TOP}/lib/libbfd/arch/${MACHINE_ARCH}
 
+LDADD +=	-lpthread_dbg
+
 .include "../../Makefile.inc"
 .include <bsd.prog.mk>
 


>Release-Note:
>Audit-Trail:
>Unformatted: