gdbserver: don't pick a random thread if the current thread dies
[deliverable/binutils-gdb.git] / gdb / gdbserver / lynx-low.c
index 3dbffa5eb91260c95ea436e2ceb0e67c2a9fd0bc..ee4d0e8395853b7e902adee0e7ed60cf7697cf5d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2013 Free Software Foundation, Inc.
+/* Copyright (C) 2009-2015 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include <sys/types.h>
 #include "gdb_wait.h"
 #include <signal.h>
+#include "filestuff.h"
 
 int using_threads = 1;
 
+const struct target_desc *lynx_tdesc;
+
 /* Per-process private data.  */
 
 struct process_info_private
@@ -214,8 +217,9 @@ lynx_add_process (int pid, int attached)
   struct process_info *proc;
 
   proc = add_process (pid, attached);
-  proc->private = xcalloc (1, sizeof (*proc->private));
-  proc->private->last_wait_event_ptid = null_ptid;
+  proc->tdesc = lynx_tdesc;
+  proc->priv = xcalloc (1, sizeof (*proc->priv));
+  proc->priv->last_wait_event_ptid = null_ptid;
 
   return proc;
 }
@@ -237,6 +241,8 @@ lynx_create_inferior (char *program, char **allargs)
     {
       int pgrp;
 
+      close_most_fds ();
+
       /* Switch child to its own process group so that signals won't
          directly affect gdbserver. */
       pgrp = getpid();
@@ -256,6 +262,42 @@ lynx_create_inferior (char *program, char **allargs)
   return pid;
 }
 
+/* Assuming we've just attached to a running inferior whose pid is PID,
+   add all threads running in that process.  */
+
+static void
+lynx_add_threads_after_attach (int pid)
+{
+  /* Ugh!  There appears to be no way to get the list of threads
+     in the program we just attached to.  So get the list by calling
+     the "ps" command.  This is only needed now, as we will then
+     keep the thread list up to date thanks to thread creation and
+     exit notifications.  */
+  FILE *f;
+  char buf[256];
+  int thread_pid, thread_tid;
+
+  f = popen ("ps atx", "r");
+  if (f == NULL)
+    perror_with_name ("Cannot get thread list");
+
+  while (fgets (buf, sizeof (buf), f) != NULL)
+    if ((sscanf (buf, "%d %d", &thread_pid, &thread_tid) == 2
+        && thread_pid == pid))
+    {
+      ptid_t thread_ptid = lynx_ptid_build (pid, thread_tid);
+
+      if (!find_thread_ptid (thread_ptid))
+       {
+         lynx_debug ("New thread: (pid = %d, tid = %d)",
+                     pid, thread_tid);
+         add_thread (thread_ptid, NULL);
+       }
+    }
+
+  pclose (f);
+}
+
 /* Implement the attach target_ops method.  */
 
 static int
@@ -268,7 +310,7 @@ lynx_attach (unsigned long pid)
           strerror (errno), errno);
 
   lynx_add_process (pid, 1);
-  add_thread (ptid, NULL);
+  lynx_add_threads_after_attach (pid);
 
   return 0;
 }
@@ -278,10 +320,11 @@ lynx_attach (unsigned long pid)
 static void
 lynx_resume (struct thread_resume *resume_info, size_t n)
 {
-  /* FIXME: Assume for now that n == 1.  */
   ptid_t ptid = resume_info[0].thread;
-  const int request = (resume_info[0].kind == resume_step
-                       ? PTRACE_SINGLESTEP : PTRACE_CONT);
+  const int request
+    = (resume_info[0].kind == resume_step
+       ? (n == 1 ? PTRACE_SINGLESTEP_ONE : PTRACE_SINGLESTEP)
+       : PTRACE_CONT);
   const int signal = resume_info[0].sig;
 
   /* If given a minus_one_ptid, then try using the current_process'
@@ -291,14 +334,14 @@ lynx_resume (struct thread_resume *resume_info, size_t n)
      unexpected signals (Eg SIG61) when we resume the inferior
      using a different thread.  */
   if (ptid_equal (ptid, minus_one_ptid))
-    ptid = current_process()->private->last_wait_event_ptid;
+    ptid = current_process()->priv->last_wait_event_ptid;
 
   /* The ptid might still be minus_one_ptid; this can happen between
      the moment we create the inferior or attach to a process, and
      the moment we resume its execution for the first time.  It is
-     fine to use the current_inferior's ptid in those cases.  */
+     fine to use the current_thread's ptid in those cases.  */
   if (ptid_equal (ptid, minus_one_ptid))
-    ptid = thread_to_gdb_id (current_inferior);
+    ptid = thread_to_gdb_id (current_thread);
 
   regcache_invalidate ();
 
@@ -371,7 +414,7 @@ lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options)
   ptid_t new_ptid;
 
   if (ptid_equal (ptid, minus_one_ptid))
