This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA 03/08] multi-process support: remote multi-process extensions


On Friday 19 September 2008 17:29:49, Daniel Jacobowitz wrote:
> There's two things I don't want to end up with: crashes or other
> inconsistent behavior if you connect to a multi-process stub
> using target remote (which is what I was worried about here),
> and gratuitous differences between remote and extended-remote.
>
> It seems to me that we should define the actual difference - to the
> user - between target remote and target extended-remote. ?Is it the
> fact that kill does not disconnect you from the remote target (and
> usually cause it to exit)? ?If so, I don't think we should announce or
> support the multiprocess extensions when using target remote.
> It'll be just like things are today.

As we talked this on IRC, the only current description of
"extended" in the current docs is: "In extended mode, the
remote server is made persistent".  The other difference is
attach and run support.

If we make GDB assume that on a "target remote" connection
kill ('k') and detach ('D') kills and detaches from all
inferiors, I doesn't seem to be that much different from
what we have today.  At least, the single-inferior case
shouldn't be different, except, ...

The only issue I see, is that "target remote"'s detach
would need be know to remove breakpoints from all inferiors,
because the common code's common case of detaching from the
current inferior wouldn't know that this target would
have this different behaviour.  Hmmm, for that reason, I propose
sticking to the original plan for now, and only indeed only announce
multi-process support in target extended-remote.  At least,
until we need it in target remote.  I do have a strong feeling
we're coming come back to this soonish.  :-)

Attached patch does that.  The differences from the previous
patches are:

