This is the mail archive of the gdb-patches@sources.redhat.com 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]

RFA/RFC: vCont for the remote protocol [gdbserver]


Gdbserver support, as promised.  I'll check this in (with any necessary
updates) once we've settled on the rest.  Then there'll be a follow-up to
delete the vestiges of Hs, since this is a much better solution.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2003-09-29  Daniel Jacobowitz  <drow@mvista.com>

	* linux-low.c (linux_resume): Take a struct thread_resume *
	argument.
	(linux_wait): Update call.
	(resume_ptr): New static variable.
	(linux_continue_one_thread): Renamed from
	linux_continue_one_process.  Use resume_ptr.
	(linux_resume): Use linux_continue_one_thread.
	* server.c (handle_v_cont, handle_v_requests): New functions.
	(myresume): New function.
	(main): Handle 'v' case.
	* target.h (struct thread_resume): New type.
	(struct target_ops): Change argument of "resume" to struct
	thread_resume *.
	(myresume): Delete macro.

Index: gdbserver/linux-low.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.25
diff -u -p -r1.25 linux-low.c
--- gdbserver/linux-low.c	29 Jun 2003 04:01:39 -0000	1.25
+++ gdbserver/linux-low.c	29 Sep 2003 14:29:24 -0000
@@ -52,7 +52,7 @@ 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 linux_resume (struct thread_resume *resume_info);
 static void stop_all_processes (void);
 static int linux_wait_for_event (struct thread_info *child);
 
@@ -652,7 +652,12 @@ retry:
 
       /* No stepping, no signal - unless one is pending already, of course.  */
       if (child == NULL)
-	linux_resume (0, 0);
+	{
+	  struct thread_resume resume_info;
+	  resume_info.thread = -1;
+	  resume_info.step = resume_info.sig = resume_info.leave_stopped = 0;
+	  linux_resume (&resume_info);
+	}
     }
 
   enable_async_io ();
@@ -868,33 +873,48 @@ linux_resume_one_process (struct inferio
     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 struct thread_resume *resume_ptr;
+
+/* This function is called once per thread.  We look up the thread
+   in RESUME_PTR, which will tell us whether to resume, step, or leave
+   the thread stopped; and what signal, if any, it should be sent.
+   For threads which we aren't explicitly told otherwise, we preserve
+   the stepping flag; this is used for stepping over gdbserver-placed
+   breakpoints.  If the thread has a status pending, it may not actually
+   be resumed.  */
 static void
-linux_continue_one_process (struct inferior_list_entry *entry)
+linux_continue_one_thread (struct inferior_list_entry *entry)
 {
   struct process_info *process;
+  struct thread_info *thread;
+  int ndx, step;
+
+  thread = (struct thread_info *) entry;
+  process = get_thread_process (thread);
+
+  ndx = 0;
+  while (resume_ptr[ndx].thread != -1 && resume_ptr[ndx].thread != entry->id)
+    ndx++;
+
+  if (resume_ptr[ndx].leave_stopped)
+    return;
+
+  if (resume_ptr[ndx].thread == -1)
+    step = process->stepping || resume_ptr[ndx].step;
+  else
+    step = resume_ptr[ndx].step;
 
-  process = (struct process_info *) entry;
-  linux_resume_one_process (entry, process->stepping, 0);
+  linux_resume_one_process (&process->head, step, resume_ptr[ndx].sig);
 }
 
 static void
-linux_resume (int step, int signal)
+linux_resume (struct thread_resume *resume_info)
 {
-  struct process_info *process;
-
-  process = get_thread_process (current_inferior);
-
-  /* If the current process has a status pending, this signal will
-     be enqueued and sent later.  */
-  linux_resume_one_process (&process->head, step, signal);
+  /* Yes, this is quadratic.  If it ever becomes a problem then it's
+     fairly easy to fix.  Yes, the use of a global here is rather ugly.  */
 
-  if (cont_thread == 0 || cont_thread == -1)
-    for_each_inferior (&all_processes, linux_continue_one_process);
+  resume_ptr = resume_info;
+  for_each_inferior (&all_threads, linux_continue_one_thread);
 }
 
 #ifdef HAVE_LINUX_USRREGS
Index: gdbserver/server.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/gdbserver/server.c,v
retrieving revision 1.15
diff -u -p -r1.15 server.c
--- gdbserver/server.c	17 Jun 2003 20:28:14 -0000	1.15
+++ gdbserver/server.c	29 Sep 2003 14:23:07 -0000
@@ -125,6 +125,138 @@ handle_query (char *own_buf)
   own_buf[0] = 0;
 }
 
