* linux-nat.c (linux_nat_filter_event): Minor comment reformatting.
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 5ff4bceadd11ebd150be35924f00c98d597e10e8..0679173764cf3f6593b3b930ef081d8f3f862f6e 100644 (file)
@@ -1,6 +1,6 @@
 /* GNU/Linux native-dependent code common to multiple platforms.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 #include "inf-loop.h"
 #include "event-loop.h"
 #include "event-top.h"
+#include <pwd.h>
+#include <sys/types.h>
+#include "gdb_dirent.h"
+#include "xml-support.h"
 
 #ifdef HAVE_PERSONALITY
 # include <sys/personality.h>
@@ -190,7 +194,8 @@ blocked.  */
 #endif
 
 #ifndef PTRACE_GETSIGINFO
-#define PTRACE_GETSIGINFO    0x4202
+# define PTRACE_GETSIGINFO    0x4202
+# define PTRACE_SETSIGINFO    0x4203
 #endif
 
 /* The single-threaded native GNU/Linux target_ops.  We save a pointer for
@@ -201,6 +206,13 @@ 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 method to call, if any, when the siginfo object needs to be
+   converted between the layout returned by ptrace, and the layout in
+   the architecture of the inferior.  */
+static int (*linux_nat_siginfo_fixup) (struct siginfo *,
+                                      gdb_byte *,
+                                      int);
+
 /* 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 *, 
@@ -316,7 +328,6 @@ static void linux_nat_async (void (*callback)
 static int linux_nat_async_mask (int mask);
 static int kill_lwp (int lwpid, int signo);
 
-static int send_sigint_callback (struct lwp_info *lp, void *data);
 static int stop_callback (struct lwp_info *lp, void *data);
 
 /* Captures the result of a successful waitpid call, along with the
@@ -333,8 +344,12 @@ struct waitpid_result
    in the async SIGCHLD handler.  */
 static struct waitpid_result *waitpid_queue = NULL;
 
+/* Similarly to `waitpid', but check the local event queue instead of
+   querying the kernel queue.  If PEEK, don't remove the event found
+   from the queue.  */
+
 static int
-queued_waitpid (int pid, int *status, int flags)
+queued_waitpid_1 (int pid, int *status, int flags, int peek)
 {
   struct waitpid_result *msg = waitpid_queue, *prev = NULL;
 
@@ -370,12 +385,6 @@ QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n",
     {
       int pid;
 
-      if (prev)
-       prev->next = msg->next;
-      else
-       waitpid_queue = msg->next;
-
-      msg->next = NULL;
       if (status)
        *status = msg->status;
       pid = msg->pid;
@@ -383,7 +392,17 @@ QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n",
       if (debug_linux_nat_async)
        fprintf_unfiltered (gdb_stdlog, "QWPID: pid(%d), status(%x)\n",
                            pid, msg->status);
-      xfree (msg);
+
+      if (!peek)
+       {
+         if (prev)
+           prev->next = msg->next;
+         else
+           waitpid_queue = msg->next;
+
+         msg->next = NULL;
+         xfree (msg);
+       }
 
       return pid;
     }
@@ -396,6 +415,14 @@ QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n",
   return -1;
 }
 
+/* Similarly to `waitpid', but check the local event queue.  */
+
+static int
+queued_waitpid (int pid, int *status, int flags)
+{
+  return queued_waitpid_1 (pid, status, flags, 0);
+}
+
 static void
 push_waitpid (int pid, int status, int options)
 {
@@ -711,9 +738,13 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       else
        {
          struct fork_info *fp;
+         struct inferior *parent_inf, *child_inf;
 
          /* Add process to GDB's tables.  */
-         add_inferior (child_pid);
+         child_inf = add_inferior (child_pid);
+
+         parent_inf = find_inferior_pid (GET_PID (last_ptid));
+         child_inf->attach_flag = parent_inf->attach_flag;
 
          /* Retain child fork in ptrace (stopped) state.  */
          fp = find_fork_pid (child_pid);
@@ -781,6 +812,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       struct thread_info *last_tp = find_thread_pid (last_ptid);
       struct thread_info *tp;
       char child_pid_spelling[40];
+      struct inferior *parent_inf, *child_inf;
 
       /* Copy user stepping state to the new inferior thread.  */
       struct breakpoint *step_resume_breakpoint = last_tp->step_resume_breakpoint;
@@ -807,6 +839,14 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
                            child_pid);
        }
 
