[GDB/Linux] Avoid stale errno
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 3f6e5ea73195c9c96635cc974e17f298cc8f2de9..c738abf9f3e7c13e61edb2a10498bc48acbd3d2c 100644 (file)
@@ -32,8 +32,8 @@
 #endif
 #include <sys/ptrace.h>
 #include "linux-nat.h"
-#include "linux-ptrace.h"
-#include "linux-procfs.h"
+#include "nat/linux-ptrace.h"
+#include "nat/linux-procfs.h"
 #include "linux-fork.h"
 #include "gdbthread.h"
 #include "gdbcmd.h"
@@ -59,7 +59,7 @@
 #include "terminal.h"
 #include <sys/vfs.h>
 #include "solib.h"
-#include "linux-osdata.h"
+#include "nat/linux-osdata.h"
 #include "linux-tdep.h"
 #include "symfile.h"
 #include "agent.h"
@@ -414,6 +414,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
       if (detach_fork)
        {
          struct cleanup *old_chain;
+         int status = W_STOPCODE (0);
 
          /* Before detaching from the child, remove all breakpoints
             from it.  If we forked, then this has already been taken
@@ -447,7 +448,35 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 
          if (linux_nat_prepare_to_resume != NULL)
            linux_nat_prepare_to_resume (child_lp);
-         ptrace (PTRACE_DETACH, child_pid, 0, 0);
+
+         /* When debugging an inferior in an architecture that supports
+            hardware single stepping on a kernel without commit
+            6580807da14c423f0d0a708108e6df6ebc8bc83d, the vfork child
+            process starts with the TIF_SINGLESTEP/X86_EFLAGS_TF bits
+            set if the parent process had them set.
+            To work around this, single step the child process
+            once before detaching to clear the flags.  */
+
+         if (!gdbarch_software_single_step_p (target_thread_architecture
+                                                  (child_lp->ptid)))
+           {
+             linux_disable_event_reporting (child_pid);
+             if (ptrace (PTRACE_SINGLESTEP, child_pid, 0, 0) < 0)
+               perror_with_name (_("Couldn't do single step"));
+             if (my_waitpid (child_pid, &status, 0) < 0)
+               perror_with_name (_("Couldn't wait vfork process"));
+           }
+
+         if (WIFSTOPPED (status))
+           {
+             int signo;
+
+             signo = WSTOPSIG (status);
+             if (signo != 0
+                 && !signal_pass_state (gdb_signal_from_host (signo)))
+               signo = 0;
+             ptrace (PTRACE_DETACH, child_pid, 0, signo);
+           }
 
          do_cleanups (old_chain);
        }
@@ -1301,7 +1330,7 @@ linux_nat_create_inferior (struct target_ops *ops,
 }
 
 static void
-linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
+linux_nat_attach (struct target_ops *ops, const char *args, int from_tty)
 {
   struct lwp_info *lp;
   int status;
@@ -3677,20 +3706,28 @@ kill_callback (struct lwp_info *lp, void *data)
   errno = 0;
   kill (ptid_get_lwp (lp->ptid), SIGKILL);
   if (debug_linux_nat)
-    fprintf_unfiltered (gdb_stdlog,
-                       "KC:  kill (SIGKILL) %s, 0, 0 (%s)\n",
-                       target_pid_to_str (lp->ptid),
-                       errno ? safe_strerror (errno) : "OK");
+    {
+      int save_errno = errno;
+
+      fprintf_unfiltered (gdb_stdlog,
+                         "KC:  kill (SIGKILL) %s, 0, 0 (%s)\n",
+                         target_pid_to_str (lp->ptid),
+                         save_errno ? safe_strerror (save_errno) : "OK");
+    }
 
   /* Some kernels ignore even SIGKILL for processes under ptrace.  */
 
   errno = 0;
   ptrace (PTRACE_KILL, ptid_get_lwp (lp->ptid), 0, 0);
   if (debug_linux_nat)
-    fprintf_unfiltered (gdb_stdlog,
-                       "KC:  PTRACE_KILL %s, 0, 0 (%s)\n",
-                       target_pid_to_str (lp->ptid),
-                       errno ? safe_strerror (errno) : "OK");
+    {
+      int save_errno = errno;
+
+      fprintf_unfiltered (gdb_stdlog,
+                         "KC:  PTRACE_KILL %s, 0, 0 (%s)\n",
+                         target_pid_to_str (lp->ptid),
+                         save_errno ? safe_strerror (save_errno) : "OK");
+    }
 
   return 0;
 }
This page took 0.026945 seconds and 4 git commands to generate.