Fix typo in gdb.python/py-objfile.exp
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 22ce84207b0a8e8cbda9385de3aad6f80b390b7f..b33abb0dce6125241e7704b037480ad36ff835bd 100644 (file)
@@ -28,7 +28,7 @@
 #include <unistd.h>
 #include <sys/syscall.h>
 #endif
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
 #include "linux-nat.h"
 #include "nat/linux-ptrace.h"
 #include "nat/linux-procfs.h"
@@ -66,6 +66,8 @@
 #include "target-descriptions.h"
 #include "filestuff.h"
 #include "objfiles.h"
+#include "nat/linux-namespaces.h"
+#include "fileio.h"
 
 #ifndef SPUFS_MAGIC
 #define SPUFS_MAGIC 0x23c9b64e
@@ -163,6 +165,9 @@ blocked.  */
 #define O_LARGEFILE 0
 #endif
 
+/* Does the current host support PTRACE_GETREGSET?  */
+enum tribool have_ptrace_getregset = TRIBOOL_UNKNOWN;
+
 /* 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;
@@ -281,6 +286,50 @@ static int check_stopped_by_breakpoint (struct lwp_info *lp);
 static int sigtrap_is_event (int status);
 static int (*linux_nat_status_is_event) (int status) = sigtrap_is_event;
 
+\f
+/* LWP accessors.  */
+
+/* See nat/linux-nat.h.  */
+
+ptid_t
+ptid_of_lwp (struct lwp_info *lwp)
+{
+  return lwp->ptid;
+}
+
+/* See nat/linux-nat.h.  */
+
+void
+lwp_set_arch_private_info (struct lwp_info *lwp,
+                          struct arch_lwp_info *info)
+{
+  lwp->arch_private = info;
+}
+
+/* See nat/linux-nat.h.  */
+
+struct arch_lwp_info *
+lwp_arch_private_info (struct lwp_info *lwp)
+{
+  return lwp->arch_private;
+}
+
+/* See nat/linux-nat.h.  */
+
+int
+lwp_is_stopped (struct lwp_info *lwp)
+{
+  return lwp->stopped;
+}
+
+/* See nat/linux-nat.h.  */
+
+enum target_stop_reason
+lwp_stop_reason (struct lwp_info *lwp)
+{
+  return lwp->stop_reason;
+}
+
 \f
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
@@ -324,6 +373,25 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
   return 0;
 }
 
+/* Return the ptrace options that we want to try to enable.  */
+
+static int
+linux_nat_ptrace_options (int attached)
+{
+  int options = 0;
+
+  if (!attached)
+    options |= PTRACE_O_EXITKILL;
+
+  options |= (PTRACE_O_TRACESYSGOOD
+             | PTRACE_O_TRACEVFORKDONE
+             | PTRACE_O_TRACEVFORK
+             | PTRACE_O_TRACEFORK
+             | PTRACE_O_TRACEEXEC);
+
+  return options;
+}
+
 /* Initialize ptrace warnings and check for supported ptrace
    features given PID.
 
@@ -332,7 +400,9 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
 static void
 linux_init_ptrace (pid_t pid, int attached)
 {
-  linux_enable_event_reporting (pid, attached);
+  int options = linux_nat_ptrace_options (attached);
+
+  linux_enable_event_reporting (pid, options);
   linux_ptrace_init_warnings ();
 }
 
@@ -834,14 +904,11 @@ find_lwp_pid (ptid_t ptid)
   return NULL;
 }
 
-/* Call CALLBACK with its second argument set to DATA for every LWP in
-   the list.  If CALLBACK returns 1 for a particular LWP, return a
-   pointer to the structure describing that LWP immediately.
-   Otherwise return NULL.  */
+/* See nat/linux-nat.h.  */
 
 struct lwp_info *
 iterate_over_lwps (ptid_t filter,
-                  int (*callback) (struct lwp_info *, void *),
+                  iterate_over_lwps_ftype callback,
                   void *data)
 {
   struct lwp_info *lp, *lpnext;
@@ -852,7 +919,7 @@ iterate_over_lwps (ptid_t filter,
 
       if (ptid_match (lp->ptid, filter))
        {
-         if ((*callback) (lp, data))
+         if ((*callback) (lp, data) != 0)
            return lp;
        }
     }
@@ -1300,7 +1367,7 @@ linux_nat_attach (struct target_ops *ops, const char *args, int from_tty)
                                  attach_proc_task_lwp_callback);
 
   if (target_can_async_p ())