+/* Parse vCont packets.  */
+void
+handle_v_cont (char *own_buf, char *status, unsigned char *signal)
+{
+  char *p, *q;
+  int n = 0, i = 0;
+  struct thread_resume *resume_info;
+
+  p = &own_buf[6];
+
+  while (p)
+    {
+      n++;
+      p = strchr (p, ';');
+      if (p)
+	p++;
+    }
+  resume_info = malloc ((n + 1) * sizeof (resume_info[0]));
+
+  p = &own_buf[6];
+  i = 0;
+  while (*p)
+    {
+      resume_info[i].leave_stopped = 0;
+
+      if (p[0] == 's' || p[0] == 'S')
+	resume_info[i].step = 1;
+      else if (p[0] == 'c' || p[0] == 'C')
+	resume_info[i].step = 0;
+      else
+	goto err;
+
+      if (p[0] == 'S' || p[0] == 'C')
+	{
+	  int sig;
+	  sig = strtol (p + 1, &q, 16);
+	  if (p == q)
+	    goto err;
+	  p = q;
+
+	  if (!target_signal_to_host_p (sig))
+	    goto err;
+	  resume_info[i].sig = target_signal_to_host (sig);
+	}
+      else
+	{
+	  resume_info[i].sig = 0;
+	  p = p + 1;
+	}
+
+      if (p[0] == 0)
+	resume_info[i].thread = -1;
+      else if (p[0] == ':')
+	{
+	  resume_info[i].thread = strtol (p + 1, &q, 16);
+	  if (p == q)
+	    goto err;
+	  p = q;
+	  if (p[0] == ';')
+	    p++;
+	  else if (p[0] != 0)
+	    goto err;
+	}
+
+      i++;
+    }
+  resume_info[i].thread = -1;
+  resume_info[i].leave_stopped = 1;
+  resume_info[i].step = 0;
+  resume_info[i].sig = 0;
+
+  /* Still used in occasional places in the backend.  */
+  if (n == 1 && resume_info[0].thread != -1)
+    cont_thread = resume_info[0].thread;
+  else
+    cont_thread = -1;
+
+  (*the_target->resume) (resume_info);
+  strcpy (own_buf, "OK");
+  putpkt (own_buf);
+
+  free (resume_info);
+
+  *signal = mywait (status, 1);
+  prepare_resume_reply (own_buf, *status, *signal);
+  return;
+
+ err:
+  strcpy (own_buf, "E01");
+  free (resume_info);
+  return;
+}
+
+/* Handle all of the extended 'v' packets.  */
+void
+handle_v_requests (char *own_buf, char *status, unsigned char *signal)
+{
+  if (strncmp (own_buf, "vCont:", 6) == 0)
+    {
+      handle_v_cont (own_buf, status, signal);
+      return;
+    }
+
+  /* Otherwise we didn't know what packet it was.  Say we didn't
+     understand it.  */
+  own_buf[0] = 0;
+  return;
+}
+
+void
+myresume (int step, int sig)
+{
+  struct thread_resume resume_info[2];
+  int n = 0;
+
+  if (step || sig || cont_thread > 0)
+    {
+      resume_info[0].thread
+	= ((struct inferior_list_entry *) current_inferior)->id;
+      resume_info[0].step = step;
+      resume_info[0].sig = sig;
+      resume_info[0].leave_stopped = 0;
+      n++;
+    }
+  resume_info[n].thread = -1;
+  resume_info[n].step = 0;
+  resume_info[n].sig = 0;
+  resume_info[n].leave_stopped = (cont_thread > 0);
+
+  (*the_target->resume) (resume_info);
+}
+
 static int attached;
 
 static void
@@ -383,6 +515,10 @@ main (int argc, char *argv[])
 		  own_buf[0] = '\0';
 		  break;
 		}
+	    case 'v':
+	      /* Extended (long) request.  */
+	      handle_v_requests (own_buf, &status, &signal);
+	      break;
 	    default:
 	      /* It is a request we don't understand.  Respond with an
 	         empty packet so that gdb knows that we don't support this
Index: gdbserver/target.h
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/gdbserver/target.h,v
retrieving revision 1.7
diff -u -p -r1.7 target.h
--- gdbserver/target.h	17 Jun 2003 20:28:14 -0000	1.7
+++ gdbserver/target.h	29 Sep 2003 02:07:12 -0000
@@ -24,6 +24,25 @@
 #ifndef TARGET_H
 #define TARGET_H
 
+/* This structure describes how to resume a particular thread (or
+   all threads) based on the client's request.  If thread is -1, then
+   this entry applies to all threads.  These are generally passed around
+   as an array, and terminated by a thread == -1 entry.  */
+
+struct thread_resume
+{
+  int thread;
+
+  /* If non-zero, leave this thread stopped.  */
+  int leave_stopped;
+
+  /* If non-zero, we want to single-step.  */
+  int step;
+
+  /* If non-zero, send this signal when we resume.  */
+  int sig;
+};
+
 struct target_ops
 {
   /* Start a new process.
@@ -56,14 +75,9 @@ struct target_ops
 
   int (*thread_alive) (int pid);
 
-  /* Resume the inferior process.
-
-     If STEP is non-zero, we want to single-step.
+  /* Resume the inferior process.  */
 
-     If SIGNAL is nonzero, send the process that signal as we resume it.
-   */
-
-  void (*resume) (int step, int signo);
+  void (*resume) (struct thread_resume *resume_info);
 
   /* Wait for the inferior process to change state.
 
@@ -131,9 +145,6 @@ void set_target_ops (struct target_ops *
 
 #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)


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