+      /* Add the new inferior first, so that the target_detach below
+        doesn't unpush the target.  */
+
+      child_inf = add_inferior (child_pid);
+
+      parent_inf = find_inferior_pid (GET_PID (last_ptid));
+      child_inf->attach_flag = parent_inf->attach_flag;
+
       /* If we're vforking, we may want to hold on to the parent until
         the child exits or execs.  At exec time we can remove the old
         breakpoints from the parent and detach it; at exit time we
@@ -838,17 +878,18 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
          if (!fp)
            fp = add_fork (parent_pid);
          fork_save_infrun_state (fp, 0);
+
+         /* Also add an entry for the child fork.  */
+         fp = find_fork_pid (child_pid);
+         if (!fp)
+           fp = add_fork (child_pid);
+         fork_save_infrun_state (fp, 0);
        }
       else
        target_detach (NULL, 0);
 
       inferior_ptid = ptid_build (child_pid, child_pid, 0);
-      add_inferior (child_pid);
 
-      /* 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);
       check_for_thread_db ();
 
@@ -949,7 +990,7 @@ static struct sigaction sigchld_default_action;
 
 /* Prototypes for local functions.  */
 static int stop_wait_callback (struct lwp_info *lp, void *data);
-static int linux_nat_thread_alive (ptid_t ptid);
+static int linux_thread_alive (ptid_t ptid);
 static char *linux_child_pid_to_exec_file (int pid);
 static int cancel_breakpoint (struct lwp_info *lp);
 
@@ -1302,7 +1343,8 @@ lin_lwp_attach_lwp (ptid_t ptid)
 }
 
 static void
-linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
+linux_nat_create_inferior (struct target_ops *ops, 
+                          char *exec_file, char *allargs, char **env,
                           int from_tty)
 {
   int saved_async = 0;
@@ -1349,7 +1391,7 @@ linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
     }
 #endif /* HAVE_PERSONALITY */
 
-  linux_ops->to_create_inferior (exec_file, allargs, env, from_tty);
+  linux_ops->to_create_inferior (ops, exec_file, allargs, env, from_tty);
 
 #ifdef HAVE_PERSONALITY
   if (personality_set)
@@ -1367,7 +1409,7 @@ linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
 }
 
 static void
