gdb
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index e467e9a65c1733b66f37580f700d9dee3eaa6c4d..641a619727cce8ba78d616294c9367f38751685d 100644 (file)
@@ -30,6 +30,7 @@
 #endif
 #include <sys/ptrace.h>
 #include "linux-nat.h"
+#include "linux-ptrace.h"
 #include "linux-fork.h"
 #include "gdbthread.h"
 #include "gdbcmd.h"
 #include "inf-ptrace.h"
 #include "auxv.h"
 #include <sys/param.h>         /* for MAXPATHLEN */
-#include <sys/procfs.h>                /* for elf_gregset etc. */
+#include <sys/procfs.h>                /* for elf_gregset etc.  */
 #include "elf-bfd.h"           /* for elfcore_write_* */
 #include "gregset.h"           /* for gregset */
 #include "gdbcore.h"           /* for get_exec_file */
 #include <ctype.h>             /* for isdigit */
-#include "gdbthread.h"         /* for struct thread_info etc. */
+#include "gdbthread.h"         /* for struct thread_info etc.  */
 #include "gdb_stat.h"          /* for struct stat */
 #include <fcntl.h>             /* for O_RDONLY */
 #include "inf-loop.h"
@@ -68,7 +69,7 @@
 # endif
 #endif /* HAVE_PERSONALITY */
 
-/* This comment documents high-level logic of this file. 
+/* This comment documents high-level logic of this file.
 
 Waiting for events in sync mode
 ===============================
@@ -76,12 +77,12 @@ Waiting for events in sync mode
 When waiting for an event in a specific thread, we just use waitpid, passing
 the specific pid, and not passing WNOHANG.
 
-When waiting for an event in all threads, waitpid is not quite good. Prior to
+When waiting for an event in all threads, waitpid is not quite good.  Prior to
 version 2.4, Linux can either wait for event in main thread, or in secondary
-threads. (2.4 has the __WALL flag).  So, if we use blocking waitpid, we might
+threads.  (2.4 has the __WALL flag).  So, if we use blocking waitpid, we might
 miss an event.  The solution is to use non-blocking waitpid, together with
 sigsuspend.  First, we use non-blocking waitpid to get an event in the main 
-process, if any. Second, we use non-blocking waitpid with the __WCLONED
+process, if any.  Second, we use non-blocking waitpid with the __WCLONED
 flag to check for events in cloned processes.  If nothing is found, we use
 sigsuspend to wait for SIGCHLD.  When SIGCHLD arrives, it means something
 happened to a child process -- and SIGCHLD will be delivered both for events
@@ -90,7 +91,7 @@ an event, we get back to calling nonblocking waitpid with and without
 __WCLONED.
 
 Note that SIGCHLD should be blocked between waitpid and sigsuspend calls,
-so that we don't miss a signal. If SIGCHLD arrives in between, when it's
+so that we don't miss a signal.  If SIGCHLD arrives in between, when it's
 blocked, the signal becomes pending and sigsuspend immediately
 notices it and returns.
 
@@ -160,49 +161,11 @@ blocked.  */
 #define O_LARGEFILE 0
 #endif
 
-/* If the system headers did not provide the constants, hard-code the normal
-   values.  */
-#ifndef PTRACE_EVENT_FORK
-
-#define PTRACE_SETOPTIONS      0x4200
-#define PTRACE_GETEVENTMSG     0x4201
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD  0x00000001
-#define PTRACE_O_TRACEFORK     0x00000002
-#define PTRACE_O_TRACEVFORK    0x00000004
-#define PTRACE_O_TRACECLONE    0x00000008
-#define PTRACE_O_TRACEEXEC     0x00000010
-#define PTRACE_O_TRACEVFORKDONE        0x00000020
-#define PTRACE_O_TRACEEXIT     0x00000040
-
-/* Wait extended result codes for the above trace options.  */
-#define PTRACE_EVENT_FORK      1
-#define PTRACE_EVENT_VFORK     2
-#define PTRACE_EVENT_CLONE     3
-#define PTRACE_EVENT_EXEC      4
-#define PTRACE_EVENT_VFORK_DONE        5
-#define PTRACE_EVENT_EXIT      6
-
-#endif /* PTRACE_EVENT_FORK */
-
 /* Unlike other extended result codes, WSTOPSIG (status) on
    PTRACE_O_TRACESYSGOOD syscall events doesn't return SIGTRAP, but
    instead SIGTRAP with bit 7 set.  */
 #define SYSCALL_SIGTRAP (SIGTRAP | 0x80)
 
