* linux-low.c (linux_resume): Take a struct thread_resume *
authorDaniel Jacobowitz <drow@false.org>
Mon, 13 Oct 2003 16:17:21 +0000 (16:17 +0000)
committerDaniel Jacobowitz <drow@false.org>
Mon, 13 Oct 2003 16:17:21 +0000 (16:17 +0000)
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.

gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/gdbserver/server.c
gdb/gdbserver/target.h

index 42dab168db6edd1b7a407bda4d4b40083164aa76..603c33f2527bf0787c8f0d6034435c7d6cec197f 100644 (file)
@@ -1,3 +1,20 @@
+2003-10-13  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.
+
 2003-08-08  H.J. Lu  <hongjiu.lu@intel.com>
 
        * Makefile.in (install-only): Create dest dir. Support DESTDIR.
index 55c187c1bd53c53d0d00e60ebb32657b56475142..68b3f65a335a18330cb4bc1d9a545d8c06c53099 100644 (file)
@@ -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 inferior_list_entry *entry,
     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 81fde5b7f73e8f1b3f9c1d0fac31f5e21ca87942..dffff2e1e61e71e185459a02e1a335af8a14de5c 100644 (file)
@@ -125,6 +125,155 @@ 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, default_action;
+
+  /* Count the number of semicolons in the packet.  There should be one
+     for every action.  */
+  p = &own_buf[5];
+  while (p)
+    {
+      n++;
+      p++;
+      p = strchr (p, ';');
+    }
+  /* Allocate room for one extra action, for the default remain-stopped
+     behavior; if no default action is in the list, we'll need the extra
+     slot.  */
+  resume_info = malloc ((n + 1) * sizeof (resume_info[0]));
+
+  default_action.thread = -1;
+  default_action.leave_stopped = 1;
+  default_action.step = 0;
+  default_action.sig = 0;
+
+  p = &own_buf[5];
+  i = 0;
+  while (*p)
+    {
+      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;
+         default_action = resume_info[i];
+
+         /* Note: we don't increment i here, we'll overwrite this entry
+            the next time through.  */
+       }
+      else if (p[0] == ':')
+       {
+         resume_info[i].thread = strtol (p + 1, &q, 16);
+         if (p == q)
+           goto err;
+         p = q;
+         if (p[0] != ';' && p[0] != 0)
+           goto err;
+
+         i++;
+       }
+    }
+
+  resume_info[i] = default_action;
+
+  /* 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);
+
+  free (resume_info);
+
+  *signal = mywait (status, 1);
+  prepare_resume_reply (own_buf, *status, *signal);
+  return;
+
+err:
+  /* No other way to report an error... */
+  strcpy (own_buf, "");
+  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;
+    }
+
+  if (strncmp (own_buf, "vCont?", 6) == 0)
+    {
+      strcpy (own_buf, "vCont;c;C;s;S");
+      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 +532,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 1c47a3aedb3b325a2d266c03e2f59fe6d396742a..aa0a44afd61a317feb50917e01800346b18de3d8 100644 (file)
 #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.
 
@@ -132,9 +146,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)