* linux-nat.c (linux_nat_new_thread): New variable.
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 90b8a3b84502e261963d48c450d7b28400944174..18c28006b021bc07379966aa04c9fbe7b8cece1b 100644 (file)
@@ -89,6 +89,9 @@
 static struct target_ops *linux_ops;
 static struct target_ops linux_ops_saved;
 
+/* The method to call, if any, when a new thread is attached.  */
+static void (*linux_nat_new_thread) (ptid_t);
+
 /* The saved to_xfer_partial method, inherited from inf-ptrace.c.
    Called by our to_xfer_partial.  */
 static LONGEST (*super_xfer_partial) (struct target_ops *, 
@@ -503,12 +506,13 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
          target_detach (NULL, 0);
        }
 
-      inferior_ptid = pid_to_ptid (child_pid);
+      inferior_ptid = ptid_build (child_pid, child_pid, 0);
 
       /* Reinstall ourselves, since we might have been removed in
         target_detach (which does other necessary cleanup).  */
 
       push_target (ops);
+      linux_nat_switch_fork (inferior_ptid);
 
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
@@ -573,7 +577,7 @@ linux_child_insert_exec_catchpoint (int pid)
      because the "zombies" stay around.  */
 
 /* List of known LWPs.  */
-static struct lwp_info *lwp_list;
+struct lwp_info *lwp_list;
 
 /* Number of LWPs in the list.  */
 static int num_lwps;
@@ -657,7 +661,8 @@ init_lwp_list (void)
 }
 
 /* Add the LWP specified by PID to the list.  Return a pointer to the
-   structure describing the new LWP.  */
+   structure describing the new LWP.  The LWP should already be stopped
+   (with an exception for the very first LWP).  */
 
 static struct lwp_info *
 add_lwp (ptid_t ptid)
@@ -678,6 +683,9 @@ add_lwp (ptid_t ptid)
   lwp_list = lp;
   ++num_lwps;
 
+  if (num_lwps > 1 && linux_nat_new_thread != NULL)
+    linux_nat_new_thread (ptid);
+
   return lp;
 }
 
@@ -884,6 +892,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
     {
       pid_t pid;
       int status;
+      int cloned = 0;
 
       if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
        {
@@ -897,9 +906,6 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
          return -1;
        }
 
-      if (lp == NULL)
-       lp = add_lwp (ptid);
-
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
                            "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n",
@@ -910,12 +916,16 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
        {
          /* Try again with __WCLONE to check cloned processes.  */
          pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE);
-         lp->cloned = 1;
+         cloned = 1;
        }
 
       gdb_assert (pid == GET_LWP (ptid)
                  && WIFSTOPPED (status) && WSTOPSIG (status));
 
+      if (lp == NULL)
+       lp = add_lwp (ptid);
+      lp->cloned = cloned;
+
       target_post_attach (pid);
 
       lp->stopped = 1;
@@ -953,15 +963,12 @@ linux_nat_attach (char *args, int from_tty)
   struct lwp_info *lp;
   pid_t pid;
   int status;
+  int cloned = 0;
 
   /* FIXME: We should probably accept a list of process id's, and
      attach all of them.  */
   linux_ops->to_attach (args, from_tty);
 
-  /* Add the initial process as the first LWP to the list.  */
-  inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
-  lp = add_lwp (inferior_ptid);
-
   /* Make sure the initial process is stopped.  The user-level threads
      layer might want to poke around in the inferior, and that won't
      work if things haven't stabilized yet.  */
@@ -972,12 +979,17 @@ linux_nat_attach (char *args, int from_tty)
 
       /* Try again with __WCLONE to check cloned processes.  */
       pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
-      lp->cloned = 1;
+      cloned = 1;
     }
 
   gdb_assert (pid == GET_PID (inferior_ptid)
              && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP);
 
+  /* Add the initial process as the first LWP to the list.  */
+  inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
+  lp = add_lwp (inferior_ptid);
+  lp->cloned = cloned;
+
   lp->stopped = 1;
 
   /* Fake the SIGSTOP that core GDB expects.  */
@@ -1077,8 +1089,6 @@ resume_callback (struct lwp_info *lp, void *data)
 {
   if (lp->stopped && lp->status == 0)
     {
-      struct thread_info *tp;
-
       linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
                            0, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -1087,6 +1097,7 @@ resume_callback (struct lwp_info *lp, void *data)
                            target_pid_to_str (lp->ptid));
       lp->stopped = 0;
       lp->step = 0;
+      memset (&lp->siginfo, 0, sizeof (lp->siginfo));
     }
 
   return 0;
@@ -1136,68 +1147,69 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
     ptid = inferior_ptid;
 
   lp = find_lwp_pid (ptid);