The changes we're discussing:
 - new remote_state field `extended'
 - new predicate function remote_multi_process_p, which checks
   for extended-remote usage.

And what I refered I had forgotten to merge into this
patch:
 - detecting new inferiors in remote_threads_info
 - Getting rid of the inferiors when getting rid of the
   target.

Retested against a x86_64-unknown-linux-gnu gdbserver.

Confirmed that connecting against a multi-process aware
gdbserver (in the works), behaves as we're discussing.

OK?

-- 
Pedro Alves
2008-09-19  Pedro Alves  <pedro@codesourcery.com>

	Implement multi-process extensions.

	* remote.c (struct remote_state): Add extended and
	multi_process_aware fields.
	(remote_multi_process_p): New.
	(PACKET_vKill): New.
	(record_currthread): Use thread_change_ptid.  Notice new
	inferiors.
	(set_thread, remote_thread_alive): Use write_ptid.
	(write_ptid, read_ptid): New.
	(remote_current_thread, remote_threads_extra_info): Use them.
	(remote_threads_info): Likewise.  Detect new inferiors.
	(remote_start_remote): Add inferior to inferior list.
	(remote_multi_process_feature): New.
	(remote_protocol_features): Add "multiprocess" feature.
	(remote_query_supported): Pass "multiprocess+" as supported
	features.
	(remote_open_1): Clear multi_process_aware.  Set extended
	accordingly.
	(remote_detach_1): Detach current process.  Use extended packet
	format for extended-remote multi-process.  Detach process from the
	inferior list.  Only mourn after printing output.
	(extended_remote_attach_1): Add process to the inferior list.
	(remote_vcont_resume): Use write_ptid to pass the thread ids.
	(remote_wait): Use read_ptid.  Implement the extended
	multi-process extension format of the 'W' and 'X' reply packets.
	Remove exited inferiors from inferior list.
	(remote_xfer_memory): Set general thread.
	(remote_vkill): New.
	(extended_remote_kill): New.
	(remote_mourn_1): Discard all inferiors.
	(select_new_thread_callback): New.
	(extended_remote_mourn_1): If there are more processes to debug,
	switch to a thread in another process, and don't pop the target.
	(extended_remote_create_inferior_1): Add the new process to the
	inferior list.
	(remote_stopped_by_watchpoint): Indenting.
	(remote_xfer_partial): Set the general thread.
	(remote_pid_to_str): If the remote is multi-process aware, print
	the process id as well as the thread id.
	(remote_get_thread_local_address): Use write_ptid.
	(init_extended_remote_ops): Register extended_remote_kill.
	(_initialize_remote): Register new packets.  Change
	magic_null_ptid's, not_sent_ptid's and any_thread_ptid's pid
	member to 42000.

	* thread.c (thread_change_ptid): Also account for the inferior pid
	changing.

	* inferior.h (discard_all_inferiors): Declare.
	* inferior.c (discard_all_inferiors): New.

---
 gdb/inferior.c |   12 +
 gdb/inferior.h |    3 
 gdb/remote.c   |  540 ++++++++++++++++++++++++++++++++++++++++++++-------------
 gdb/thread.c   |   11 +
 4 files changed, 448 insertions(+), 118 deletions(-)

Index: src/gdb/remote.c
===================================================================
--- src.orig/gdb/remote.c	2008-09-19 23:21:52.000000000 +0100
+++ src/gdb/remote.c	2008-09-19 23:21:54.000000000 +0100
@@ -208,6 +208,9 @@ static void show_remote_protocol_packet_
 					     struct cmd_list_element *c,
 					     const char *value);
 
+static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid);
+static ptid_t read_ptid (char *buf, char **obuf);
+
 void _initialize_remote (void);
 
 /* For "remote".  */
@@ -253,8 +256,22 @@ struct remote_state
      expect acks from each other.  The connection is assumed to be
      reliable.  */
   int noack_mode;
+
+  /* True if we're connected in extended remote mode.  */
+  int extended;
+
+  /* True if the stub reported support for multi-process
+     extensions.  */
+  int multi_process_aware;
 };
 
+/* Returns true if the multi-process extensions are in effect.  */
+static int
+remote_multi_process_p (struct remote_state *rs)
+{
+  return rs->extended && rs->multi_process_aware;
+}
+
 /* This data could be associated with a target, but we do not always
    have access to the current target when we need it, so for now it is
    static.  This will be fine for as long as only one target is in use
@@ -940,6 +957,7 @@ enum {
   PACKET_vAttach,
   PACKET_vRun,
   PACKET_QStartNoAckMode,
+  PACKET_vKill,
   PACKET_MAX
 };
 
@@ -1068,6 +1086,15 @@ record_currthread (ptid_t currthread)
 
   /* If this is a new thread, add it to GDB's thread list.
      If we leave it up to WFI to do this, bad things will happen.  */
+
+  if (in_thread_list (currthread) && is_exited (currthread))
+    {
+      /* We're seeing an event on a thread id we knew had exited.
+	 This has to be a new thread reusing the old id.  Add it.  */
+      add_thread (currthread);
+      return;
+    }
+
   if (!in_thread_list (currthread))
     {
       if (ptid_equal (pid_to_ptid (ptid_get_pid (currthread)), inferior_ptid))
@@ -1077,23 +1104,30 @@ record_currthread (ptid_t currthread)
 	     stub doesn't support qC.  This is the first stop reported
 	     after an attach, so this is the main thread.  Update the
 	     ptid in the thread list.  */
-	  struct thread_info *th = find_thread_pid (inferior_ptid);
-	  inferior_ptid = th->ptid = currthread;
+  	  thread_change_ptid (inferior_ptid, currthread);
+ 	  return;
 	}
-      else if (ptid_equal (magic_null_ptid, inferior_ptid))
+
+      if (ptid_equal (magic_null_ptid, inferior_ptid))
 	{
 	  /* inferior_ptid is not set yet.  This can happen with the
 	     vRun -> remote_wait,"TAAthread:" path if the stub
 	     doesn't support qC.  This is the first stop reported
 	     after an attach, so this is the main thread.  Update the
 	     ptid in the thread list.  */
-	  struct thread_info *th = find_thread_pid (inferior_ptid);
-	  inferior_ptid = th->ptid = currthread;
+  	  thread_change_ptid (inferior_ptid, currthread);
+	  return;
 	}
-      else
-	/* This is really a new thread.  Add it.  */
-	add_thread (currthread);
+
+      /* This is really a new thread.  Add it.  */
+      add_thread (currthread);
     }
+
+  if (!in_inferior_list (ptid_get_pid (currthread)))
+    /* When connecting to a target remote, or to a target
+       extended-remote which already was debugging an inferior, we may
+       not know about it yet --- add it.  */
+    add_inferior (ptid_get_pid (currthread));
 }
 
 static char *last_pass_packet;
@@ -1179,13 +1213,7 @@ set_thread (struct ptid ptid, int gen)
   else if (ptid_equal (ptid, minus_one_ptid))
     xsnprintf (buf, endbuf - buf, "-1");
   else
-    {
-      int tid = ptid_get_tid (ptid);
-      if (tid < 0)
-	xsnprintf (buf, endbuf - buf, "-%x", -tid);
-      else
-	xsnprintf (buf, endbuf - buf, "%x", tid);
-    }
+    write_ptid (buf, endbuf, ptid);
   putpkt (rs->buf);
   getpkt (&rs->buf, &rs->buf_size, 0);
   if (gen)
@@ -1215,6 +1243,7 @@ remote_thread_alive (ptid_t ptid)
 {
   struct remote_state *rs = get_remote_state ();
   int tid = ptid_get_tid (ptid);
+  char *p, *endp;
 
   if (ptid_equal (ptid, magic_null_ptid))
     /* The main thread is always alive.  */
@@ -1226,10 +1255,12 @@ remote_thread_alive (ptid_t ptid)
        multi-threading.  */
     return 1;
 
-  if (tid < 0)
-    xsnprintf (rs->buf, get_remote_packet_size (), "T-%08x", -tid);
-  else
-    xsnprintf (rs->buf, get_remote_packet_size (), "T%08x", tid);
+  p = rs->buf;
+  endp = rs->buf + get_remote_packet_size ();
+
+  *p++ = 'T';
+  write_ptid (p, endp, ptid);
+
   putpkt (rs->buf);
   getpkt (&rs->buf, &rs->buf_size, 0);
   return (rs->buf[0] == 'O' && rs->buf[1] == 'K');
@@ -1350,6 +1381,71 @@ static int remote_threadlist_iterator (r
 
 static int remote_newthread_step (threadref *ref, void *context);
 
+
+/* Write a PTID to BUF.  ENDBUF points to one-passed-the-end of the
+   buffer we're allowed to write to.  Returns
+   BUF+CHARACTERS_WRITTEN.  */
+
+static char *
+write_ptid (char *buf, const char *endbuf, ptid_t ptid)
+{
+  int pid, tid;
+  struct remote_state *rs = get_remote_state ();
+
+  if (remote_multi_process_p (rs))
+    {
+      pid = ptid_get_pid (ptid);
+      if (pid < 0)
+	buf += xsnprintf (buf, endbuf - buf, "p-%x.", -pid);
+      else
+	buf += xsnprintf (buf, endbuf - buf, "p%x.", pid);
+    }
+  tid = ptid_get_tid (ptid);
+  if (tid < 0)
+    buf += xsnprintf (buf, endbuf - buf, "-%x", -tid);
+  else
+    buf += xsnprintf (buf, endbuf - buf, "%x", tid);
+
+  return buf;
+}
+
+/* Extract a PTID from BUF.  If non-null, OBUF is set to the to one
+   passed the last parsed char.  Returns null_ptid on error.  */
+
+static ptid_t
+read_ptid (char *buf, char **obuf)
+{
+  char *p = buf;
+  char *pp;
+  ULONGEST pid = 0, tid = 0;
+  ptid_t ptid;
+
+  if (*p == 'p')
+    {
+      /* Multi-process ptid.  */
+      pp = unpack_varlen_hex (p + 1, &pid);
+      if (*pp != '.')
+	error (_("invalid remote ptid: %s\n"), p);
+
+      p = pp;
+      pp = unpack_varlen_hex (p + 1, &tid);
+      if (obuf)
+	*obuf = pp;
+      return ptid_build (pid, 0, tid);
+    }
+
+  /* No multi-process.  Just a tid.  */
+  pp = unpack_varlen_hex (p, &tid);
+
+  /* Since the stub is not sending a process id, then default to
+     what's in inferior_ptid.  */
+  pid = ptid_get_pid (inferior_ptid);
+
+  if (obuf)
+    *obuf = pp;
+  return ptid_build (pid, 0, tid);
+}
+
 /* Encode 64 bits in 16 chars of hex.  */
 
 static const char hexchars[] = "0123456789abcdef";
@@ -1916,16 +2012,7 @@ remote_current_thread (ptid_t oldpid)
   putpkt ("qC");
   getpkt (&rs->buf, &rs->buf_size, 0);
   if (rs->buf[0] == 'Q' && rs->buf[1] == 'C')
-    {
-      /* Use strtoul here, so we'll correctly parse values whose
-	 highest bit is set.  The protocol carries them as a simple
-	 series of hex digits; in the absence of a sign, strtol will
-	 see such values as positive numbers out of range for signed
-	 'long', and return LONG_MAX to indicate an overflow.  */
-      tid = strtoul (&rs->buf[2], NULL, 16);
-      pid = ptid_get_pid (oldpid);
-      return ptid_build (pid, 0, tid);
-    }
+    return read_ptid (&rs->buf[2], NULL);
   else
     return oldpid;
 }
@@ -1953,8 +2040,6 @@ remote_threads_info (void)
 {
   struct remote_state *rs = get_remote_state ();
   char *bufp;
-  int tid;
-  int pid;
   ptid_t new_thread;
 
   if (remote_desc == 0)		/* paranoia */
@@ -1971,17 +2056,19 @@ remote_threads_info (void)
 	    {
 	      do
 		{
-		  /* Use strtoul here, so we'll correctly parse values
-		     whose highest bit is set.  The protocol carries
-		     them as a simple series of hex digits; in the
-		     absence of a sign, strtol will see such values as
-		     positive numbers out of range for signed 'long',
-		     and return LONG_MAX to indicate an overflow.  */
-		  tid = strtoul (bufp, &bufp, 16);
-		  pid = ptid_get_pid (inferior_ptid);
-		  new_thread = ptid_build (pid, 0, tid);
-		  if (tid != 0 && !in_thread_list (new_thread))
-		    add_thread (new_thread);
+		  new_thread = read_ptid (bufp, &bufp);
+		  if (!ptid_equal (new_thread, null_ptid)
+		      && !in_thread_list (new_thread))
+		    {
+		      if (!in_inferior_list (ptid_get_pid (new_thread)))
+			/* When connected to a multi-process aware
+			   stub, "info threads" may show up threads of
+			   inferiors we didn't know about yet.  Add
+			   them.  */
+			add_inferior (ptid_get_pid (new_thread));
+
+		      add_thread (new_thread);
+		    }
 		}
 	      while (*bufp++ == ',');	/* comma-separated list */
 	      putpkt ("qsThreadInfo");
@@ -2030,8 +2117,13 @@ remote_threads_extra_info (struct thread
 
   if (use_threadextra_query)
     {
-      xsnprintf (rs->buf, get_remote_packet_size (), "qThreadExtraInfo,%lx",
-		 ptid_get_tid (tp->ptid));
+      char *b = rs->buf;
+      char *endb = rs->buf + get_remote_packet_size ();
+
+      xsnprintf (b, endb - b, "qThreadExtraInfo,");
+      b += strlen (b);
+      write_ptid (b, endb, tp->ptid);
+
       putpkt (rs->buf);
       getpkt (&rs->buf, &rs->buf_size, 0);
       if (rs->buf[0] != 0)
@@ -2321,6 +2413,8 @@ remote_start_remote (struct ui_out *uiou
   /* Now, if we have thread information, update inferior_ptid.  */
   inferior_ptid = remote_current_thread (inferior_ptid);
 
+  add_inferior (ptid_get_pid (inferior_ptid));
+
   /* Always add the main thread.  */
   add_thread_silent (inferior_ptid);
 
@@ -2518,6 +2612,14 @@ remote_packet_size (const struct protoco
   rs->explicit_packet_size = packet_size;
 }
 
+static void
+remote_multi_process_feature (const struct protocol_feature *feature,
+			      enum packet_support support, const char *value)
+{
+  struct remote_state *rs = get_remote_state ();
+  rs->multi_process_aware = (support == PACKET_ENABLE);
+}
+
 static struct protocol_feature remote_protocol_features[] = {
   { "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
   { "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
@@ -2536,6 +2638,7 @@ static struct protocol_feature remote_pr
     PACKET_QPassSignals },
   { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
     PACKET_QStartNoAckMode },
+  { "multiprocess", PACKET_DISABLE, remote_multi_process_feature, -1 },
 };
 
 static void
@@ -2556,7 +2659,11 @@ remote_query_supported (void)
   rs->buf[0] = 0;
   if (remote_protocol_packets[PACKET_qSupported].support != PACKET_DISABLE)
     {
-      putpkt ("qSupported");
+      if (rs->extended)
+	putpkt ("qSupported:multiprocess+");
+      else
+	putpkt ("qSupported");
+
       getpkt (&rs->buf, &rs->buf_size, 0);
 
       /* If an error occured, warn, but do not return - just reset the
@@ -2753,6 +2860,8 @@ remote_open_1 (char *name, int from_tty,
   init_all_packet_configs ();
   rs->explicit_packet_size = 0;
   rs->noack_mode = 0;
+  rs->multi_process_aware = 0;
+  rs->extended = extended_p;
 
   general_thread = not_sent_ptid;
   continue_thread = not_sent_ptid;
@@ -2875,6 +2984,7 @@ remote_open_1 (char *name, int from_tty,
 static void
 remote_detach_1 (char *args, int from_tty, int extended)
 {
+  int pid = ptid_get_pid (inferior_ptid);
   struct remote_state *rs = get_remote_state ();
 
   if (args)
@@ -2884,25 +2994,41 @@ remote_detach_1 (char *args, int from_tt
     error (_("No process to detach from."));
 
   /* Tell the remote target to detach.  */
-  strcpy (rs->buf, "D");
+  if (remote_multi_process_p (rs))
+    sprintf (rs->buf, "D;%x", pid);
+  else
+    strcpy (rs->buf, "D");
+
   putpkt (rs->buf);
   getpkt (&rs->buf, &rs->buf_size, 0);
 
-  if (rs->buf[0] == 'E')
+  if (rs->buf[0] == 'O' && rs->buf[1] == 'K')
+    ;
+  else if (rs->buf[0] == '\0')
+    error (_("Remote doesn't know how to detach"));
+  else
     error (_("Can't detach process."));
 
   /* Unregister the file descriptor from the event loop.  */
   if (target_is_async_p ())
     serial_async (remote_desc, NULL, 0);
 
-  target_mourn_inferior ();
   if (from_tty)
     {
-      if (extended)
-	puts_filtered ("Detached from remote process.\n");
+      if (remote_multi_process_p (rs))
+	printf_filtered (_("Detached from remote %s.\n"),
+			 target_pid_to_str (pid_to_ptid (pid)));
       else
-	puts_filtered ("Ending remote debugging.\n");
+	{
+	  if (extended)
+	    puts_filtered (_("Detached from remote process.\n"));
+	  else
+	    puts_filtered (_("Ending remote debugging.\n"));
+	}
     }
+
+  detach_inferior (pid);
+  target_mourn_inferior ();
 }
 
 static void
@@ -2987,6 +3113,8 @@ extended_remote_attach_1 (struct target_
   /* Now, if we have thread information, update inferior_ptid.  */
   inferior_ptid = remote_current_thread (inferior_ptid);
 
+  add_inferior (pid);
+
   /* Now, add the main thread to the thread list.  */
   add_thread_silent (inferior_ptid);
 
@@ -3131,8 +3259,8 @@ static int
 remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal)
 {
   struct remote_state *rs = get_remote_state ();
-  char *outbuf;
-  struct cleanup *old_cleanup;
+  char *p;
+  char *endp;
 
   if (remote_protocol_packets[PACKET_vCont].support == PACKET_SUPPORT_UNKNOWN)
     remote_vcont_probe (rs);
@@ -3140,6 +3268,9 @@ remote_vcont_resume (ptid_t ptid, int st
   if (remote_protocol_packets[PACKET_vCont].support == PACKET_DISABLE)
     return 0;
 
+  p = rs->buf;
+  endp = rs->buf + get_remote_packet_size ();
+
   /* If we could generate a wider range of packets, we'd have to worry
      about overflowing BUF.  Should there be a generic
      "multi-part-packet" packet?  */
@@ -3151,47 +3282,75 @@ remote_vcont_resume (ptid_t ptid, int st
 	 understand.  Make sure to only send forms that do not specify
 	 a TID.  */
       if (step && siggnal != TARGET_SIGNAL_0)
-	outbuf = xstrprintf ("vCont;S%02x", siggnal);
+	xsnprintf (p, endp - p, "vCont;S%02x", siggnal);
       else if (step)
-	outbuf = xstrprintf ("vCont;s");
+	xsnprintf (p, endp - p, "vCont;s");
       else if (siggnal != TARGET_SIGNAL_0)
-	outbuf = xstrprintf ("vCont;C%02x", siggnal);
+	xsnprintf (p, endp - p, "vCont;C%02x", siggnal);
       else
-	outbuf = xstrprintf ("vCont;c");
+	xsnprintf (p, endp - p, "vCont;c");
     }
   else if (ptid_equal (ptid, minus_one_ptid))
     {
       /* Resume all threads, with preference for INFERIOR_PTID.  */
-      int tid = ptid_get_tid (inferior_ptid);
       if (step && siggnal != TARGET_SIGNAL_0)
-	outbuf = xstrprintf ("vCont;S%02x:%x;c", siggnal, tid);
+	{
+	  /* Step inferior_ptid with signal.  */
+	  p += xsnprintf (p, endp - p, "vCont;S%02x:", siggnal);
+	  p = write_ptid (p, endp, inferior_ptid);
+	  /* And continue others.  */
+	  p += xsnprintf (p, endp - p, ";c");
+	}
       else if (step)
-	outbuf = xstrprintf ("vCont;s:%x;c", tid);
+	{
+	  /* Step inferior_ptid.  */
+	  p += xsnprintf (p, endp - p, "vCont;s:");
+	  p = write_ptid (p, endp, inferior_ptid);
+	  /* And continue others.  */
+	  p += xsnprintf (p, endp - p, ";c");
+	}
       else if (siggnal != TARGET_SIGNAL_0)
-	outbuf = xstrprintf ("vCont;C%02x:%x;c", siggnal, tid);
+	{
+	  /* Continue inferior_ptid with signal.  */
+	  p += xsnprintf (p, endp - p, "vCont;C%02x:", siggnal);
+	  p = write_ptid (p, endp, inferior_ptid);
+	  /* And continue others.  */
+	  p += xsnprintf (p, endp - p, ";c");
+	}
       else
-	outbuf = xstrprintf ("vCont;c");
+	xsnprintf (p, endp - p, "vCont;c");
     }
   else
     {
       /* Scheduler locking; resume only PTID.  */
-      int tid = ptid_get_tid (ptid);
       if (step && siggnal != TARGET_SIGNAL_0)
-	outbuf = xstrprintf ("vCont;S%02x:%x", siggnal, tid);
+	{
+	  /* Step ptid with signal.  */
+	  p += xsnprintf (p, endp - p, "vCont;S%02x:", siggnal);
+	  p = write_ptid (p, endp, ptid);
+	}
       else if (step)
-	outbuf = xstrprintf ("vCont;s:%x", tid);
+	{
+	  /* Step ptid.  */
+	  p += xsnprintf (p, endp - p, "vCont;s:");
+	  p = write_ptid (p, endp, ptid);
+	}
       else if (siggnal != TARGET_SIGNAL_0)
-	outbuf = xstrprintf ("vCont;C%02x:%x", siggnal, tid);
+	{
+	  /* Continue ptid with signal.  */
+	  p += xsnprintf (p, endp - p, "vCont;C%02x:", siggnal);
+	  p = write_ptid (p, endp, ptid);
+	}
       else
-	outbuf = xstrprintf ("vCont;c:%x", tid);
+	{
+	  /* Continue ptid.  */
+	  p += xsnprintf (p, endp - p, "vCont;c:");
+	  p = write_ptid (p, endp, ptid);
+	}
     }
 
-  gdb_assert (outbuf && strlen (outbuf) < get_remote_packet_size ());
-  old_cleanup = make_cleanup (xfree, outbuf);
-
-  putpkt (outbuf);
-
-  do_cleanups (old_cleanup);
+  gdb_assert (strlen (rs->buf) < get_remote_packet_size ());
+  putpkt (rs->buf);
 
   return 1;
 }
@@ -3446,8 +3605,7 @@ remote_wait (ptid_t ptid, struct target_
 {
   struct remote_state *rs = get_remote_state ();
   struct remote_arch_state *rsa = get_remote_arch_state ();
-  ULONGEST thread_num = -1;
-  ULONGEST process_num = -1;
+  ptid_t event_ptid = null_ptid;
   ULONGEST addr;
   int solibs_changed = 0;
 
@@ -3542,10 +3700,7 @@ remote_wait (ptid_t ptid, struct target_
 Packet: '%s'\n"),
 			     p, buf);
 		    if (strncmp (p, "thread", p1 - p) == 0)
-		      {
-			p_temp = unpack_varlen_hex (++p1, &thread_num);
-			p = p_temp;
-		      }
+		      event_ptid = read_ptid (++p1, &p);
 		    else if ((strncmp (p, "watch", p1 - p) == 0)
 			     || (strncmp (p, "rwatch", p1 - p) == 0)
 			     || (strncmp (p, "awatch", p1 - p) == 0))
@@ -3617,18 +3772,56 @@ Packet: '%s'\n"),
 	    }
 	  goto got_status;
 	case 'W':		/* Target exited.  */
+	case 'X':
 	  {
-	    /* The remote process exited.  */
-	    status->kind = TARGET_WAITKIND_EXITED;
-	    status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
+	    char *p;
+	    int pid;
+	    ULONGEST value;
+
+	    /* GDB used to accept only 2 hex chars here.  Stubs should
+	       only send more if they detect GDB supports
+	       multi-process support.  */
+	    p = unpack_varlen_hex (&buf[1], &value);
+
+	    if (buf[0] == 'W')
+	      {
+		/* The remote process exited.  */
+		status->kind = TARGET_WAITKIND_EXITED;
+		status->value.integer = value;
+	      }
+	    else
+	      {
+		/* The remote process exited with a signal.  */
+		status->kind = TARGET_WAITKIND_SIGNALLED;
+		status->value.sig = (enum target_signal) value;
+	      }
+
+	    /* If no process is specified, assume inferior_ptid.  */
+	    pid = ptid_get_pid (inferior_ptid);
+	    if (*p == '\0')
+	      ;
+	    else if (*p == ';')
+	      {
+		p++;
+
+		if (p == '\0')
+		  ;
+		else if (strncmp (p,
+				  "process:", sizeof ("process:") - 1) == 0)
+		  {
+		    ULONGEST upid;
+		    p += sizeof ("process:") - 1;
+		    unpack_varlen_hex (p, &upid);
+		    pid = upid;
+		  }
+		else
+		  error (_("unknown stop reply packet: %s"), buf);
+	      }
+	    else
+	      error (_("unknown stop reply packet: %s"), buf);
+	    event_ptid = ptid_build (pid, 0, 0);
 	    goto got_status;
 	  }
-	case 'X':
-	  status->kind = TARGET_WAITKIND_SIGNALLED;
-	  status->value.sig = (enum target_signal)
-	    (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
-
-	  goto got_status;
 	case 'O':		/* Console output.  */
 	  remote_console_output (buf + 1);
 	  if (target_can_async_p ())
@@ -3663,15 +3856,21 @@ Packet: '%s'\n"),
 	}
     }
 got_status:
-  if (thread_num != -1)
+  if (status->kind == TARGET_WAITKIND_EXITED
+      || status->kind == TARGET_WAITKIND_SIGNALLED)
+    {
+      int pid = ptid_get_pid (event_ptid);
+      delete_inferior (pid);
+    }
+  else
     {
-      ptid_t ptid;
-      ptid = ptid_build (ptid_get_pid (inferior_ptid), 0, thread_num);
-      record_currthread (ptid);
-      return ptid;
+      if (!ptid_equal (event_ptid, null_ptid))
+	record_currthread (event_ptid);
+      else
+	event_ptid = inferior_ptid;
     }
 
-  return inferior_ptid;
+  return event_ptid;
 }
 
 /* Fetch a single register using a 'p' packet.  */
@@ -4563,6 +4762,8 @@ remote_xfer_memory (CORE_ADDR mem_addr, 
 {
   int res;
 
+  set_general_thread (inferior_ptid);
+
   if (should_write)
     res = remote_write_bytes (mem_addr, buffer, mem_len);
   else
@@ -5187,6 +5388,58 @@ remote_kill (void)
   target_mourn_inferior ();
 }
 
+static int
+remote_vkill (int pid, struct remote_state *rs)
+{
+  if (remote_protocol_packets[PACKET_vKill].support == PACKET_DISABLE)
+    return -1;
+
+  /* Tell the remote target to detach.  */
+  sprintf (rs->buf, "vKill;%x", pid);
+  putpkt (rs->buf);
+  getpkt (&rs->buf, &rs->buf_size, 0);
+
+  if (packet_ok (rs->buf,
+		 &remote_protocol_packets[PACKET_vKill]) == PACKET_OK)
+    return 0;
+  else if (remote_protocol_packets[PACKET_vKill].support == PACKET_DISABLE)
+    return -1;
+  else
+    return 1;
+}
+
+static void
+extended_remote_kill (void)
+{
+  int res;
+  int pid = ptid_get_pid (inferior_ptid);
+  struct remote_state *rs = get_remote_state ();
+
+  res = remote_vkill (pid, rs);
+  if (res == -1 && !remote_multi_process_p (rs))
+    {
+      /* Don't try 'k' on a multi-process aware stub -- it has no way
+	 to specify the pid.  */
+
+      putpkt ("k");
+#if 0
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      if (rs->buf[0] != 'O' || rs->buf[0] != 'K')
+	res = 1;
+#else
+      /* Don't wait for it to die.  I'm not really sure it matters whether
+	 we do or not.  For the existing stubs, kill is a noop.  */
+      res = 0;
+#endif
+    }
+
+  if (res != 0)
+    error (_("Can't kill process"));
+
+  delete_inferior (pid);
+  target_mourn_inferior ();
+}
+
 static void
 remote_mourn (void)
 {
@@ -5197,10 +5450,27 @@ remote_mourn (void)
 static void
 remote_mourn_1 (struct target_ops *target)
 {
+  /* Get rid of all the inferiors and their threads we were
+     controlling.  */
+  discard_all_inferiors ();
+
   unpush_target (target);
   generic_mourn_inferior ();
 }
 
+static int
+select_new_thread_callback (struct thread_info *th, void* data)
+{
+  if (!ptid_equal (th->ptid, minus_one_ptid))
+    {
+      switch_to_thread (th->ptid);
+      printf_filtered (_("[Switching to %s]\n"),
+		       target_pid_to_str (inferior_ptid));
+      return 1;
+    }
+  return 0;
+}
+
 static void
 extended_remote_mourn_1 (struct target_ops *target)
 {
@@ -5209,27 +5479,45 @@ extended_remote_mourn_1 (struct target_o
   /* Unlike "target remote", we do not want to unpush the target; then
      the next time the user says "run", we won't be connected.  */
 
-  /* Call common code to mark the inferior as not running.  */
-  generic_mourn_inferior ();
-
-  /* Check whether the target is running now - some remote stubs
-     automatically restart after kill.  */
-  putpkt ("?");
-  getpkt (&rs->buf, &rs->buf_size, 0);
-
-  if (rs->buf[0] == 'S' || rs->buf[0] == 'T')
+  if (have_inferiors ())
     {
-      /* Assume that the target has been restarted.  Set inferior_ptid
-	 so that bits of core GDB realizes there's something here, e.g.,
-	 so that the user can say "kill" again.  */
-      inferior_ptid = remote_current_thread (magic_null_ptid);
-      add_thread_silent (inferior_ptid);
+      extern void nullify_last_target_wait_ptid ();
+      /* Multi-process case.  The current process has exited, but
+	 there are other processes to debug.  Switch to the first
+	 available.  */
+      iterate_over_threads (select_new_thread_callback, NULL);
+      nullify_last_target_wait_ptid ();
     }
   else
     {
-      /* Mark this (still pushed) target as not executable until we
-	 restart it.  */
-      target_mark_exited (target);
+      struct remote_state *rs = get_remote_state ();
+
+      /* Call common code to mark the inferior as not running.	*/
+      generic_mourn_inferior ();
+      if (!remote_multi_process_p (rs))
+	{
+	  /* Check whether the target is running now - some remote stubs
+	     automatically restart after kill.	*/
+	  putpkt ("?");
+	  getpkt (&rs->buf, &rs->buf_size, 0);
+
+	  if (rs->buf[0] == 'S' || rs->buf[0] == 'T')
+	    {
+	      /* Assume that the target has been restarted.  Set inferior_ptid
+		 so that bits of core GDB realizes there's something here, e.g.,
+		 so that the user can say "kill" again.	 */
+	      inferior_ptid = magic_null_ptid;
+	    }
+	  else
+	    {
+	      /* Mark this (still pushed) target as not executable until we
+		 restart it.  */
+	      target_mark_exited (target);
+	    }
+	}
+      else
+	/* Always remove execution if this was the last process.  */
+	target_mark_exited (target);
     }
 }
 
@@ -5339,6 +5627,7 @@ extended_remote_create_inferior_1 (char 
   attach_flag = 0;
   inferior_ptid = magic_null_ptid;
 
+  add_inferior (ptid_get_pid (inferior_ptid));
   add_thread_silent (inferior_ptid);
 
   target_mark_running (&extended_remote_ops);
@@ -5548,7 +5837,7 @@ remote_check_watch_resources (int type, 
 static int
 remote_stopped_by_watchpoint (void)
 {
-    return remote_stopped_by_watchpoint_p;
+  return remote_stopped_by_watchpoint_p;
 }
 
 static int
@@ -5906,11 +6195,15 @@ remote_xfer_partial (struct target_ops *
 		     const char *annex, gdb_byte *readbuf,
 		     const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
 {
-  struct remote_state *rs = get_remote_state ();
+  struct remote_state *rs;
   int i;
   char *p2;
   char query_type;
 
+  set_general_thread (inferior_ptid);
+
+  rs = get_remote_state ();
+
   /* Handle memory using the standard memory routines.  */
   if (object == TARGET_OBJECT_MEMORY)
     {
@@ -6389,12 +6682,20 @@ static char *
 remote_pid_to_str (ptid_t ptid)
 {
   static char buf[64];
+  struct remote_state *rs = get_remote_state ();
 
   if (ptid_equal (magic_null_ptid, ptid))
     {
       xsnprintf (buf, sizeof buf, "Thread <main>");
       return buf;
     }
+  else if (remote_multi_process_p (rs)
+	   && ptid_get_tid (ptid) != 0 && ptid_get_pid (ptid) != 0)
+    {
+      xsnprintf (buf, sizeof buf, "Thread %d.%ld",
+		 ptid_get_pid (ptid), ptid_get_tid (ptid));
+      return buf;
+    }
   else if (ptid_get_tid (ptid) != 0)
     {
       xsnprintf (buf, sizeof buf, "Thread %ld",
@@ -6415,11 +6716,12 @@ remote_get_thread_local_address (ptid_t 
     {
       struct remote_state *rs = get_remote_state ();
       char *p = rs->buf;
+      char *endp = rs->buf + get_remote_packet_size ();
       enum packet_result result;
 
       strcpy (p, "qGetTLSAddr:");
       p += strlen (p);
-      p += hexnumstr (p, ptid_get_tid (ptid));
+      p = write_ptid (p, endp, ptid);
       *p++ = ',';
       p += hexnumstr (p, offset);
       *p++ = ',';
@@ -7325,6 +7627,7 @@ Specify the serial device it is connecte
   extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
   extended_remote_ops.to_detach = extended_remote_detach;
   extended_remote_ops.to_attach = extended_remote_attach;
+  extended_remote_ops.to_kill = extended_remote_kill;
 }
 
 static int
@@ -7656,6 +7959,9 @@ Show the maximum size of the address (in
   add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartNoAckMode],
 			 "QStartNoAckMode", "noack", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vKill],
+			 "vKill", "kill", 0);
+
   /* Keep the old ``set remote Z-packet ...'' working.  Each individual
      Z sub-packet has its own set and show commands, but users may
      have sets to this variable in their .gdbinit files (or in their
@@ -7700,7 +8006,7 @@ Show the remote pathname for \"run\""), 
 
   /* Take advantage of the fact that the LWP field is not used, to tag
      special ptids with it set to != 0.  */
-  magic_null_ptid = ptid_build (0, 1, -1);
-  not_sent_ptid = ptid_build (0, 1, -2);
-  any_thread_ptid = ptid_build (0, 1, 0);
+  magic_null_ptid = ptid_build (42000, 1, -1);
+  not_sent_ptid = ptid_build (42000, 1, -2);
+  any_thread_ptid = ptid_build (42000, 1, 0);
 }
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c	2008-09-19 23:21:52.000000000 +0100
+++ src/gdb/thread.c	2008-09-19 23:21:54.000000000 +0100
@@ -466,7 +466,16 @@ prune_threads (void)
 void
 thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
 {
-  struct thread_info * tp = find_thread_pid (old_ptid);
+  struct inferior *inf;
+  struct thread_info *tp;
+
+  /* It can happen that what we knew as the target inferior id
+     changes.  E.g, target remote may only discover the remote process
+     pid after adding the inferior to GDB's list.  */
+  inf = find_inferior_pid (ptid_get_pid (old_ptid));
+  inf->pid = ptid_get_pid (new_ptid);
+
+  tp = find_thread_pid (old_ptid);
   tp->ptid = new_ptid;
 
   observer_notify_thread_ptid_changed (old_ptid, new_ptid);
Index: src/gdb/inferior.h
===================================================================
--- src.orig/gdb/inferior.h	2008-09-19 23:21:52.000000000 +0100
+++ src/gdb/inferior.h	2008-09-19 23:21:54.000000000 +0100
@@ -450,6 +450,9 @@ extern void delete_inferior_silent (int 
 /* Delete an existing inferior list entry, due to inferior detaching.  */
 extern void detach_inferior (int pid);
 
+/* Get rid of all inferiors.  */
+extern void discard_all_inferiors (void);
+
 /* Translate the integer inferior id (GDB's homegrown id, not the system's)
    into a "pid" (which may be overloaded with extra inferior information).  */
 extern int gdb_inferior_id_to_pid (int);
Index: src/gdb/inferior.c
===================================================================
--- src.orig/gdb/inferior.c	2008-09-19 23:21:52.000000000 +0100
+++ src/gdb/inferior.c	2008-09-19 23:21:54.000000000 +0100
@@ -170,6 +170,18 @@ detach_inferior (int pid)
     printf_unfiltered (_("[Inferior %d detached]\n"), pid);
 }
 
+void
+discard_all_inferiors (void)
+{
+  struct inferior *inf, *infnext;
+
+  for (inf = inferior_list; inf; inf = infnext)
+    {
+      infnext = inf->next;
+      delete_inferior_silent (inf->pid);
+    }
+}
+
 static struct inferior *
 find_inferior_id (int num)
 {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]