-/* We can't always assume that this flag is available, but all systems
-   with the ptrace event handlers also have __WALL, so it's safe to use
-   here.  */
-#ifndef __WALL
-#define __WALL          0x40000000 /* Wait for any child.  */
-#endif
-
-#ifndef PTRACE_GETSIGINFO
-# define PTRACE_GETSIGINFO    0x4202
-# define PTRACE_SETSIGINFO    0x4203
-#endif
-
 /* The single-threaded native GNU/Linux target_ops.  We save a pointer for
    the use of the multi-threaded target.  */
 static struct target_ops *linux_ops;
@@ -297,7 +260,7 @@ static int linux_supports_tracesysgood_flag = -1;
 
 static int linux_supports_tracevforkdone_flag = -1;
 
-/* Async mode support */
+/* Async mode support */
 
 /* Zero if the async mode, although enabled, is masked, which means
    linux_nat_wait should behave as if async mode was off.  */
@@ -686,12 +649,11 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
         the parent stays blocked.  If we're telling the parent to run
         in the foreground, the user will not be able to ctrl-c to get
         back the terminal, effectively hanging the debug session.  */
-      fprintf_filtered (gdb_stderr,
-                       _("Can not resume the parent process "
-                         "over vfork in the foreground while\n"
-                         "holding the child stopped.  "
-                         "Try \"set detach-on-fork\" or "
-                         "\"set schedule-multiple\".\n"));
+      fprintf_filtered (gdb_stderr, _("\
+Can not resume the parent process over vfork in the foreground while\n\
+holding the child stopped.  Try \"set detach-on-fork\" or \
+\"set schedule-multiple\".\n"));
+      /* FIXME output string > 80 columns.  */
       return 1;
     }
 
@@ -699,7 +661,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
     {
       struct lwp_info *child_lp = NULL;
 
-      /* We're already attached to the parent, by default. */
+      /* We're already attached to the parent, by default.  */
 
       /* Detach new forked process?  */
       if (detach_fork)
@@ -975,36 +937,52 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
 }
 
 \f
-static void
+static int
 linux_child_insert_fork_catchpoint (int pid)
 {
-  if (! linux_supports_tracefork (pid))
-    error (_("Your system does not support fork catchpoints."));
+  return !linux_supports_tracefork (pid);
 }
 
-static void
+static int
+linux_child_remove_fork_catchpoint (int pid)
+{
+  return 0;
+}
+
+static int
 linux_child_insert_vfork_catchpoint (int pid)
 {
-  if (!linux_supports_tracefork (pid))
-    error (_("Your system does not support vfork catchpoints."));
+  return !linux_supports_tracefork (pid);
 }
 