-linux_nat_attach (char *args, int from_tty)
+linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
 {
   struct lwp_info *lp;
   int status;
@@ -1375,7 +1417,7 @@ linux_nat_attach (char *args, int from_tty)
 
   /* FIXME: We should probably accept a list of process id's, and
      attach all of them.  */
-  linux_ops->to_attach (args, from_tty);
+  linux_ops->to_attach (ops, args, from_tty);
 
   if (!target_can_async_p ())
     {
@@ -1450,8 +1492,8 @@ get_pending_status (struct lwp_info *lp, int *status)
             queue.  */
          if (queued_waitpid (GET_LWP (lp->ptid), status, __WALL) != -1)
            {
-             if (WIFSTOPPED (status))
-               signo = target_signal_from_host (WSTOPSIG (status));
+             if (WIFSTOPPED (*status))
+               signo = target_signal_from_host (WSTOPSIG (*status));
 
              /* If not stopped, then the lwp is gone, no use in
                 resending a signal.  */
@@ -1556,7 +1598,7 @@ detach_callback (struct lwp_info *lp, void *data)
 }
 
 static void
-linux_nat_detach (char *args, int from_tty)
+linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
 {
   int pid;
   int status;
@@ -1595,12 +1637,24 @@ linux_nat_detach (char *args, int from_tty)
   /* Destroy LWP info; it's no longer valid.  */
   init_lwp_list ();
 
-  pid = GET_PID (inferior_ptid);
-  inferior_ptid = pid_to_ptid (pid);
-  linux_ops->to_detach (args, from_tty);
+  pid = ptid_get_pid (inferior_ptid);
 
   if (target_can_async_p ())
     drain_queued_events (pid);
+
+  if (forks_exist_p ())
+    {
+      /* Multi-fork case.  The current inferior_ptid is being detached
+        from, but there are other viable forks to debug.  Detach from
+        the current fork, and context-switch to the first
+        available.  */
+      linux_fork_detach (args, from_tty);
+
+      if (non_stop && target_can_async_p ())
+       target_async (inferior_event_handler, 0);
+    }
+  else
+    linux_ops->to_detach (ops, args, from_tty);
 }
 
 /* Resume LP.  */
@@ -1610,7 +1664,8 @@ resume_callback (struct lwp_info *lp, void *data)
 {
   if (lp->stopped && lp->status == 0)
     {
-      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+      linux_ops->to_resume (linux_ops,
+                           pid_to_ptid (GET_LWP (lp->ptid)),
                            0, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -1645,7 +1700,8 @@ resume_set_callback (struct lwp_info *lp, void *data)
 }
 
 static void
-linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
+linux_nat_resume (struct target_ops *ops,
+                 ptid_t ptid, int step, enum target_signal signo)
 {
   struct lwp_info *lp;
   int resume_all;
@@ -1756,7 +1812,7 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
   if (resume_all)
     iterate_over_lwps (resume_callback, NULL);
 
-  linux_ops->to_resume (ptid, step, signo);
+  linux_ops->to_resume (linux_ops, ptid, step, signo);
   memset (&lp->siginfo, 0, sizeof (lp->siginfo));
 
   if (debug_linux_nat)
@@ -2200,11 +2256,11 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                      /* There was no gdb breakpoint set at pc.  Put
                         the event back in the queue.  */
                      if (debug_linux_nat)
-                       fprintf_unfiltered (gdb_stdlog,
-                                           "SWC: kill %s, %s\n",
-                                           target_pid_to_str (lp->ptid),
-                                           status_to_str ((int) status));
-                     kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
+                       fprintf_unfiltered (gdb_stdlog, "\
+SWC: leaving SIGTRAP in local queue of %s\n", target_pid_to_str (lp->ptid));
+                     push_waitpid (GET_LWP (lp->ptid),
+                                   W_STOPCODE (SIGTRAP),
+                                   lp->cloned ? __WCLONE : 0);
                    }
                }
              else
@@ -2567,9 +2623,9 @@ linux_nat_filter_event (int lwpid, int status, int options)
   /* Check if the thread has exited.  */
   if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
     {
-      /* If this is the main thread, we must stop all threads and
-        verify if they are still alive.  This is because in the nptl
-        thread model, there is no signal issued for exiting LWPs
+      /* If this is the main thread, we must stop all threads and verify
+        if they are still alive.  This is because in the nptl thread model
+        on Linux 2.4, there is no signal issued for exiting LWPs
         other than the main thread.  We only get the main thread exit
         signal once all child threads have already exited.  If we
         stop all the threads and use the stop_wait_callback to check
@@ -2588,20 +2644,21 @@ linux_nat_filter_event (int lwpid, int status, int options)
                            "LLW: %s exited.\n",
                            target_pid_to_str (lp->ptid));
 
-      exit_lwp (lp);
-
-      /* If there is at least one more LWP, then the exit signal was
-        not the end of the debugged application and should be
-        ignored.  */
-      if (num_lwps > 0)
-       return NULL;
+      if (num_lwps > 1)
+       {
+        /* If there is at least one more LWP, then the exit signal
+           was not the end of the debugged application and should be
+           ignored.  */
+        exit_lwp (lp);
+        return NULL;
+       }
     }
 
   /* Check if the current LWP has previously exited.  In the nptl
      thread model, LWPs other than the main thread do not issue
      signals when they exit so we must check whenever the thread has
      stopped.  A similar check is made in stop_wait_callback().  */
-  if (num_lwps > 1 && !linux_nat_thread_alive (lp->ptid))
+  if (num_lwps > 1 && !linux_thread_alive (lp->ptid))
     {
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -2632,7 +2689,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
 
       registers_changed ();
 
-      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+      linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -2662,7 +2719,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
       lp->ignore_sigint = 0;
 
       registers_changed ();
-      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+      linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -2730,7 +2787,8 @@ local_event_queue_to_pipe (void)
 }
 
 static ptid_t
-linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+linux_nat_wait (struct target_ops *ops,
+               ptid_t ptid, struct target_waitstatus *ourstatus)
 {
   struct lwp_info *lp = NULL;
   int options = 0;
@@ -2830,7 +2888,7 @@ retry:
       /* Resume the thread.  It should halt immediately returning the
          pending SIGSTOP.  */
       registers_changed ();
-      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+      linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -2848,7 +2906,6 @@ retry:
     {
       /* Causes SIGINT to be passed on to the attached process.  */
       set_sigint_trap ();
-      set_sigio_trap ();
     }
 
   while (status == 0)
@@ -2917,10 +2974,7 @@ retry:
     }
 
   if (!target_can_async_p ())
-    {
-      clear_sigio_trap ();
-      clear_sigint_trap ();
-    }
+    clear_sigint_trap ();
 
   gdb_assert (lp);
 
@@ -2955,7 +3009,7 @@ retry:
             newly attached threads may cause an unwanted delay in
             getting them running.  */
          registers_changed ();
-         linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+         linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                                lp->step, signo);
          if (debug_linux_nat)
            fprintf_unfiltered (gdb_stdlog,
@@ -3114,7 +3168,7 @@ kill_wait_callback (struct lwp_info *lp, void *data)
 }
 
 static void
-linux_nat_kill (void)
+linux_nat_kill (struct target_ops *ops)
 {
   struct target_waitstatus last;
   ptid_t last_ptid;
@@ -3161,7 +3215,7 @@ linux_nat_kill (void)
 }
 
 static void
-linux_nat_mourn_inferior (void)
+linux_nat_mourn_inferior (struct target_ops *ops)
 {
   /* Destroy LWP info; it's no longer valid.  */
   init_lwp_list ();
@@ -3171,7 +3225,7 @@ linux_nat_mourn_inferior (void)
       /* Normal case, no other forks available.  */
       if (target_can_async_p ())
        linux_nat_async (NULL, 0);
-      linux_ops->to_mourn_inferior ();
+      linux_ops->to_mourn_inferior (ops);
     }
   else
     /* Multi-fork case.  The current inferior_ptid has exited, but
@@ -3180,15 +3234,98 @@ linux_nat_mourn_inferior (void)
     linux_fork_mourn_inferior ();
 }
 
+/* Convert a native/host siginfo object, into/from the siginfo in the
+   layout of the inferiors' architecture.  */
+
+static void
+siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction)
+{
+  int done = 0;
+
+  if (linux_nat_siginfo_fixup != NULL)
+    done = linux_nat_siginfo_fixup (siginfo, inf_siginfo, direction);
+
+  /* If there was no callback, or the callback didn't do anything,
+     then just do a straight memcpy.  */
+  if (!done)
+    {
+      if (direction == 1)
+       memcpy (siginfo, inf_siginfo, sizeof (struct siginfo));
+      else
+       memcpy (inf_siginfo, siginfo, sizeof (struct siginfo));
+    }
+}
+
+static LONGEST
+linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
+                    const char *annex, gdb_byte *readbuf,
+                   const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  struct lwp_info *lp;
+  LONGEST n;
+  int pid;
+  struct siginfo siginfo;
+  gdb_byte inf_siginfo[sizeof (struct siginfo)];
+
+  gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO);
+  gdb_assert (readbuf || writebuf);
+
+  pid = GET_LWP (inferior_ptid);
+  if (pid == 0)
+    pid = GET_PID (inferior_ptid);
+
+  if (offset > sizeof (siginfo))
+    return -1;
+
+  errno = 0;
+  ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+  if (errno != 0)
+    return -1;
+
+  /* When GDB is built as a 64-bit application, ptrace writes into
+     SIGINFO an object with 64-bit layout.  Since debugging a 32-bit
+     inferior with a 64-bit GDB should look the same as debugging it
+     with a 32-bit GDB, we need to convert it.  GDB core always sees
+     the converted layout, so any read/write will have to be done
+     post-conversion.  */
+  siginfo_fixup (&siginfo, inf_siginfo, 0);
+
+  if (offset + len > sizeof (siginfo))
+    len = sizeof (siginfo) - offset;
+
+  if (readbuf != NULL)
+    memcpy (readbuf, inf_siginfo + offset, len);
+  else
+    {
+      memcpy (inf_siginfo + offset, writebuf, len);
+
+      /* Convert back to ptrace layout before flushing it out.  */
+      siginfo_fixup (&siginfo, inf_siginfo, 1);
+
+      errno = 0;
+      ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+      if (errno != 0)
+       return -1;
+    }
+
+  return len;
+}
+
 static LONGEST
 linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
                        const char *annex, gdb_byte *readbuf,
                        const gdb_byte *writebuf,
                        ULONGEST offset, LONGEST len)
 {
-  struct cleanup *old_chain = save_inferior_ptid ();
+  struct cleanup *old_chain;
   LONGEST xfer;
 
+  if (object == TARGET_OBJECT_SIGNAL_INFO)
+    return linux_xfer_siginfo (ops, object, annex, readbuf, writebuf,
+                              offset, len);
+
+  old_chain = save_inferior_ptid ();
+
   if (is_lwp (inferior_ptid))
     inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid));
 
