* linux-thread-db.c (thread_db_mourn_inferior): Remove breakpoints
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 57843c53adb203e8a3f800059e0a6dc7f98d6857..7b4bed8c9270bfbdde42231ca61d7354e31025f7 100644 (file)
@@ -1,6 +1,6 @@
 /* GNU/Linux native-dependent code common to multiple platforms.
 
-   Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -16,8 +16,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #include "defs.h"
 #include "inferior.h"
 #endif
 #include <sys/ptrace.h>
 #include "linux-nat.h"
+#include "linux-fork.h"
 #include "gdbthread.h"
 #include "gdbcmd.h"
 #include "regcache.h"
+#include "inf-ptrace.h"
+#include "auxv.h"
 #include <sys/param.h>         /* for MAXPATHLEN */
 #include <sys/procfs.h>                /* for elf_gregset etc. */
 #include "elf-bfd.h"           /* for elfcore_write_* */
 #define __WALL          0x40000000 /* Wait for any child.  */
 #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;
+
+/* 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 *, 
+                                     enum target_object,
+                                     const char *, gdb_byte *, 
+                                     const gdb_byte *,
+                                     ULONGEST, LONGEST);
+
+/* The saved to_mourn_inferior method, inherited from inf-ptrace.c.
+   Called by our to_mourn_inferior.  */
+static void (*super_mourn_inferior) (void);
+
 static int debug_linux_nat;
 static void
 show_debug_linux_nat (struct ui_file *file, int from_tty,
@@ -319,22 +338,14 @@ child_post_attach (int pid)
   linux_enable_event_reporting (pid_to_ptid (pid));
 }
 
-void
+static void
 linux_child_post_startup_inferior (ptid_t ptid)
 {
   linux_enable_event_reporting (ptid);
 }
 
-#ifndef LINUX_CHILD_POST_STARTUP_INFERIOR
-void
-child_post_startup_inferior (ptid_t ptid)
-{
-  linux_child_post_startup_inferior (ptid);
-}
-#endif
-
 int