-static void
+static int
+linux_child_remove_vfork_catchpoint (int pid)
+{
+  return 0;
+}
+
+static int
 linux_child_insert_exec_catchpoint (int pid)
 {
-  if (!linux_supports_tracefork (pid))
-    error (_("Your system does not support exec catchpoints."));
+  return !linux_supports_tracefork (pid);
+}
+
+static int
+linux_child_remove_exec_catchpoint (int pid)
+{
+  return 0;
 }
 
 static int
 linux_child_set_syscall_catchpoint (int pid, int needed, int any_count,
                                    int table_size, int *table)
 {
-  if (! linux_supports_tracesysgood (pid))
-    error (_("Your system does not support syscall catchpoints."));
+  if (!linux_supports_tracesysgood (pid))
+    return 1;
+
   /* On GNU/Linux, we ignore the arguments.  It means that we only
      enable the syscall catchpoints, but do not disable them.
-     
+
      Also, we do not use the `table' information because we do not
      filter system calls here.  We let GDB do the logic for us.  */
   return 0;
@@ -1081,6 +1059,26 @@ restore_child_signals_mask (sigset_t *prev_mask)
 {
   sigprocmask (SIG_SETMASK, prev_mask, NULL);
 }
+
+/* Mask of signals to pass directly to the inferior.  */
+static sigset_t pass_mask;
+
+/* Update signals to pass to the inferior.  */
+static void
+linux_nat_pass_signals (int numsigs, unsigned char *pass_signals)
+{
+  int signo;
+
+  sigemptyset (&pass_mask);
+
+  for (signo = 1; signo < NSIG; signo++)
+    {
+      int target_signo = target_signal_from_host (signo);
+      if (target_signo < numsigs && pass_signals[target_signo])
+        sigaddset (&pass_mask, signo);
+    }
+}
+
 \f
 
 /* Prototypes for local functions.  */
@@ -1478,7 +1476,10 @@ lin_lwp_attach_lwp (ptid_t ptid)
 
       status = linux_nat_post_attach_wait (ptid, 0, &cloned, &signalled);
       if (!WIFSTOPPED (status))
-       return -1;
+       {
+         restore_child_signals_mask (&prev_mask);
+         return -1;
+       }
 
       lp = add_lwp (ptid);
       lp->stopped = 1;
@@ -1546,6 +1547,9 @@ linux_nat_create_inferior (struct target_ops *ops,
     }
 #endif /* HAVE_PERSONALITY */
 
+  /* Make sure we report all signals during startup.  */
+  linux_nat_pass_signals (0, NULL);
+
   linux_ops->to_create_inferior (ops, exec_file, allargs, env, from_tty);
 
 #ifdef HAVE_PERSONALITY
@@ -1567,6 +1571,9 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
   int status;
   ptid_t ptid;
 
+  /* Make sure we report all signals during attach.  */
+  linux_nat_pass_signals (0, NULL);
+
   linux_ops->to_attach (ops, args, from_tty);
 
   /* The ptrace base target adds the main thread with (pid,0,0)
@@ -1925,19 +1932,9 @@ linux_nat_resume (struct target_ops *ops,
 
   if (lp->status && WIFSTOPPED (lp->status))
     {
-      enum target_signal saved_signo;
-      struct inferior *inf;
-
-      inf = find_inferior_pid (ptid_get_pid (lp->ptid));
-      gdb_assert (inf);
-      saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
-
-      /* Defer to common code if we're gaining control of the
-        inferior.  */
-      if (inf->control.stop_soon == NO_STOP_QUIETLY
-         && signal_stop_state (saved_signo) == 0
-         && signal_print_state (saved_signo) == 0
-         && signal_pass_state (saved_signo) == 1)
+      if (!lp->step
+         && WSTOPSIG (lp->status)
+         && sigismember (&pass_mask, WSTOPSIG (lp->status)))
        {
          if (debug_linux_nat)
            fprintf_unfiltered (gdb_stdlog,
@@ -1947,7 +1944,7 @@ linux_nat_resume (struct target_ops *ops,
          /* 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;
+         signo = target_signal_from_host (WSTOPSIG (lp->status));
          lp->status = 0;
        }
     }
@@ -2201,8 +2198,6 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
       if (event == PTRACE_EVENT_FORK
          && linux_fork_checkpointing_p (GET_PID (lp->ptid)))
        {
-         struct fork_info *fp;
-
          /* Handle checkpointing by linux-fork.c here as a special
             case.  We don't want the follow-fork-mode or 'catch fork'
             to interfere with this.  */
@@ -2212,9 +2207,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
          detach_breakpoints (new_pid);
 
          /* Retain child fork in ptrace (stopped) state.  */
-         fp = find_fork_pid (new_pid);
-         if (!fp)
-           fp = add_fork (new_pid);
+         if (!find_fork_pid (new_pid))
+           add_fork (new_pid);
 
          /* Report as spurious, so that infrun doesn't want to follow
             this fork.  We're actually doing an infcall in
@@ -2727,7 +2721,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
 
              save_sigtrap (lp);
 
-             /* Now resume this LWP and get the SIGSTOP event. */
+             /* Now resume this LWP and get the SIGSTOP event.  */
              errno = 0;
              ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
              if (debug_linux_nat)
@@ -2742,12 +2736,12 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                                      target_pid_to_str (lp->ptid));
                }
              /* Hold this event/waitstatus while we check to see if
-                there are any more (we still want to get that SIGSTOP). */
+                there are any more (we still want to get that SIGSTOP).  */
              stop_wait_callback (lp, NULL);
 
              /* Hold the SIGTRAP for handling by linux_nat_wait.  If
                 there's another event, throw it back into the
-                queue. */
+                queue.  */
              if (lp->status)
                {
                  if (debug_linux_nat)
@@ -2758,14 +2752,14 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                  kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
                }
 
-             /* Save the sigtrap event. */
+             /* Save the sigtrap event.  */
              lp->status = status;
              return 0;
            }
          else
            {
              /* The thread was stopped with a signal other than
-                SIGSTOP, and didn't accidentally trip a breakpoint. */
+                SIGSTOP, and didn't accidentally trip a breakpoint.  */
 
              if (debug_linux_nat)
                {
@@ -2774,7 +2768,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                                      status_to_str ((int) status),
                                      target_pid_to_str (lp->ptid));
                }
-             /* Now resume this LWP and get the SIGSTOP event. */
+             /* Now resume this LWP and get the SIGSTOP event.  */
              errno = 0;
              ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
              if (debug_linux_nat)
@@ -2784,7 +2778,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                                    errno ? safe_strerror (errno) : "OK");
 
              /* Hold this event/waitstatus while we check to see if
-                there are any more (we still want to get that SIGSTOP). */
+                there are any more (we still want to get that SIGSTOP).  */
              stop_wait_callback (lp, NULL);
 
              /* If the lp->status field is still empty, use it to
@@ -2831,7 +2825,7 @@ status_callback (struct lwp_info *lp, void *data)
   if (lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
     {
       /* A ptrace event, like PTRACE_FORK|VFORK|EXEC, syscall event,
-        or a pending process exit.  Note that `W_EXITCODE(0,0) ==
+        or a pending process exit.  Note that `W_EXITCODE(0,0) ==
         0', so a clean process exit can not be stored pending in
         lp->status, it is indistinguishable from
         no-pending-status.  */