@@ -3200,7 +3337,7 @@ linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
 }
 
 static int
-linux_nat_thread_alive (ptid_t ptid)
+linux_thread_alive (ptid_t ptid)
 {
   int err;
 
@@ -3223,8 +3360,14 @@ linux_nat_thread_alive (ptid_t ptid)
   return 1;
 }
 
+static int
+linux_nat_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+  return linux_thread_alive (ptid);
+}
+
 static char *
-linux_nat_pid_to_str (ptid_t ptid)
+linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
 {
   static char buf[64];
 
@@ -3312,18 +3455,20 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
                                            unsigned long,
                                            int, int, int, void *), void *obfd)
 {
-  long long pid = PIDGET (inferior_ptid);
+  int pid = PIDGET (inferior_ptid);
   char mapsfilename[MAXPATHLEN];
   FILE *mapsfile;
   long long addr, endaddr, size, offset, inode;
   char permissions[8], device[8], filename[MAXPATHLEN];
   int read, write, exec;
   int ret;
+  struct cleanup *cleanup;
 
   /* Compose the filename for the /proc memory map, and open it.  */
-  sprintf (mapsfilename, "/proc/%lld/maps", pid);
+  sprintf (mapsfilename, "/proc/%d/maps", pid);
   if ((mapsfile = fopen (mapsfilename, "r")) == NULL)
     error (_("Could not open %s."), mapsfilename);
+  cleanup = make_cleanup_fclose (mapsfile);
 
   if (info_verbose)
     fprintf_filtered (gdb_stdout,
@@ -3356,7 +3501,7 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
         segment.  */
       func (addr, size, read, write, exec, obfd);
     }
-  fclose (mapsfile);
+  do_cleanups (cleanup);
   return 0;
 }
 