-child_follow_fork (int follow_child)
+child_follow_fork (struct target_ops *ops, int follow_child)
 {
   ptid_t last_ptid;
   struct target_waitstatus last_status;
@@ -359,11 +370,28 @@ child_follow_fork (int follow_child)
         also, but they'll be reinserted below.  */
       detach_breakpoints (child_pid);
 
-      fprintf_filtered (gdb_stdout,
-                       "Detaching after fork from child process %d.\n",
-                       child_pid);
+      /* Detach new forked process?  */
+      if (detach_fork)
+       {
+         if (debug_linux_nat)
+           {
+             target_terminal_ours ();
+             fprintf_filtered (gdb_stdlog,
+                               "Detaching after fork from child process %d.\n",
+                               child_pid);
+           }
 
-      ptrace (PTRACE_DETACH, child_pid, 0, 0);
+         ptrace (PTRACE_DETACH, child_pid, 0, 0);
+       }
+      else
+       {
+         struct fork_info *fp;
+         /* Retain child fork in ptrace (stopped) state.  */
+         fp = find_fork_pid (child_pid);
+         if (!fp)
+           fp = add_fork (child_pid);
+         fork_save_infrun_state (fp, 0);
+       }
 
       if (has_vforked)
        {
@@ -373,7 +401,7 @@ child_follow_fork (int follow_child)
              int status;
 
              ptrace (PTRACE_CONT, parent_pid, 0, 0);
-             waitpid (parent_pid, &status, __WALL);
+             my_waitpid (parent_pid, &status, __WALL);
              if ((status >> 16) != PTRACE_EVENT_VFORK_DONE)
                warning (_("Unexpected waitpid result %06x when waiting for "
                         "vfork-done"), status);
@@ -430,9 +458,13 @@ child_follow_fork (int follow_child)
       /* Before detaching from the parent, remove all breakpoints from it. */
       remove_breakpoints ();
 
-      fprintf_filtered (gdb_stdout,
-                       "Attaching after fork to child process %d.\n",
-                       child_pid);
+      if (debug_linux_nat)
+       {
+         target_terminal_ours ();
+         fprintf_filtered (gdb_stdlog,
+                           "Attaching after fork to child process %d.\n",
+                           child_pid);
+       }
 
       /* 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
@@ -454,11 +486,26 @@ child_follow_fork (int follow_child)
 
       if (has_vforked)
        linux_parent_pid = parent_pid;
+      else if (!detach_fork)
+       {
+         struct fork_info *fp;
+         /* Retain parent fork in ptrace (stopped) state.  */
+         fp = find_fork_pid (parent_pid);
+         if (!fp)
+           fp = add_fork (parent_pid);
+         fork_save_infrun_state (fp, 0);
+       }
       else
-       target_detach (NULL, 0);
+       {
+         target_detach (NULL, 0);
+       }
 
       inferior_ptid = pid_to_ptid (child_pid);
-      push_target (&deprecated_child_ops);
+
+      /* Reinstall ourselves, since we might have been removed in
+        target_detach (which does other necessary cleanup).  */
+
+      push_target (ops);
 
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
@@ -486,10 +533,8 @@ linux_handle_extended_wait (int pid, int status,
        {
          /* The new child has a pending SIGSTOP.  We can't affect it until it
             hits the SIGSTOP, but we're already attached.  */
-         do {
-           ret = waitpid (new_pid, &status,
-                          (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
-         } while (ret == -1 && errno == EINTR);
+         ret = my_waitpid (new_pid, &status,
+                           (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
          if (ret == -1)
            perror_with_name (_("waiting for new child"));
          else if (ret != new_pid)
@@ -566,33 +611,42 @@ kill_inferior (void)
   if (pid == 0)
     return;
 
-  /* If we're stopped while forking and we haven't followed yet, kill the
-     other task.  We need to do this first because the parent will be
-     sleeping if this is a vfork.  */
-
-  get_last_target_status (&last_ptid, &last);
-
-  if (last.kind == TARGET_WAITKIND_FORKED
-      || last.kind == TARGET_WAITKIND_VFORKED)
+  /* First cut -- let's crudely do everything inline.  */
+  if (forks_exist_p ())
     {
-      ptrace (PT_KILL, last.value.related_pid, 0, 0);
-      wait (&status);
+      linux_fork_killall ();
+      pop_target ();
+      generic_mourn_inferior ();
     }
+  else
+    {
+      /* If we're stopped while forking and we haven't followed yet,
+        kill the other task.  We need to do this first because the
+        parent will be sleeping if this is a vfork.  */
 
-  /* Kill the current process.  */
-  ptrace (PT_KILL, pid, 0, 0);
-  ret = wait (&status);
+      get_last_target_status (&last_ptid, &last);
 
-  /* We might get a SIGCHLD instead of an exit status.  This is
-     aggravated by the first kill above - a child has just died.  */
+      if (last.kind == TARGET_WAITKIND_FORKED
+         || last.kind == TARGET_WAITKIND_VFORKED)
+       {
+         ptrace (PT_KILL, last.value.related_pid, 0, 0);
+         wait (&status);
+       }
 
-  while (ret == pid && WIFSTOPPED (status))
-    {
+      /* Kill the current process.  */
       ptrace (PT_KILL, pid, 0, 0);
       ret = wait (&status);
-    }
 
-  target_mourn_inferior ();
+      /* We might get a SIGCHLD instead of an exit status.  This is
+        aggravated by the first kill above - a child has just died.  */
+
+      while (ret == pid && WIFSTOPPED (status))
+       {
+         ptrace (PT_KILL, pid, 0, 0);
+         ret = wait (&status);
+       }
+      target_mourn_inferior ();
+    }
 }
 
 /* On GNU/Linux there are no real LWP's.  The closest thing to LWP's
@@ -860,11 +914,11 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
                            "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n",
                            target_pid_to_str (ptid));
 
-      pid = waitpid (GET_LWP (ptid), &status, 0);
+      pid = my_waitpid (GET_LWP (ptid), &status, 0);
       if (pid == -1 && errno == ECHILD)
        {
          /* Try again with __WCLONE to check cloned processes.  */
-         pid = waitpid (GET_LWP (ptid), &status, __WCLONE);
+         pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE);
          lp->cloned = 1;
        }
 
@@ -904,7 +958,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.  */
-  deprecated_child_ops.to_attach (args, from_tty);
+  linux_ops->to_attach (args, from_tty);
 
   /* Add the initial process as the first LWP to the list.  */
   lp = add_lwp (BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid)));
@@ -912,13 +966,13 @@ linux_nat_attach (char *args, int from_tty)
   /* 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.  */
-  pid = waitpid (GET_PID (inferior_ptid), &status, 0);
+  pid = my_waitpid (GET_PID (inferior_ptid), &status, 0);
   if (pid == -1 && errno == ECHILD)
     {
       warning (_("%s is a cloned process"), target_pid_to_str (inferior_ptid));
 
       /* Try again with __WCLONE to check cloned processes.  */
-      pid = waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
+      pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
       lp->cloned = 1;
     }
 
@@ -1014,7 +1068,7 @@ linux_nat_detach (char *args, int from_tty)
   sigemptyset (&blocked_mask);
 
   inferior_ptid = pid_to_ptid (GET_PID (inferior_ptid));
-  deprecated_child_ops.to_detach (args, from_tty);
+  linux_ops->to_detach (args, from_tty);
 }
 
 /* Resume LP.  */
@@ -1026,7 +1080,8 @@ resume_callback (struct lwp_info *lp, void *data)
     {
       struct thread_info *tp;
 
-      child_resume (pid_to_ptid (GET_LWP (lp->ptid)), 0, TARGET_SIGNAL_0);
+      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+                           0, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
                            "RC:  PTRACE_CONT %s, 0, 0 (resume sibling)\n",
@@ -1058,6 +1113,14 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
   struct lwp_info *lp;
   int resume_all;
 
+  if (debug_linux_nat)
+    fprintf_unfiltered (gdb_stdlog,
+                       "LLR: Preparing to %s %s, %s, inferior_ptid %s\n",
+                       step ? "step" : "resume",
+                       target_pid_to_str (ptid),
+                       signo ? strsignal (signo) : "0",
+                       target_pid_to_str (inferior_ptid));
+
   /* A specific PTID means `step only this process id'.  */
   resume_all = (PIDGET (ptid) == -1);
 
@@ -1083,12 +1146,45 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
       lp->resumed = 1;
 
       /* If we have a pending wait status for this thread, there is no
-         point in resuming the process.  */
+        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 (lp->status && WIFSTOPPED (lp->status))
+       {
+         int saved_signo = target_signal_from_host (WSTOPSIG (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 (lp->status)
        {
          /* FIXME: What should we do if we are supposed to continue
             this thread with a signal?  */
          gdb_assert (signo == TARGET_SIGNAL_0);
+
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "LLR: Short circuiting for status 0x%x\n",
+                               lp->status);
+
          return;
        }
 
@@ -1100,7 +1196,7 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
   if (resume_all)
     iterate_over_lwps (resume_callback, NULL);
 
-  child_resume (ptid, step, signo);
+  linux_ops->to_resume (ptid, step, signo);
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
                        "LLR: %s %s, %s (resume event thread)\n",
@@ -1183,10 +1279,10 @@ wait_lwp (struct lwp_info *lp)
   gdb_assert (!lp->stopped);
   gdb_assert (lp->status == 0);
 
-  pid = waitpid (GET_LWP (lp->ptid), &status, 0);
+  pid = my_waitpid (GET_LWP (lp->ptid), &status, 0);
   if (pid == -1 && errno == ECHILD)
     {
-      pid = waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
+      pid = my_waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
       if (pid == -1 && errno == ECHILD)
        {
          /* The thread has previously exited.  We need to delete it
@@ -1622,7 +1718,7 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
   int random_selector;
   struct lwp_info *event_lp;
 
-  /* Record the wait status for the origional LWP.  */
+  /* Record the wait status for the original LWP.  */
   (*orig_lp)->status = *status;
 
   /* Give preference to any LWP that is being single-stepped.  */
@@ -1674,7 +1770,29 @@ resumed_callback (struct lwp_info *lp, void *data)
   return lp->resumed;
 }
 
-#ifdef CHILD_WAIT
+/* Local mourn_inferior -- we need to override mourn_inferior
+   so that we can do something clever if one of several forks
+   has exited.  */
+
+static void
+child_mourn_inferior (void)
+{
+  int status;
+
+  if (! forks_exist_p ())
+    {
+      /* Normal case, no other forks available.  */
+      super_mourn_inferior ();
+      return;
+    }
+  else
+    {
+      /* Multi-fork case.  The current inferior_ptid has exited, but
+        there are other viable forks to debug.  Delete the exiting
+        one and context-switch to the first available.  */
+      linux_fork_mourn_inferior ();
+    }
+}
 
 /* We need to override child_wait to support attaching to cloned
    processes, since a normal wait (as done by the default version)
@@ -1698,10 +1816,10 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
                                   attached process.  */
       set_sigio_trap ();
 
-      pid = waitpid (GET_PID (ptid), &status, 0);
+      pid = my_waitpid (GET_PID (ptid), &status, 0);
       if (pid == -1 && errno == ECHILD)
        /* Try again with __WCLONE to check cloned processes.  */
-       pid = waitpid (GET_PID (ptid), &status, __WCLONE);
+       pid = my_waitpid (GET_PID (ptid), &status, __WCLONE);
 
       if (debug_linux_nat)
        {
@@ -1780,8 +1898,6 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
   return pid_to_ptid (pid);
 }
 
-#endif
-
 /* Stop an active thread, verify it still exists, then resume it.  */
 
 static int
@@ -1890,8 +2006,8 @@ retry:
       /* Resume the thread.  It should halt immediately returning the
          pending SIGSTOP.  */
       registers_changed ();
-      child_resume (pid_to_ptid (GET_LWP (lp->ptid)), lp->step,
-                   TARGET_SIGNAL_0);
+      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+                           lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
                            "LLW: %s %s, 0, 0 (expect SIGSTOP)\n",
@@ -1912,7 +2028,7 @@ retry:
     {
       pid_t lwpid;
 
-      lwpid = waitpid (pid, &status, options);
+      lwpid = my_waitpid (pid, &status, options);
       if (lwpid > 0)
        {
          gdb_assert (pid == -1 || lwpid == pid);
@@ -2092,8 +2208,8 @@ retry:
              lp->signalled = 0;
 
              registers_changed ();
-             child_resume (pid_to_ptid (GET_LWP (lp->ptid)), lp->step,
-                           TARGET_SIGNAL_0);
+             linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+                                   lp->step, TARGET_SIGNAL_0);
              if (debug_linux_nat)
                fprintf_unfiltered (gdb_stdlog,
                                    "LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
@@ -2152,7 +2268,8 @@ retry:
             newly attached threads may cause an unwanted delay in
             getting them running.  */
          registers_changed ();
-         child_resume (pid_to_ptid (GET_LWP (lp->ptid)), lp->step, signo);
+         linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+                               lp->step, signo);
          if (debug_linux_nat)
            fprintf_unfiltered (gdb_stdlog,
                                "LLW: %s %s, %s (preempt 'handle')\n",
@@ -2256,7 +2373,7 @@ kill_wait_callback (struct lwp_info *lp, void *data)
     {
       do
        {
-         pid = waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
+         pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
          if (pid != (pid_t) -1 && debug_linux_nat)
            {
              fprintf_unfiltered (gdb_stdlog,
@@ -2271,7 +2388,7 @@ kill_wait_callback (struct lwp_info *lp, void *data)
 
   do
     {
-      pid = waitpid (GET_LWP (lp->ptid), NULL, 0);
+      pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0);
       if (pid != (pid_t) -1 && debug_linux_nat)
        {
          fprintf_unfiltered (gdb_stdlog,
@@ -2301,7 +2418,7 @@ static void
 linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
                         int from_tty)
 {
-  deprecated_child_ops.to_create_inferior (exec_file, allargs, env, from_tty);
+  linux_ops->to_create_inferior (exec_file, allargs, env, from_tty);
 }
 
 static void
@@ -2316,22 +2433,23 @@ linux_nat_mourn_inferior (void)
   sigprocmask (SIG_SETMASK, &normal_mask, NULL);
   sigemptyset (&blocked_mask);
 
-  deprecated_child_ops.to_mourn_inferior ();
+  linux_ops->to_mourn_inferior ();
 }
 
-static int
-linux_nat_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
-                    struct mem_attrib *attrib, struct target_ops *target)
+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 ();
-  int xfer;
+  LONGEST xfer;
 
   if (is_lwp (inferior_ptid))
     inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid));
 
-  xfer = linux_proc_xfer_memory (memaddr, myaddr, len, write, attrib, target);
-  if (xfer == 0)
-    xfer = child_xfer_memory (memaddr, myaddr, len, write, attrib, target);
+  xfer = linux_ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
+                                    offset, len);
 
   do_cleanups (old_chain);
   return xfer;
@@ -2369,6 +2487,26 @@ linux_nat_pid_to_str (ptid_t ptid)
   return normal_pid_to_str (ptid);
 }
 
+static void
+linux_nat_fetch_registers (int regnum)
+{
+  /* to_fetch_registers will honor the LWP ID, so we can use it directly.  */
+  linux_ops->to_fetch_registers (regnum);
+}
+
+static void
+linux_nat_store_registers (int regnum)
+{
+  /* to_store_registers will honor the LWP ID, so we can use it directly.  */
+  linux_ops->to_store_registers (regnum);
+}
+
+static void
+linux_nat_child_post_startup_inferior (ptid_t ptid)
+{
+  linux_ops->to_post_startup_inferior (ptid);
+}
+
 static void
 init_linux_nat_ops (void)
 {
@@ -2382,17 +2520,16 @@ init_linux_nat_ops (void)
   linux_nat_ops.to_detach = linux_nat_detach;
   linux_nat_ops.to_resume = linux_nat_resume;
   linux_nat_ops.to_wait = linux_nat_wait;
-  /* fetch_inferior_registers and store_inferior_registers will
-     honor the LWP id, so we can use them directly.  */
-  linux_nat_ops.to_fetch_registers = fetch_inferior_registers;
-  linux_nat_ops.to_store_registers = store_inferior_registers;
-  linux_nat_ops.deprecated_xfer_memory = linux_nat_xfer_memory;
+  linux_nat_ops.to_fetch_registers = linux_nat_fetch_registers;
+  linux_nat_ops.to_store_registers = linux_nat_store_registers;
+  linux_nat_ops.to_xfer_partial = linux_nat_xfer_partial;
   linux_nat_ops.to_kill = linux_nat_kill;
   linux_nat_ops.to_create_inferior = linux_nat_create_inferior;
   linux_nat_ops.to_mourn_inferior = linux_nat_mourn_inferior;
   linux_nat_ops.to_thread_alive = linux_nat_thread_alive;
   linux_nat_ops.to_pid_to_str = linux_nat_pid_to_str;
-  linux_nat_ops.to_post_startup_inferior = child_post_startup_inferior;
+  linux_nat_ops.to_post_startup_inferior
+    = linux_nat_child_post_startup_inferior;
   linux_nat_ops.to_post_attach = child_post_attach;
   linux_nat_ops.to_insert_fork_catchpoint = child_insert_fork_catchpoint;
   linux_nat_ops.to_insert_vfork_catchpoint = child_insert_vfork_catchpoint;
@@ -2445,7 +2582,8 @@ read_mapping (FILE *mapfile,
   int ret = fscanf (mapfile, "%llx-%llx %s %llx %s %llx",
                    addr, endaddr, permissions, offset, device, inode);
 
-  if (ret > 0 && ret != EOF && *inode != 0)
+  filename[0] = '\0';
+  if (ret > 0 && ret != EOF)
     {
       /* Eat everything up to EOL for the filename.  This will prevent
          weird filenames (such as one with embedded whitespace) from
@@ -2456,11 +2594,7 @@ read_mapping (FILE *mapfile,
          only.  */
       ret += fscanf (mapfile, "%[^\n]\n", filename);
     }
-  else
-    {
-      filename[0] = '\0';      /* no filename */
-      fscanf (mapfile, "\n");
-    }
+
   return (ret != 0 && ret != EOF);
 }
 
@@ -2618,7 +2752,7 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
   char psargs[80] = { '\0' };
   char *note_data = NULL;
   ptid_t current_ptid = inferior_ptid;
-  char *auxv;
+  gdb_byte *auxv;
   int auxv_len;
 
   if (get_exec_file (0))
@@ -2941,14 +3075,22 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
     }
 }
 
-int
-linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len, int write,
-                       struct mem_attrib *attrib, struct target_ops *target)
+/* Implement the to_xfer_partial interface for memory reads using the /proc
+   filesystem.  Because we can use a single read() call for /proc, this
+   can be much more efficient than banging away at PTRACE_PEEKTEXT,
+   but it doesn't support writes.  */
+
+static LONGEST
+linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
+                        const char *annex, gdb_byte *readbuf,
+                        const gdb_byte *writebuf,
+                        ULONGEST offset, LONGEST len)
 {
-  int fd, ret;
+  LONGEST ret;
+  int fd;
   char filename[64];
 
-  if (write)
+  if (object != TARGET_OBJECT_MEMORY || !readbuf)
     return 0;
 
   /* Don't bother for one word.  */
@@ -2967,9 +3109,9 @@ linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len, int write,
      32-bit platforms (for instance, SPARC debugging a SPARC64
      application).  */
 #ifdef HAVE_PREAD64
-  if (pread64 (fd, myaddr, len, addr) != len)
+  if (pread64 (fd, readbuf, len, offset) != len)
 #else
-  if (lseek (fd, addr, SEEK_SET) == -1 || read (fd, myaddr, len) != len)
+  if (lseek (fd, offset, SEEK_SET) == -1 || read (fd, readbuf, len) != len)
 #endif
     ret = 0;
   else
@@ -3060,15 +3202,83 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
   fclose (procfile);
 }
 
+static LONGEST
+linux_xfer_partial (struct target_ops *ops, enum target_object object,
+                    const char *annex, gdb_byte *readbuf,
+                   const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  LONGEST xfer;
+
+  if (object == TARGET_OBJECT_AUXV)
+    return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
+                            offset, len);
+
+  xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
+                                 offset, len);
+  if (xfer != 0)
+    return xfer;
+
+  return super_xfer_partial (ops, object, annex, readbuf, writebuf,
+                            offset, len);
+}
+
+#ifndef FETCH_INFERIOR_REGISTERS
+
+/* Return the address in the core dump or inferior of register
+   REGNO.  */
+
+static CORE_ADDR
+linux_register_u_offset (int regno)
+{
+  /* FIXME drow/2005-09-04: The hardcoded use of register_addr should go
+     away.  This requires disentangling the various definitions of it
+     (particularly alpha-nat.c's).  */
+  return register_addr (regno, 0);
+}
+
+#endif
+
+/* Create a prototype generic Linux target.  The client can override
+   it with local methods.  */
+
+struct target_ops *
+linux_target (void)
+{
+  struct target_ops *t;
+
+#ifdef FETCH_INFERIOR_REGISTERS
+  t = inf_ptrace_target ();
+#else
+  t = inf_ptrace_trad_target (linux_register_u_offset);
+#endif
+  t->to_wait = child_wait;
+  t->to_kill = kill_inferior;
+  t->to_insert_fork_catchpoint = child_insert_fork_catchpoint;
+  t->to_insert_vfork_catchpoint = child_insert_vfork_catchpoint;
+  t->to_insert_exec_catchpoint = child_insert_exec_catchpoint;
+  t->to_pid_to_exec_file = child_pid_to_exec_file;
+  t->to_post_startup_inferior = linux_child_post_startup_inferior;
+  t->to_post_attach = child_post_attach;
+  t->to_follow_fork = child_follow_fork;
+  t->to_find_memory_regions = linux_nat_find_memory_regions;
+  t->to_make_corefile_notes = linux_nat_make_corefile_notes;
+
+  super_xfer_partial = t->to_xfer_partial;
+  t->to_xfer_partial = linux_xfer_partial;
+
+  super_mourn_inferior = t->to_mourn_inferior;
+  t->to_mourn_inferior = child_mourn_inferior;
+
+  linux_ops = t;
+  return t;
+}
+
 void
 _initialize_linux_nat (void)
 {
   struct sigaction action;
   extern void thread_db_init (struct target_ops *);
 
-  deprecated_child_ops.to_find_memory_regions = linux_nat_find_memory_regions;
-  deprecated_child_ops.to_make_corefile_notes = linux_nat_make_corefile_notes;
-
   add_info ("proc", linux_nat_info_proc_cmd, _("\
 Show /proc process information about any running process.\n\
 Specify any process id, or use the program being debugged by default.\n\
@@ -3087,7 +3297,7 @@ Specify any of the following keywords for detailed info:\n\
 
   action.sa_handler = sigchld_handler;
   sigemptyset (&action.sa_mask);
-  action.sa_flags = 0;
+  action.sa_flags = SA_RESTART;
   sigaction (SIGCHLD, &action, NULL);
 
   /* Make sure we don't block SIGCHLD during a sigsuspend.  */
@@ -3124,7 +3334,7 @@ get_signo (const char *name)
   if (ms == NULL)
     return 0;
 
-  if (target_read_memory (SYMBOL_VALUE_ADDRESS (ms), (char *) &signo,
+  if (target_read_memory (SYMBOL_VALUE_ADDRESS (ms), (gdb_byte *) &signo,
                          sizeof (signo)) != 0)
     return 0;
 
@@ -3160,7 +3370,7 @@ lin_thread_get_thread_signals (sigset_t *set)
 
   action.sa_handler = sigchld_handler;
   sigemptyset (&action.sa_mask);
-  action.sa_flags = 0;
+  action.sa_flags = SA_RESTART;
   sigaction (cancel, &action, NULL);
 
   /* We block the "cancel" signal throughout this code ...  */
@@ -3170,3 +3380,4 @@ lin_thread_get_thread_signals (sigset_t *set)
   /* ... except during a sigsuspend.  */
   sigdelset (&suspend_mask, cancel);
 }
+
This page took 0.036243 seconds and 4 git commands to generate.