-  if (lp)
-    {
-      ptid = pid_to_ptid (GET_LWP (lp->ptid));
+  gdb_assert (lp != NULL);
 
-      /* Remember if we're stepping.  */
-      lp->step = step;
+  ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
-      /* Mark this LWP as resumed.  */
-      lp->resumed = 1;
+  /* Remember if we're stepping.  */
+  lp->step = step;
 
-      /* If we have a pending wait status for this thread, there is no
-        point in resuming the process.  But first make sure that
-        linux_nat_wait won't preemptively handle the event - we
-        should never take this short-circuit if we are going to
-        leave LP running, since we have skipped resuming all the
-        other threads.  This bit of code needs to be synchronized
-        with linux_nat_wait.  */
+  /* Mark this LWP as resumed.  */
+  lp->resumed = 1;
 
-      if (lp->status && WIFSTOPPED (lp->status))
-       {
-         int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
+  /* If we have a pending wait status for this thread, there is no
+     point in resuming the process.  But first make sure that
+     linux_nat_wait won't preemptively handle the event - we
+     should never take this short-circuit if we are going to
+     leave LP running, since we have skipped resuming all the
+     other threads.  This bit of code needs to be synchronized
+     with linux_nat_wait.  */
 
-         if (signal_stop_state (saved_signo) == 0
-             && signal_print_state (saved_signo) == 0
-             && signal_pass_state (saved_signo) == 1)
-           {
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLR: Not short circuiting for ignored "
-                                   "status 0x%x\n", lp->status);
-
-             /* FIXME: What should we do if we are supposed to continue
-                this thread with a signal?  */
-             gdb_assert (signo == TARGET_SIGNAL_0);
-             signo = saved_signo;
-             lp->status = 0;
-           }
-       }
+  if (lp->status && WIFSTOPPED (lp->status))
+    {
+      int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
 
-      if (lp->status)
+      if (signal_stop_state (saved_signo) == 0
+         && signal_print_state (saved_signo) == 0
+         && signal_pass_state (saved_signo) == 1)
        {
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "LLR: Not short circuiting for ignored "
+                               "status 0x%x\n", lp->status);
+
          /* FIXME: What should we do if we are supposed to continue
             this thread with a signal?  */
          gdb_assert (signo == TARGET_SIGNAL_0);
+         signo = saved_signo;
+         lp->status = 0;
+       }
+    }
 
-         if (debug_linux_nat)
-           fprintf_unfiltered (gdb_stdlog,
-                               "LLR: Short circuiting for status 0x%x\n",
-                               lp->status);
+  if (lp->status)
+    {
+      /* FIXME: What should we do if we are supposed to continue
+        this thread with a signal?  */
+      gdb_assert (signo == TARGET_SIGNAL_0);
 
-         return;
-       }
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLR: Short circuiting for status 0x%x\n",
+                           lp->status);
 
-      /* Mark LWP as not stopped to prevent it from being continued by
-         resume_callback.  */
-      lp->stopped = 0;
+      return;
     }
 
+  /* Mark LWP as not stopped to prevent it from being continued by
+     resume_callback.  */
+  lp->stopped = 0;
+
   if (resume_all)
     iterate_over_lwps (resume_callback, NULL);
 
   linux_ops->to_resume (ptid, step, signo);
+  memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
                        "LLR: %s %s, %s (resume event thread)\n",
@@ -1416,6 +1428,22 @@ wait_lwp (struct lwp_info *lp)
   return status;
 }
 
+/* Save the most recent siginfo for LP.  This is currently only called
+   for SIGTRAP; some ports use the si_addr field for
+   target_stopped_data_address.  In the future, it may also be used to
+   restore the siginfo of requeued signals.  */
+
+static void
+save_siginfo (struct lwp_info *lp)
+{
+  errno = 0;
+  ptrace (PTRACE_GETSIGINFO, GET_LWP (lp->ptid),
+         (PTRACE_TYPE_ARG3) 0, &lp->siginfo);
+
+  if (errno != 0)
+    memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+}
+
 /* Send a SIGSTOP to LP.  */
 
 static int
@@ -1501,6 +1529,9 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                 user will delete or disable the breakpoint, but the
                 thread will have already tripped on it.  */
 
+             /* Save the trap's siginfo in case we need it later.  */
+             save_siginfo (lp);
+
              /* Now resume this LWP and get the SIGSTOP event. */
              errno = 0;
              ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
@@ -2058,6 +2089,10 @@ retry:
                                 target_pid_to_str (lp->ptid));
            }
 
+         /* Save the trap's siginfo in case we need it later.  */
+         if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
+           save_siginfo (lp);
+
          /* Handle GNU/Linux's extended waitstatus for trace events.  */
          if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
            {
@@ -3250,6 +3285,27 @@ linux_nat_add_target (struct target_ops *t)
   thread_db_init (t);
 }
 
+/* Register a method to call whenever a new thread is attached.  */
+void
+linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
+{
+  /* Save the pointer.  We only support a single registered instance
+     of the GNU/Linux native target, so we do not need to map this to
+     T.  */
+  linux_nat_new_thread = new_thread;
+}
+
+/* Return the saved siginfo associated with PTID.  */
+struct siginfo *
+linux_nat_get_siginfo (ptid_t ptid)
+{
+  struct lwp_info *lp = find_lwp_pid (ptid);
+
+  gdb_assert (lp != NULL);
+
+  return &lp->siginfo;
+}
+
 void
 _initialize_linux_nat (void)
 {
This page took 0.030268 seconds and 4 git commands to generate.