-    target_async (inferior_event_handler, 0);
+    target_async (1);
 }
 
 /* Get pending status of LP.  */
@@ -1503,7 +1570,8 @@ linux_nat_detach (struct target_ops *ops, const char *args, int from_tty)
    single-step it.  If SIGNAL is nonzero, give it that signal.  */
 
 static void
-linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
+linux_resume_one_lwp_throw (struct lwp_info *lp, int step,
+                           enum gdb_signal signo)
 {
   lp->step = step;
 
@@ -1522,11 +1590,68 @@ linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
   if (linux_nat_prepare_to_resume != NULL)
     linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, lp->ptid, step, signo);
-  lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
+
+  /* Successfully resumed.  Clear state that no longer makes sense,
+     and mark the LWP as running.  Must not do this before resuming
+     otherwise if that fails other code will be confused.  E.g., we'd
+     later try to stop the LWP and hang forever waiting for a stop
+     status.  Note that we must not throw after this is cleared,
+     otherwise handle_zombie_lwp_error would get confused.  */
   lp->stopped = 0;
+  lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
   registers_changed_ptid (lp->ptid);
 }
 
+/* Called when we try to resume a stopped LWP and that errors out.  If
+   the LWP is no longer in ptrace-stopped state (meaning it's zombie,
+   or about to become), discard the error, clear any pending status
+   the LWP may have, and return true (we'll collect the exit status
+   soon enough).  Otherwise, return false.  */
+
+static int
+check_ptrace_stopped_lwp_gone (struct lwp_info *lp)
+{
+  /* If we get an error after resuming the LWP successfully, we'd
+     confuse !T state for the LWP being gone.  */
+  gdb_assert (lp->stopped);
+
+  /* We can't just check whether the LWP is in 'Z (Zombie)' state,
+     because even if ptrace failed with ESRCH, the tracee may be "not
+     yet fully dead", but already refusing ptrace requests.  In that
+     case the tracee has 'R (Running)' state for a little bit
+     (observed in Linux 3.18).  See also the note on ESRCH in the
+     ptrace(2) man page.  Instead, check whether the LWP has any state
+     other than ptrace-stopped.  */
+
+  /* Don't assume anything if /proc/PID/status can't be read.  */
+  if (linux_proc_pid_is_trace_stopped_nowarn (ptid_get_lwp (lp->ptid)) == 0)
+    {
+      lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
+      lp->status = 0;
+      lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+      return 1;
+    }
+  return 0;
+}
+
+/* Like linux_resume_one_lwp_throw, but no error is thrown if the LWP
+   disappears while we try to resume it.  */
+
+static void
+linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
+{
+  TRY
+    {
+      linux_resume_one_lwp_throw (lp, step, signo);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (!check_ptrace_stopped_lwp_gone (lp))
+       throw_exception (ex);
+    }
+  END_CATCH
+}
+
 /* Resume LP.  */
 
 static void