-    pid = lynx_ptid_get_pid (thread_to_gdb_id (current_inferior));
+    pid = lynx_ptid_get_pid (thread_to_gdb_id (current_thread));
   else
     pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
 
@@ -379,7 +422,7 @@ retry:
 
   ret = lynx_waitpid (pid, &wstat);
   new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid);
-  find_process_pid (ret)->private->last_wait_event_ptid = new_ptid;
+  find_process_pid (ret)->priv->last_wait_event_ptid = new_ptid;
 
   /* If this is a new thread, then add it now.  The reason why we do
      this here instead of when handling new-thread events is because
@@ -509,8 +552,8 @@ static void
 lynx_mourn (struct process_info *proc)
 {
   /* Free our private data.  */
-  free (proc->private);
-  proc->private = NULL;
+  free (proc->priv);
+  proc->priv = NULL;
 
   clear_inferiors ();
 }
@@ -540,7 +583,7 @@ static void
 lynx_fetch_registers (struct regcache *regcache, int regno)
 {
   struct lynx_regset_info *regset = lynx_target_regsets;
-  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+  ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
 
   lynx_debug ("lynx_fetch_registers (regno = %d)", regno);
 
@@ -565,7 +608,7 @@ static void
 lynx_store_registers (struct regcache *regcache, int regno)
 {
   struct lynx_regset_info *regset = lynx_target_regsets;
-  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+  ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
 
   lynx_debug ("lynx_store_registers (regno = %d)", regno);
 
@@ -601,7 +644,7 @@ lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
   int buf;
   const int xfer_size = sizeof (buf);
   CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
-  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+  ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
 
   while (addr < memaddr + len)
     {
@@ -634,7 +677,7 @@ lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
   int buf;
   const int xfer_size = sizeof (buf);
   CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
-  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+  ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
 
   while (addr < memaddr + len)
     {
@@ -646,11 +689,13 @@ lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
       if (addr + xfer_size > memaddr + len)
         truncate = addr + xfer_size - memaddr - len;
       if (skip > 0 || truncate > 0)
-        /* We need to read the memory at this address in order to preserve
-           the data that we are not overwriting.  */
-        lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
-        if (errno)
-          return errno;
+       {
+         /* We need to read the memory at this address in order to preserve
+            the data that we are not overwriting.  */
+         lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
+         if (errno)
+           return errno;
+       }
       memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip,
               xfer_size - skip - truncate);
       errno = 0;
@@ -668,7 +713,7 @@ lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
 static void
 lynx_request_interrupt (void)
 {
-  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+  ptid_t inferior_ptid = thread_to_gdb_id (get_first_thread ());
 
   kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
 }
@@ -677,6 +722,7 @@ lynx_request_interrupt (void)
 
 static struct target_ops lynx_target_ops = {
   lynx_create_inferior,
+  NULL,  /* arch_setup */
   lynx_attach,
   lynx_kill,
   lynx_detach,
@@ -694,8 +740,17 @@ static struct target_ops lynx_target_ops = {
   NULL,  /* look_up_symbols */
   lynx_request_interrupt,
   NULL,  /* read_auxv */
+  NULL,  /* supports_z_point_type */
   NULL,  /* insert_point */
   NULL,  /* remove_point */
+  NULL,  /* stopped_by_sw_breakpoint */
+  NULL,  /* supports_stopped_by_sw_breakpoint */
+  NULL,  /* stopped_by_hw_breakpoint */
+  NULL,  /* supports_stopped_by_hw_breakpoint */
+  /* Although lynx has hardware single step, still disable this
+     feature for lynx, because it is implemented in linux-low.c instead
+     of in generic code.  */
+  NULL,  /* supports_conditional_breakpoints */
   NULL,  /* stopped_by_watchpoint */
   NULL,  /* stopped_data_address */
   NULL,  /* read_offsets */
@@ -708,6 +763,9 @@ static struct target_ops lynx_target_ops = {
   NULL,  /* async */
   NULL,  /* start_non_stop */
   NULL,  /* supports_multi_process */
+  NULL,  /* supports_fork_events */
+  NULL,  /* supports_vfork_events */
+  NULL,  /* handle_new_gdb_connection */
   NULL,  /* handle_monitor_command */
 };
 
This page took 0.029368 seconds and 4 git commands to generate.