@@ -3573,7 +3718,9 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
 static void
 linux_nat_info_proc_cmd (char *args, int from_tty)
 {
-  long long pid = PIDGET (inferior_ptid);
+  /* A long is used for pid instead of an int to avoid a loss of precision
+     compiler warning from the output of strtoul.  */
+  long pid = PIDGET (inferior_ptid);
   FILE *procfile;
   char **argv = NULL;
   char buffer[MAXPATHLEN];
@@ -3591,10 +3738,8 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
   if (args)
     {
       /* Break up 'args' into an argv array.  */
-      if ((argv = buildargv (args)) == NULL)
-       nomem (0);
-      else
-       make_cleanup_freeargv (argv);
+      argv = gdb_buildargv (args);
+      make_cleanup_freeargv (argv);
     }
   while (argv != NULL && *argv != NULL)
     {
@@ -3639,26 +3784,29 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
   if (pid == 0)
     error (_("No current process: you must name one."));
 
-  sprintf (fname1, "/proc/%lld", pid);
+  sprintf (fname1, "/proc/%ld", pid);
   if (stat (fname1, &dummy) != 0)
     error (_("No /proc directory: '%s'"), fname1);
 
-  printf_filtered (_("process %lld\n"), pid);
+  printf_filtered (_("process %ld\n"), pid);
   if (cmdline_f || all)
     {
-      sprintf (fname1, "/proc/%lld/cmdline", pid);
+      sprintf (fname1, "/proc/%ld/cmdline", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
        {
-         fgets (buffer, sizeof (buffer), procfile);
-         printf_filtered ("cmdline = '%s'\n", buffer);
-         fclose (procfile);
+         struct cleanup *cleanup = make_cleanup_fclose (procfile);
+          if (fgets (buffer, sizeof (buffer), procfile))
+            printf_filtered ("cmdline = '%s'\n", buffer);
+          else
+            warning (_("unable to read '%s'"), fname1);
+         do_cleanups (cleanup);
        }
       else
        warning (_("unable to open /proc file '%s'"), fname1);
     }
   if (cwd_f || all)
     {
-      sprintf (fname1, "/proc/%lld/cwd", pid);
+      sprintf (fname1, "/proc/%ld/cwd", pid);
       memset (fname2, 0, sizeof (fname2));
       if (readlink (fname1, fname2, sizeof (fname2)) > 0)
        printf_filtered ("cwd = '%s'\n", fname2);
@@ -3667,7 +3815,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
     }
   if (exe_f || all)
     {
-      sprintf (fname1, "/proc/%lld/exe", pid);
+      sprintf (fname1, "/proc/%ld/exe", pid);
       memset (fname2, 0, sizeof (fname2));
       if (readlink (fname1, fname2, sizeof (fname2)) > 0)
        printf_filtered ("exe = '%s'\n", fname2);
@@ -3676,12 +3824,14 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
     }
   if (mappings_f || all)
     {
-      sprintf (fname1, "/proc/%lld/maps", pid);
+      sprintf (fname1, "/proc/%ld/maps", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
        {
          long long addr, endaddr, size, offset, inode;
          char permissions[8], device[8], filename[MAXPATHLEN];
+         struct cleanup *cleanup;
 
+         cleanup = make_cleanup_fclose (procfile);
          printf_filtered (_("Mapped address spaces:\n\n"));
          if (gdbarch_addr_bit (current_gdbarch) == 32)
            {
@@ -3729,31 +3879,33 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
                }
            }
 
-         fclose (procfile);
+         do_cleanups (cleanup);
        }
       else
        warning (_("unable to open /proc file '%s'"), fname1);
     }
   if (status_f || all)
     {
-      sprintf (fname1, "/proc/%lld/status", pid);
+      sprintf (fname1, "/proc/%ld/status", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
        {
+         struct cleanup *cleanup = make_cleanup_fclose (procfile);
          while (fgets (buffer, sizeof (buffer), procfile) != NULL)
            puts_filtered (buffer);
-         fclose (procfile);
+         do_cleanups (cleanup);
        }
       else
        warning (_("unable to open /proc file '%s'"), fname1);
     }
   if (stat_f || all)
     {
-      sprintf (fname1, "/proc/%lld/stat", pid);
+      sprintf (fname1, "/proc/%ld/stat", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
        {
          int itmp;
          char ctmp;
          long ltmp;
+         struct cleanup *cleanup = make_cleanup_fclose (procfile);
 
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("Process: %d\n"), itmp);
@@ -3837,7 +3989,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
          if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
            printf_filtered (_("wchan (system call): 0x%lx\n"), ltmp);
 #endif
-         fclose (procfile);
+         do_cleanups (cleanup);
        }
       else
        warning (_("unable to open /proc file '%s'"), fname1);
@@ -3939,6 +4091,7 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
   FILE *procfile;
   char buffer[MAXPATHLEN], fname[MAXPATHLEN];
   int signum;
+  struct cleanup *cleanup;
 
   sigemptyset (pending);
   sigemptyset (blocked);
@@ -3947,6 +4100,7 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
   procfile = fopen (fname, "r");
   if (procfile == NULL)
     error (_("Could not open %s"), fname);
+  cleanup = make_cleanup_fclose (procfile);
 
   while (fgets (buffer, MAXPATHLEN, procfile) != NULL)
     {
@@ -3968,7 +4122,114 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
        add_line_to_sigset (buffer + 8, ignored);
     }
 
-  fclose (procfile);
+  do_cleanups (cleanup);
+}
+
+static LONGEST
+linux_nat_xfer_osdata (struct target_ops *ops, enum target_object object,
+                    const char *annex, gdb_byte *readbuf,
+                    const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  /* We make the process list snapshot when the object starts to be
+     read.  */
+  static const char *buf;
+  static LONGEST len_avail = -1;
+  static struct obstack obstack;
+
+  DIR *dirp;
+
+  gdb_assert (object == TARGET_OBJECT_OSDATA);
+
+  if (strcmp (annex, "processes") != 0)
+    return 0;
+
+  gdb_assert (readbuf && !writebuf);
+
+  if (offset == 0)
+    {
+      if (len_avail != -1 && len_avail != 0)
+       obstack_free (&obstack, NULL);
+      len_avail = 0;
+      buf = NULL;
+      obstack_init (&obstack);
+      obstack_grow_str (&obstack, "<osdata type=\"processes\">\n");
+
+      dirp = opendir ("/proc");
+      if (dirp)
+       {
+         struct dirent *dp;
+         while ((dp = readdir (dirp)) != NULL)
+           {
+             struct stat statbuf;
+             char procentry[sizeof ("/proc/4294967295")];
+
+             if (!isdigit (dp->d_name[0])
+                 || NAMELEN (dp) > sizeof ("4294967295") - 1)
+               continue;
+
+             sprintf (procentry, "/proc/%s", dp->d_name);
+             if (stat (procentry, &statbuf) == 0
+                 && S_ISDIR (statbuf.st_mode))
+               {
+                 char *pathname;
+                 FILE *f;
+                 char cmd[MAXPATHLEN + 1];
+                 struct passwd *entry;
+
+                 pathname = xstrprintf ("/proc/%s/cmdline", dp->d_name);
+                 entry = getpwuid (statbuf.st_uid);
+
+                 if ((f = fopen (pathname, "r")) != NULL)
+                   {
+                     size_t len = fread (cmd, 1, sizeof (cmd) - 1, f);
+                     if (len > 0)
+                       {
+                         int i;
+                         for (i = 0; i < len; i++)
+                           if (cmd[i] == '\0')
+                             cmd[i] = ' ';
+                         cmd[len] = '\0';
+
+                         obstack_xml_printf (
+                          &obstack,
+                          "<item>"
+                          "<column name=\"pid\">%s</column>"
+                          "<column name=\"user\">%s</column>"
+                          "<column name=\"command\">%s</column>"
+                          "</item>",
+                          dp->d_name,
+                          entry ? entry->pw_name : "?",
+                          cmd);
+                       }
+                     fclose (f);
+                   }
+
+                 xfree (pathname);
+               }
+           }
+
+         closedir (dirp);
+       }
+
+      obstack_grow_str0 (&obstack, "</osdata>\n");
+      buf = obstack_finish (&obstack);
+      len_avail = strlen (buf);
+    }
+
+  if (offset >= len_avail)
+    {
+      /* Done.  Get rid of the obstack.  */
+      obstack_free (&obstack, NULL);
+      buf = NULL;
+      len_avail = 0;
+      return 0;
+    }
+
+  if (len > len_avail - offset)
+    len = len_avail - offset;
+  memcpy (readbuf, buf + offset, len);
+
+  return len;
 }
 
 static LONGEST
@@ -3982,6 +4243,10 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
     return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
                             offset, len);
 
+  if (object == TARGET_OBJECT_OSDATA)
+    return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf,
+                               offset, len);
+
   xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
                                  offset, len);
   if (xfer != 0)
@@ -4304,7 +4569,7 @@ linux_nat_terminal_inferior (void)
 
 /* target_terminal_ours implementation.  */
 
-void
+static void
 linux_nat_terminal_ours (void)
 {
   if (!target_is_async_p ())
@@ -4370,15 +4635,76 @@ linux_nat_async (void (*callback) (enum inferior_event_type event_type,
   return;
 }
 
+/* Stop an LWP, and push a TARGET_SIGNAL_0 stop status if no other
+   event came out.  */
+
 static int
-send_sigint_callback (struct lwp_info *lp, void *data)
+linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
 {
-  /* Use is_running instead of !lp->stopped, because the lwp may be
-     stopped due to an internal event, and we want to interrupt it in
-     that case too.  What we want is to check if the thread is stopped
-     from the point of view of the user.  */
-  if (is_running (lp->ptid))
-    kill_lwp (GET_LWP (lp->ptid), SIGINT);
+  ptid_t ptid = * (ptid_t *) data;
+
+  if (ptid_equal (lwp->ptid, ptid)
+      || ptid_equal (minus_one_ptid, ptid)
+      || (ptid_is_pid (ptid)
+         && ptid_get_pid (ptid) == ptid_get_pid (lwp->ptid)))
+    {
+      if (!lwp->stopped)
+       {
+         int pid, status;
+
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "LNSL: running -> suspending %s\n",
+                               target_pid_to_str (lwp->ptid));
+
+         /* Peek once, to check if we've already waited for this
+            LWP.  */
+         pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status,
+                                 lwp->cloned ? __WCLONE : 0,  1 /* peek */);
+
+         if (pid == -1)
+           {
+             ptid_t ptid = lwp->ptid;
+
+             stop_callback (lwp, NULL);
+             stop_wait_callback (lwp, NULL);
+
+             /* If the lwp exits while we try to stop it, there's
+                nothing else to do.  */
+             lwp = find_lwp_pid (ptid);
+             if (lwp == NULL)
+               return 0;
+
+             pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status,
+                                     lwp->cloned ? __WCLONE : 0,
+                                     1 /* peek */);
+           }
+
+         /* If we didn't collect any signal other than SIGSTOP while
+            stopping the LWP, push a SIGNAL_0 event.  In either case,
+            the event-loop will end up calling target_wait which will
+            collect these.  */
+         if (pid == -1)
+           push_waitpid (ptid_get_lwp (lwp->ptid), W_STOPCODE (0),
+                         lwp->cloned ? __WCLONE : 0);
+       }
+      else
+       {
+         /* Already known to be stopped; do nothing.  */
+
+         if (debug_linux_nat)
+           {
+             if (find_thread_pid (lwp->ptid)->stop_requested)
+               fprintf_unfiltered (gdb_stdlog, "\
+LNSL: already stopped/stop_requested %s\n",
+                                   target_pid_to_str (lwp->ptid));
+             else
+               fprintf_unfiltered (gdb_stdlog, "\
+LNSL: already stopped/no stop_requested yet %s\n",
+                                   target_pid_to_str (lwp->ptid));
+           }
+       }
+    }
   return 0;
 }
 