@@ -1690,7 +1815,7 @@ linux_nat_resume (struct target_ops *ops,
 
       if (target_can_async_p ())
        {
-         target_async (inferior_event_handler, 0);
+         target_async (1);
          /* Tell the event loop we have something to process.  */
          async_file_mark ();
        }
@@ -1700,18 +1825,18 @@ linux_nat_resume (struct target_ops *ops,
   if (resume_many)
     iterate_over_lwps (ptid, linux_nat_resume_callback, lp);
 
-  linux_resume_one_lwp (lp, step, signo);
-
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
                        "LLR: %s %s, %s (resume event thread)\n",
                        step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
-                       target_pid_to_str (ptid),
+                       target_pid_to_str (lp->ptid),
                        (signo != GDB_SIGNAL_0
                         ? strsignal (gdb_signal_to_host (signo)) : "0"));
 
+  linux_resume_one_lwp (lp, step, signo);
+
   if (target_can_async_p ())
-    target_async (inferior_event_handler, 0);
+    target_async (1);
 }
 
 /* Send a signal to an LWP.  */
@@ -2010,9 +2135,12 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
              add_thread (new_lp->ptid);
            }
 
+         /* Even if we're stopping the thread for some reason
+            internal to this module, from the user/frontend's
+            perspective, this new thread is running.  */
+         set_running (new_lp->ptid, 1);
          if (!stopping)
            {
-             set_running (new_lp->ptid, 1);
              set_executing (new_lp->ptid, 1);
              /* thread_db_attach_lwp -> lin_lwp_attach_lwp forced
                 resume_stop.  */
@@ -2199,8 +2327,9 @@ wait_lwp (struct lwp_info *lp)
   if (lp->must_set_ptrace_flags)
     {
       struct inferior *inf = find_inferior_pid (ptid_get_pid (lp->ptid));
+      int options = linux_nat_ptrace_options (inf->attach_flag);
 
-      linux_enable_event_reporting (ptid_get_lwp (lp->ptid), inf->attach_flag);
+      linux_enable_event_reporting (ptid_get_lwp (lp->ptid), options);
       lp->must_set_ptrace_flags = 0;
     }
 
@@ -2519,7 +2648,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
 
          if (debug_linux_nat)
            fprintf_unfiltered (gdb_stdlog,
-                               "SWC: Delayed SIGSTOP caught for %s.\n",
+                               "SWC: Expected SIGSTOP caught for %s.\n",
                                target_pid_to_str (lp->ptid));
 
          /* Reset SIGNALLED only after the stop_wait_callback call
@@ -2543,6 +2672,9 @@ status_callback (struct lwp_info *lp, void *data)
   if (!lp->resumed)
     return 0;
 
+  if (!lwp_status_pending_p (lp))
+    return 0;
+
   if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
       || lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)
     {
@@ -2551,8 +2683,6 @@ status_callback (struct lwp_info *lp, void *data)
       CORE_ADDR pc;
       int discard = 0;
 
-      gdb_assert (lp->status != 0);
-
       pc = regcache_read_pc (regcache);
 
       if (pc != lp->stop_pc)
@@ -2590,10 +2720,9 @@ status_callback (struct lwp_info *lp, void *data)
          linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
          return 0;
        }
-      return 1;
     }
 
-  return lwp_status_pending_p (lp);
+  return 1;
 }
 
 /* Return non-zero if LP isn't stopped.  */
@@ -2644,7 +2773,7 @@ lwp_status_pending_p (struct lwp_info *lp)
   return lp->status != 0 || lp->waitstatus.kind != TARGET_WAITKIND_IGNORE;
 }
 
-/* Select the Nth LWP that has had a SIGTRAP event.  */
+/* Select the Nth LWP that has had an event.  */
 
 static int
 select_event_lwp_callback (struct lwp_info *lp, void *data)