@@ -2888,7 +2882,7 @@ select_event_lwp_callback (struct lwp_info *lp, void *data)
 
   gdb_assert (selector != NULL);
 
-  /* Select only resumed LWPs that have a SIGTRAP event pending. */
+  /* Select only resumed LWPs that have a SIGTRAP event pending.  */
   if (lp->resumed && linux_nat_lp_status_is_event (lp))
     if ((*selector)-- == 0)
       return 1;
@@ -3066,8 +3060,8 @@ linux_nat_filter_event (int lwpid, int status, int options)
     }
 
   /* Make sure we don't report an event for the exit of an LWP not in
-     our list, i.e.  not part of the current process.  This can happen
-     if we detach from a program we original forked and then it
+     our list, i.e. not part of the current process.  This can happen
+     if we detach from a program we originally forked and then it
      exits.  */
   if (!WIFSTOPPED (status) && !lp)
     return NULL;
@@ -3596,20 +3590,11 @@ retry:
   if (WIFSTOPPED (status))
     {
       enum target_signal signo = target_signal_from_host (WSTOPSIG (status));
-      struct inferior *inf;
 
-      inf = find_inferior_pid (ptid_get_pid (lp->ptid));
-      gdb_assert (inf);
-
-      /* Defer to common code if we get a signal while
-        single-stepping, since that may need special care, e.g. to
-        skip the signal handler, or, if we're gaining control of the
-        inferior.  */
+      /* When using hardware single-step, we need to report every signal.
+        Otherwise, signals in pass_mask may be short-circuited.  */
       if (!lp->step
-         && inf->control.stop_soon == NO_STOP_QUIETLY
-         && signal_stop_state (signo) == 0
-         && signal_print_state (signo) == 0
-         && signal_pass_state (signo) == 1)
+         && WSTOPSIG (status) && sigismember (&pass_mask, WSTOPSIG (status)))
        {
          /* FIMXE: kettenis/2001-06-06: Should we resume all threads
             here?  It is not clear we should.  GDB may not expect
@@ -4038,7 +4023,7 @@ linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
 static int
 linux_thread_alive (ptid_t ptid)
 {
-  int err;
+  int err, tmp_errno;
 
   gdb_assert (is_lwp (ptid));
 
@@ -4046,12 +4031,12 @@ linux_thread_alive (ptid_t ptid)
      running thread errors out claiming that the thread doesn't
      exist.  */
   err = kill_lwp (GET_LWP (ptid), 0);
-
+  tmp_errno = errno;
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
                        "LLTA: KILL(SIG0) %s (%s)\n",
                        target_pid_to_str (ptid),
-                       err ? safe_strerror (err) : "OK");
+                       err ? safe_strerror (tmp_errno) : "OK");
 
   if (err != 0)
     return 0;
@@ -4081,6 +4066,43 @@ linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
   return normal_pid_to_str (ptid);
 }
 