@@ -4387,13 +4713,9 @@ linux_nat_stop (ptid_t ptid)
 {
   if (non_stop)
     {
-      if (ptid_equal (ptid, minus_one_ptid))
-       iterate_over_lwps (send_sigint_callback, &ptid);
-      else
-       {
-         struct lwp_info *lp = find_lwp_pid (ptid);
-         send_sigint_callback (lp, NULL);
-       }
+      linux_nat_async_events (sigchld_sync);
+      iterate_over_lwps (linux_nat_stop_lwp, &ptid);
+      target_async (inferior_event_handler, 0);
     }
   else
     linux_ops->to_stop (ptid);
@@ -4440,10 +4762,6 @@ linux_nat_add_target (struct target_ops *t)
      also want to be used for single-threaded processes.  */
 
   add_target (t);
-
-  /* TODO: Eliminate this and have libthread_db use
-     find_target_beneath.  */
-  thread_db_init (t);
 }
 
 /* Register a method to call whenever a new thread is attached.  */
@@ -4456,6 +4774,19 @@ linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
   linux_nat_new_thread = new_thread;
 }
 
+/* Register a method that converts a siginfo object between the layout
+   that ptrace returns, and the layout in the architecture of the
+   inferior.  */
+void
+linux_nat_set_siginfo_fixup (struct target_ops *t,
+                            int (*siginfo_fixup) (struct siginfo *,
+                                                  gdb_byte *,
+                                                  int))
+{
+  /* Save the pointer.  */
+  linux_nat_siginfo_fixup = siginfo_fixup;
+}
+
 /* Return the saved siginfo associated with PTID.  */
 struct siginfo *
 linux_nat_get_siginfo (ptid_t ptid)
@@ -4479,6 +4810,9 @@ linux_nat_setup_async (void)
   fcntl (linux_nat_event_pipe[1], F_SETFL, O_NONBLOCK);
 }
 
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_linux_nat;
+
 void
 _initialize_linux_nat (void)
 {
This page took 0.036491 seconds and 4 git commands to generate.