@@ -2696,8 +2825,8 @@ check_stopped_by_breakpoint (struct lwp_info *lp)
            {
              if (debug_linux_nat)
                fprintf_unfiltered (gdb_stdlog,
-                                   "CSBB: Push back software "
-                                   "breakpoint for %s\n",
+                                   "CSBB: %s stopped by software "
+                                   "breakpoint\n",
                                    target_pid_to_str (lp->ptid));
 
              /* Back up the PC if necessary.  */
@@ -2712,14 +2841,21 @@ check_stopped_by_breakpoint (struct lwp_info *lp)
            {
              if (debug_linux_nat)
                fprintf_unfiltered (gdb_stdlog,
-                                   "CSBB: Push back hardware "
-                                   "breakpoint/watchpoint for %s\n",
+                                   "CSBB: %s stopped by hardware "
+                                   "breakpoint/watchpoint\n",
                                    target_pid_to_str (lp->ptid));
 
              lp->stop_pc = pc;
              lp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
              return 1;
            }
+         else if (siginfo.si_code == TRAP_TRACE)
+           {
+             if (debug_linux_nat)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "CSBB: %s stopped by trace\n",
+                                   target_pid_to_str (lp->ptid));
+           }
        }
     }
 #else
@@ -2731,7 +2867,7 @@ check_stopped_by_breakpoint (struct lwp_info *lp)
         breakpoint instruction.  */
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
-                           "CB: Push back software breakpoint for %s\n",
+                           "CSBB: %s stopped by software breakpoint\n",
                            target_pid_to_str (lp->ptid));
 
       /* Back up the PC if necessary.  */
@@ -2747,7 +2883,7 @@ check_stopped_by_breakpoint (struct lwp_info *lp)
     {
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
-                           "CB: Push back hardware breakpoint for %s\n",
+                           "CSBB: stopped by hardware breakpoint %s\n",
                            target_pid_to_str (lp->ptid));
 
       lp->stop_pc = pc;
@@ -2841,6 +2977,7 @@ select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
 
       /* First see how many events we have.  */
       iterate_over_lwps (filter, count_events_callback, &num_events);
+      gdb_assert (num_events > 0);
 
       /* Now randomly pick a LWP out of those that have had
         events.  */
@@ -2992,8 +3129,9 @@ linux_nat_filter_event (int lwpid, int status)
   if (WIFSTOPPED (status) && lp->must_set_ptrace_flags)
     {
       struct inferior *inf = find_inferior_pid (ptid_get_pid (lp->ptid));
+      int options = linux_nat_ptrace_options (inf->attach_flag);
 
-      linux_enable_event_reporting (ptid_get_lwp (lp->ptid), inf->attach_flag);
+      linux_enable_event_reporting (ptid_get_lwp (lp->ptid), options);
       lp->must_set_ptrace_flags = 0;
     }
 
@@ -3057,12 +3195,14 @@ linux_nat_filter_event (int lwpid, int status)
            }
        }
 
-      gdb_assert (lp->resumed);
-
+      /* Note that even if the leader was ptrace-stopped, it can still
+        exit, if e.g., some other thread brings down the whole
+        process (calls `exit').  So don't assert that the lwp is
+        resumed.  */
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
-                           "Process %ld exited\n",
-                           ptid_get_lwp (lp->ptid));
+                           "Process %ld exited (resumed=%d)\n",
+                           ptid_get_lwp (lp->ptid), lp->resumed);
 
       /* This was the last lwp in the process.  Since events are
         serialized to GDB core, we may not be able report this one
@@ -3106,28 +3246,28 @@ linux_nat_filter_event (int lwpid, int status)
   if (lp->signalled
       && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
     {
-      if (debug_linux_nat)
-       fprintf_unfiltered (gdb_stdlog,
-                           "LLW: Delayed SIGSTOP caught for %s.\n",
-                           target_pid_to_str (lp->ptid));
-
       lp->signalled = 0;
 
-      if (lp->last_resume_kind != resume_stop)
+      if (lp->last_resume_kind == resume_stop)
+       {
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "LLW: resume_stop SIGSTOP caught for %s.\n",
+                               target_pid_to_str (lp->ptid));
+       }
+      else
        {
-         /* This is a delayed SIGSTOP.  */
+         /* This is a delayed SIGSTOP.  Filter out the event.  */
 