+static char *
+linux_nat_thread_name (struct thread_info *thr)
+{
+  int pid = ptid_get_pid (thr->ptid);
+  long lwp = ptid_get_lwp (thr->ptid);
+#define FORMAT "/proc/%d/task/%ld/comm"
+  char buf[sizeof (FORMAT) + 30];
+  FILE *comm_file;
+  char *result = NULL;
+
+  snprintf (buf, sizeof (buf), FORMAT, pid, lwp);
+  comm_file = fopen (buf, "r");
+  if (comm_file)
+    {
+      /* Not exported by the kernel, so we define it here.  */
+#define COMM_LEN 16
+      static char line[COMM_LEN + 1];
+
+      if (fgets (line, sizeof (line), comm_file))
+       {
+         char *nl = strchr (line, '\n');
+
+         if (nl)
+           *nl = '\0';
+         if (*line != '\0')
+           result = line;
+       }
+
+      fclose (comm_file);
+    }
+
+#undef COMM_LEN
+#undef FORMAT
+
+  return result;
+}
+
 /* Accepts an integer PID; Returns a string representing a file that
    can be opened to get the symbols for the child process.  */
 
@@ -4460,7 +4482,7 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
 
   if (get_exec_file (0))
     {
-      strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
+      strncpy (fname, lbasename (get_exec_file (0)), sizeof (fname));
       strncpy (psargs, get_exec_file (0), sizeof (psargs));
       if (get_inferior_args ())
        {
@@ -4570,7 +4592,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
        }
       else
        {
-         /* [...] (future options here) */
+         /* [...] (future options here) */
        }
       argv++;
     }
@@ -4770,9 +4792,9 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
            printf_filtered (_("Start of stack: 0x%lx\n"), ltmp);
 #if 0  /* Don't know how architecture-dependent the rest is...
           Anyway the signal bitmap info is available from "status".  */
-         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch?  */
            printf_filtered (_("Kernel stack pointer: 0x%lx\n"), ltmp);
-         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch?  */
            printf_filtered (_("Kernel instr pointer: 0x%lx\n"), ltmp);
          if (fscanf (procfile, "%ld ", &ltmp) > 0)
            printf_filtered (_("Pending signals bitmap: 0x%lx\n"), ltmp);
@@ -4782,7 +4804,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
            printf_filtered (_("Ignored signals bitmap: 0x%lx\n"), ltmp);
          if (fscanf (procfile, "%ld ", &ltmp) > 0)
            printf_filtered (_("Catched signals bitmap: 0x%lx\n"), ltmp);
-         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch?  */
            printf_filtered (_("wchan (system call): 0x%lx\n"), ltmp);
 #endif
          do_cleanups (cleanup);
@@ -5111,16 +5133,16 @@ linux_nat_xfer_osdata (struct target_ops *ops, enum target_object object,
 
                  if ((f = fopen (pathname, "r")) != NULL)
                    {
-                     size_t len = fread (cmd, 1, sizeof (cmd) - 1, f);
+                     size_t length = fread (cmd, 1, sizeof (cmd) - 1, f);
 
-                     if (len > 0)
+                     if (length > 0)
                        {
                          int i;
 
-                         for (i = 0; i < len; i++)
+                         for (i = 0; i < length; i++)
                            if (cmd[i] == '\0')
                              cmd[i] = ' ';
-                         cmd[len] = '\0';
+                         cmd[length] = '\0';
 
                          obstack_xml_printf (
                            &obstack,
@@ -5213,8 +5235,11 @@ static void
 linux_target_install_ops (struct target_ops *t)
 {
   t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint;
+  t->to_remove_fork_catchpoint = linux_child_remove_fork_catchpoint;
   t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint;
+  t->to_remove_vfork_catchpoint = linux_child_remove_vfork_catchpoint;
   t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint;
+  t->to_remove_exec_catchpoint = linux_child_remove_exec_catchpoint;
   t->to_set_syscall_catchpoint = linux_child_set_syscall_catchpoint;
   t->to_pid_to_exec_file = linux_child_pid_to_exec_file;
   t->to_post_startup_inferior = linux_child_post_startup_inferior;
@@ -5681,11 +5706,13 @@ linux_nat_add_target (struct target_ops *t)
   t->to_detach = linux_nat_detach;
   t->to_resume = linux_nat_resume;
   t->to_wait = linux_nat_wait;
+  t->to_pass_signals = linux_nat_pass_signals;
   t->to_xfer_partial = linux_nat_xfer_partial;
   t->to_kill = linux_nat_kill;
   t->to_mourn_inferior = linux_nat_mourn_inferior;
   t->to_thread_alive = linux_nat_thread_alive;
   t->to_pid_to_str = linux_nat_pid_to_str;
+  t->to_thread_name = linux_nat_thread_name;
   t->to_has_thread_control = tc_schedlock;
   t->to_thread_address_space = linux_nat_thread_address_space;
   t->to_stopped_by_watchpoint = linux_nat_stopped_by_watchpoint;
This page took 0.038164 seconds and 4 git commands to generate.