-         linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
          if (debug_linux_nat)
            fprintf_unfiltered (gdb_stdlog,
-                               "LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
+                               "LLW: %s %s, 0, 0 (discard delayed SIGSTOP)\n",
                                lp->step ?
                                "PTRACE_SINGLESTEP" : "PTRACE_CONT",
                                target_pid_to_str (lp->ptid));
 
+         linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
          gdb_assert (lp->resumed);
-
-         /* Discard the event.  */
          return NULL;
        }
     }
@@ -3541,24 +3681,39 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
     {
       struct regcache *regcache = get_thread_regcache (lp->ptid);
       struct gdbarch *gdbarch = get_regcache_arch (regcache);
-      CORE_ADDR pc = regcache_read_pc (regcache);
 
-      /* Don't bother if there's a breakpoint at PC that we'd hit
-        immediately, and we're not waiting for this LWP.  */
-      if (!ptid_match (lp->ptid, *wait_ptid_p))
+      TRY
        {
-         if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
-           return 0;
-       }
+         CORE_ADDR pc = regcache_read_pc (regcache);
+         int leave_stopped = 0;
 
-      if (debug_linux_nat)
-       fprintf_unfiltered (gdb_stdlog,
-                           "RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n",
-                           target_pid_to_str (lp->ptid),
-                           paddress (gdbarch, pc),
-                           lp->step);
+         /* Don't bother if there's a breakpoint at PC that we'd hit
+            immediately, and we're not waiting for this LWP.  */
+         if (!ptid_match (lp->ptid, *wait_ptid_p))
+           {
+             if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
+               leave_stopped = 1;
+           }
 
-      linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
+         if (!leave_stopped)
+           {
+             if (debug_linux_nat)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "RSRL: resuming stopped-resumed LWP %s at "
+                                   "%s: step=%d\n",
+                                   target_pid_to_str (lp->ptid),
+                                   paddress (gdbarch, pc),
+                                   lp->step);
+
+             linux_resume_one_lwp_throw (lp, lp->step, GDB_SIGNAL_0);
+           }
+       }
+      CATCH (ex, RETURN_MASK_ERROR)
+       {
+         if (!check_ptrace_stopped_lwp_gone (lp))
+           throw_exception (ex);
+       }
+      END_CATCH
     }
 
   return 0;
@@ -3905,6 +4060,23 @@ linux_nat_thread_alive (struct target_ops *ops, ptid_t ptid)
   return linux_thread_alive (ptid);
 }
 
+/* Implement the to_update_thread_list target method for this
+   target.  */
+
+static void
+linux_nat_update_thread_list (struct target_ops *ops)
+{
+  if (linux_supports_traceclone ())
+    {
+      /* With support for clone events, we add/delete threads from the
+        list as clone/exit events are processed, so just try deleting
+        exited threads still in the thread list.  */
+      delete_exited_threads ();
+    }
+  else
+    prune_threads ();
+}
+
 static char *
 linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
 {
@@ -3964,15 +4136,7 @@ linux_nat_thread_name (struct target_ops *self, struct thread_info *thr)
 static char *
 linux_child_pid_to_exec_file (struct target_ops *self, int pid)
 {
-  static char buf[PATH_MAX];
-  char name[PATH_MAX];
-
-  xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
-  memset (buf, 0, PATH_MAX);
-  if (readlink (name, buf, PATH_MAX - 1) <= 0)
-    strcpy (buf, name);
-
-  return buf;
+  return linux_proc_pid_to_exec_file (pid);
 }
 
 /* Implement the to_xfer_partial interface for memory reads using the /proc
@@ -4503,10 +4667,6 @@ linux_nat_terminal_ours (struct target_ops *self)
   async_terminal_is_ours = 1;
 }
 
-static void (*async_client_callback) (enum inferior_event_type event_type,
-                                     void *context);
-static void *async_client_context;
-
 /* SIGCHLD handler that serves two purposes: In non-stop/async mode,
    so we notice when any child changes state, and notify the
    event-loop; it allows us to use sigsuspend in linux_nat_wait_1
@@ -4534,7 +4694,7 @@ sigchld_handler (int signo)
 static void
 handle_target_event (int error, gdb_client_data client_data)
 {
-  (*async_client_callback) (INF_REG_EVENT, async_client_context);
+  inferior_event_handler (INF_REG_EVENT, NULL);
 }
 
 /* Create/destroy the target events pipe.  Returns previous state.  */
@@ -4578,15 +4738,10 @@ linux_async_pipe (int enable)
 /* target_async implementation.  */
 
 static void
-linux_nat_async (struct target_ops *ops,
-                void (*callback) (enum inferior_event_type event_type,
-                                  void *context),
-                void *context)
+linux_nat_async (struct target_ops *ops, int enable)
 {
-  if (callback != NULL)
+  if (enable)
     {
-      async_client_callback = callback;
-      async_client_context = context;
       if (!linux_async_pipe (1))
        {
          add_file_handler (linux_nat_event_pipe[0],
@@ -4598,8 +4753,6 @@ linux_nat_async (struct target_ops *ops,
     }
   else
     {
-      async_client_callback = callback;
-      async_client_context = context;
       delete_file_handler (linux_nat_event_pipe[0]);
       linux_async_pipe (0);
     }
@@ -4667,7 +4820,7 @@ linux_nat_close (struct target_ops *self)
 {
   /* Unregister from the event loop.  */
   if (linux_nat_is_async_p (self))
-    linux_nat_async (self, NULL, NULL);
+    linux_nat_async (self, 0);
 
   if (linux_ops->to_close)
     linux_ops->to_close (linux_ops);
@@ -4719,6 +4872,104 @@ linux_nat_core_of_thread (struct target_ops *ops, ptid_t ptid)
   return -1;
 }
 
+/* Implementation of to_filesystem_is_local.  */
+
+static int
+linux_nat_filesystem_is_local (struct target_ops *ops)
+{
+  struct inferior *inf = current_inferior ();
+
+  if (inf->fake_pid_p || inf->pid == 0)
+    return 1;
+
+  return linux_ns_same (inf->pid, LINUX_NS_MNT);
+}
+
+/* Convert the INF argument passed to a to_fileio_* method
+   to a process ID suitable for passing to its corresponding
+   linux_mntns_* function.  If INF is non-NULL then the
+   caller is requesting the filesystem seen by INF.  If INF
+   is NULL then the caller is requesting the filesystem seen
+   by the GDB.  We fall back to GDB's filesystem in the case
+   that INF is non-NULL but its PID is unknown.  */
+
+static pid_t
+linux_nat_fileio_pid_of (struct inferior *inf)
+{
+  if (inf == NULL || inf->fake_pid_p || inf->pid == 0)
+    return getpid ();
+  else
+    return inf->pid;
+}
+
+/* Implementation of to_fileio_open.  */
+
+static int
+linux_nat_fileio_open (struct target_ops *self,
+                      struct inferior *inf, const char *filename,
+                      int flags, int mode, int *target_errno)
+{
+  int nat_flags;
+  mode_t nat_mode;
+  int fd;
+
+  if (fileio_to_host_openflags (flags, &nat_flags) == -1
+      || fileio_to_host_mode (mode, &nat_mode) == -1)
+    {
+      *target_errno = FILEIO_EINVAL;
+      return -1;
+    }
+
+  fd = linux_mntns_open_cloexec (linux_nat_fileio_pid_of (inf),
+                                filename, nat_flags, nat_mode);
+  if (fd == -1)
+    *target_errno = host_to_fileio_error (errno);
+
+  return fd;
+}
+
+/* Implementation of to_fileio_readlink.  */
+
+static char *
+linux_nat_fileio_readlink (struct target_ops *self,
+                          struct inferior *inf, const char *filename,
+                          int *target_errno)
+{
+  char buf[PATH_MAX];
+  int len;
+  char *ret;
+
+  len = linux_mntns_readlink (linux_nat_fileio_pid_of (inf),
+                             filename, buf, sizeof (buf));
+  if (len < 0)
+    {
+      *target_errno = host_to_fileio_error (errno);
+      return NULL;
+    }
+
+  ret = xmalloc (len + 1);
+  memcpy (ret, buf, len);
+  ret[len] = '\0';
+  return ret;
+}
+
+/* Implementation of to_fileio_unlink.  */
+
+static int
+linux_nat_fileio_unlink (struct target_ops *self,
+                        struct inferior *inf, const char *filename,
+                        int *target_errno)
+{
+  int ret;
+
+  ret = linux_mntns_unlink (linux_nat_fileio_pid_of (inf),
+                           filename);
+  if (ret == -1)
+    *target_errno = host_to_fileio_error (errno);
+
+  return ret;
+}
+
 void
 linux_nat_add_target (struct target_ops *t)
 {
@@ -4740,6 +4991,7 @@ linux_nat_add_target (struct target_ops *t)
   t->to_kill = linux_nat_kill;
   t->to_mourn_inferior = linux_nat_mourn_inferior;
   t->to_thread_alive = linux_nat_thread_alive;
+  t->to_update_thread_list = linux_nat_update_thread_list;
   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;
@@ -4771,6 +5023,11 @@ linux_nat_add_target (struct target_ops *t)
 
   t->to_core_of_thread = linux_nat_core_of_thread;
 
+  t->to_filesystem_is_local = linux_nat_filesystem_is_local;
+  t->to_fileio_open = linux_nat_fileio_open;
+  t->to_fileio_readlink = linux_nat_fileio_readlink;
+  t->to_fileio_unlink = linux_nat_fileio_unlink;
+
   /* We don't change the stratum; this target will sit at
      process_stratum and thread_db will set at thread_stratum.  This
      is a little strange, since this is a multi-threaded-capable
@@ -4864,6 +5121,15 @@ linux_nat_get_siginfo (ptid_t ptid, siginfo_t *siginfo)
   return 1;
 }
 
+/* See nat/linux-nat.h.  */
+
+ptid_t
+current_lwp_ptid (void)
+{
+  gdb_assert (ptid_lwp_p (inferior_ptid));
+  return inferior_ptid;
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_linux_nat;
 
@@ -4879,6 +5145,15 @@ Enables printf debugging output."),
                             show_debug_linux_nat,
                             &setdebuglist, &showdebuglist);
 
+  add_setshow_boolean_cmd ("linux-namespaces", class_maintenance,
+                          &debug_linux_namespaces, _("\
+Set debugging of GNU/Linux namespaces module."), _("\
+Show debugging of GNU/Linux namespaces module."), _("\
+Enables printf debugging output."),
+                          NULL,
+                          NULL,
+                          &setdebuglist, &showdebuglist);
+
   /* Save this mask as the default.  */
   sigprocmask (SIG_SETMASK, NULL, &normal_mask);
 
@@ -4895,14 +5170,6 @@ Enables printf debugging output."),
   sigdelset (&suspend_mask, SIGCHLD);
 
   sigemptyset (&blocked_mask);
-
-  /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to
-     support read-only process state.  */
-  linux_ptrace_set_additional_flags (PTRACE_O_TRACESYSGOOD
-                                    | PTRACE_O_TRACEVFORKDONE
-                                    | PTRACE_O_TRACEVFORK
-                                    | PTRACE_O_TRACEFORK
-                                    | PTRACE_O_TRACEEXEC);
 }
 \f
 
This page took 0.032148 seconds and 4 git commands to generate.