* linux-nat.c (linux_ops_saved): New.
authorDaniel Jacobowitz <drow@false.org>
Fri, 24 Mar 2006 23:08:16 +0000 (23:08 +0000)
committerDaniel Jacobowitz <drow@false.org>
Fri, 24 Mar 2006 23:08:16 +0000 (23:08 +0000)
(super_mourn_inferior, kill_inferior, threaded, linux_nat_ops)
(child_mourn_inferior, child_wait, linux_nat_create_inferior)
(linux_nat_fetch_registers, linux_nat_store_registers)
(linux_nat_child_post_startup_inferior, init_linux_nat_ops): Delete.
(init_lwp_list): Don't set threaded.
(add_lwp): Don't modify threaded.
(delete_lwp): Don't mention non-threaded mode.
(linux_nat_switch_fork): New.
(linux_nat_attach): Update inferior_ptid.
(linux_nat_wait): Handle num_lwps == 0 at entry.  Don't check
threaded flag.
(linux_nat_kill): Handle pending forks and saved forks.
(linux_nat_mourn_inferior): Handle saved forks.
(linux_nat_pid_to_str): Don't use the LWP form when there is
only one thread.
(linux_target): Don't set to_wait, to_kill, or to_mourn_inferior.
(linux_nat_add_target): New.
(_initialize_linux_nat): Don't initialize the linux native target
here.
* linux-nat.h (linux_nat_add_target, linux_nat_switch_fork): New
prototypes.
* linux-fork.c: Include "linux-nat.h".
(add_fork): Update initial PID.
(fork_load_infrun_state): Call linux_nat_switch_fork.
* Makefile.in (linux-fork.o): Update.

* alpha-linux-nat.c (_initialize_alpha_linux_nat): Use
linux_nat_add_target instead of add_target.
* amd64-linux-nat.c (_initialize_amd64_linux_nat): Likewise.
* arm-linux-nat.c (_initialize_arm_linux_nat): Likewise.
* hppa-linux-nat.c (_initialize_hppa_linux_nat): Likewise.
* ia64-linux-nat.c (_initialize_ia64_linux_nat): Likewise.
* i386-linux-nat.c (_initialize_i386_linux_nat): Likewise.
* m32r-linux-nat.c (_initialize_m32r_linux_nat): Likewise.
* m68klinux-nat.c (_initialize_m68k_linux_nat): Likewise.
* mips-linux-nat.c (_initialize_mips_linux_nat): Likewise.
* ppc-linux-nat.c (_initialize_ppc_linux_nat): Likewise.
* s390-nat.c (_initialize_s390_nat): Likewise.
* sparc-linux-nat.c (_initialize_sparc_linux_nat): Likewise.
* sparc64-linux-nat.c (_initialize_sparc64_linux_nat): Likewise.

18 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/alpha-linux-nat.c
gdb/amd64-linux-nat.c
gdb/arm-linux-nat.c
gdb/hppa-linux-nat.c
gdb/i386-linux-nat.c
gdb/ia64-linux-nat.c
gdb/linux-fork.c
gdb/linux-nat.c
gdb/linux-nat.h
gdb/m32r-linux-nat.c
gdb/m68klinux-nat.c
gdb/mips-linux-nat.c
gdb/ppc-linux-nat.c
gdb/s390-nat.c
gdb/sparc-linux-nat.c
gdb/sparc64-linux-nat.c

index bf4c68d0adcc00832275966c7b9ffc008fd6a4d2..d982e29246e056e4029d7873a953b5ba3982f49c 100644 (file)
@@ -1,3 +1,47 @@
+2006-03-24  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * linux-nat.c (linux_ops_saved): New.
+       (super_mourn_inferior, kill_inferior, threaded, linux_nat_ops)
+       (child_mourn_inferior, child_wait, linux_nat_create_inferior)
+       (linux_nat_fetch_registers, linux_nat_store_registers)
+       (linux_nat_child_post_startup_inferior, init_linux_nat_ops): Delete.
+       (init_lwp_list): Don't set threaded.
+       (add_lwp): Don't modify threaded.
+       (delete_lwp): Don't mention non-threaded mode.
+       (linux_nat_switch_fork): New.
+       (linux_nat_attach): Update inferior_ptid.
+       (linux_nat_wait): Handle num_lwps == 0 at entry.  Don't check
+       threaded flag.
+       (linux_nat_kill): Handle pending forks and saved forks.
+       (linux_nat_mourn_inferior): Handle saved forks.
+       (linux_nat_pid_to_str): Don't use the LWP form when there is
+       only one thread.
+       (linux_target): Don't set to_wait, to_kill, or to_mourn_inferior.
+       (linux_nat_add_target): New.
+       (_initialize_linux_nat): Don't initialize the linux native target
+       here.
+       * linux-nat.h (linux_nat_add_target, linux_nat_switch_fork): New
+       prototypes.
+       * linux-fork.c: Include "linux-nat.h".
+       (add_fork): Update initial PID.
+       (fork_load_infrun_state): Call linux_nat_switch_fork.
+       * Makefile.in (linux-fork.o): Update.
+
+       * alpha-linux-nat.c (_initialize_alpha_linux_nat): Use
+       linux_nat_add_target instead of add_target.
+       * amd64-linux-nat.c (_initialize_amd64_linux_nat): Likewise.
+       * arm-linux-nat.c (_initialize_arm_linux_nat): Likewise.
+       * hppa-linux-nat.c (_initialize_hppa_linux_nat): Likewise.
+       * ia64-linux-nat.c (_initialize_ia64_linux_nat): Likewise.
+       * i386-linux-nat.c (_initialize_i386_linux_nat): Likewise.
+       * m32r-linux-nat.c (_initialize_m32r_linux_nat): Likewise.
+       * m68klinux-nat.c (_initialize_m68k_linux_nat): Likewise.
+       * mips-linux-nat.c (_initialize_mips_linux_nat): Likewise.
+       * ppc-linux-nat.c (_initialize_ppc_linux_nat): Likewise.
+       * s390-nat.c (_initialize_s390_nat): Likewise.
+       * sparc-linux-nat.c (_initialize_sparc_linux_nat): Likewise.
+       * sparc64-linux-nat.c (_initialize_sparc64_linux_nat): Likewise.
+
 2006-03-24  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * linux-fork.c: Include "gdb_assert.h".
index 29aa218a37a123f5bdf96c1c655b0a515e15596c..1ad9738eef5a8b7b060255e14b472b658996af93 100644 (file)
@@ -2190,7 +2190,8 @@ linespec.o: linespec.c $(defs_h) $(symtab_h) $(frame_h) $(command_h) \
        $(completer_h) $(cp_abi_h) $(parser_defs_h) $(block_h) \
        $(objc_lang_h) $(linespec_h) $(exceptions_h)
 linux-fork.o: linux-fork.c $(defs_h) $(inferior_h) $(regcache_h) $(gdbcmd_h) \
-       $(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_h)
+       $(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_h) \
+       $(linux_nat_h)
 linux-nat.o: linux-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdb_string_h) \
        $(gdb_wait_h) $(gdb_assert_h) $(linux_nat_h) $(gdbthread_h) \
        $(gdbcmd_h) $(regcache_h) $(inf_ptrace.h) $(auxv.h) $(elf_bfd_h) \
index c8559921ec761cca12c19d54c2592824bd0bb04e..183a7a412532fbc9deaba2eb05d93454d160cf81 100644 (file)
@@ -1,5 +1,5 @@
 /* Low level Alpha GNU/Linux interface, for GDB when running native.
-   Copyright (C) 2005
+   Copyright (C) 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -28,5 +28,5 @@ void _initialialize_alpha_linux_nat (void);
 void
 _initialize_alpha_linux_nat (void)
 {
-  add_target (linux_target ());
+  linux_nat_add_target (linux_target ());
 }
index 8fa6df9ab82e05b4a8101fd5ecf9e28ac980b0d6..b4a71125a3e27a26bee35724a421dec4213fd8b8 100644 (file)
@@ -1,6 +1,7 @@
 /* Native-dependent code for GNU/Linux x86-64.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
    Contributed by Jiri Smid, SuSE Labs.
 
    This file is part of GDB.
@@ -399,5 +400,5 @@ _initialize_amd64_linux_nat (void)
   t->to_store_registers = amd64_linux_store_inferior_registers;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 }
index 16298cc284b8c8f8d909103079f71b3a13b8b830..8023026a209fb4dcf140b2485086e02d4a0d679d 100644 (file)
@@ -1,5 +1,5 @@
 /* GNU/Linux on ARM native support.
-   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -736,5 +736,5 @@ _initialize_arm_linux_nat (void)
   t->to_store_registers = arm_linux_store_inferior_registers;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 }
index 48ad5335d478607442126af393e7c02bca7befcf..394c46d7b66a43ab3bb42bb641888e4c06fef175 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions specific to running GDB native on HPPA running GNU/Linux.
 
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -392,5 +392,5 @@ _initialize_hppa_linux_nat (void)
   t->to_store_registers = hppa_linux_store_inferior_registers;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 }
index 8fbbd4fcc27ee4b10e0e93abee0c1e49a3aab4c2..05501e214e32fb9c92c433053fd405c71ceb69c8 100644 (file)
@@ -1,6 +1,6 @@
 /* Native-dependent code for GNU/Linux i386.
 
-   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -844,5 +844,5 @@ _initialize_i386_linux_nat (void)
   t->to_store_registers = i386_linux_store_inferior_registers;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 }
index 6de171b1c19291f4e0f3cf871fb4a79e031c10ce..e2230815d1da014330a076a92c3e1fbda028da40 100644 (file)
@@ -1,7 +1,7 @@
 /* Functions specific to running gdb native on IA-64 running
    GNU/Linux.
 
-   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -700,5 +700,5 @@ _initialize_ia64_linux_nat (void)
   t->to_xfer_partial = ia64_linux_xfer_partial;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 }
index 88bea6169ba94de41a7b9d1fd83b6cf0d348958c..bb4468268c29dba615d1aa2d5c9aa7ad974c1d36 100644 (file)
@@ -27,6 +27,7 @@
 #include "gdb_assert.h"
 #include "gdb_string.h"
 #include "linux-fork.h"
+#include "linux-nat.h"
 
 #include <sys/ptrace.h>
 #include <sys/wait.h>
@@ -84,7 +85,7 @@ add_fork (pid_t pid)
     }
 
   fp = XZALLOC (struct fork_info);
-  fp->ptid = pid_to_ptid (pid);
+  fp->ptid = ptid_build (pid, pid, 0);
   fp->num = ++highest_fork_num;
   fp->next = fork_list;
   fork_list = fp;
@@ -241,6 +242,8 @@ fork_load_infrun_state (struct fork_info *fp)
 
   inferior_ptid = fp->ptid;
 
+  linux_nat_switch_fork (inferior_ptid);
+
   if (fp->savedregs && fp->clobber_regs)
     regcache_cpy (current_regcache, fp->savedregs);
 
index 2ba5d7d1647426fbb61097f96f92955bbf9e44f1..88e0d7d24d990ed2af5a356995460a423a7b98c2 100644 (file)
@@ -88,6 +88,7 @@
 /* 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;
+static struct target_ops linux_ops_saved;
 
 /* The saved to_xfer_partial method, inherited from inf-ptrace.c.
    Called by our to_xfer_partial.  */
@@ -97,10 +98,6 @@ static LONGEST (*super_xfer_partial) (struct target_ops *,
                                      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,
@@ -600,54 +597,6 @@ child_insert_exec_catchpoint (int pid)
     error (_("Your system does not support exec catchpoints."));
 }
 
-void
-kill_inferior (void)
-{
-  int status;
-  int pid =  PIDGET (inferior_ptid);
-  struct target_waitstatus last;
-  ptid_t last_ptid;
-  int ret;
-
-  if (pid == 0)
-    return;
-
-  /* First cut -- let's crudely do everything inline.  */
-  if (forks_exist_p ())
-    {
-      linux_fork_killall ();
-    }
-  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.  */
-
-      get_last_target_status (&last_ptid, &last);
-
-      if (last.kind == TARGET_WAITKIND_FORKED
-         || last.kind == TARGET_WAITKIND_VFORKED)
-       {
-         ptrace (PT_KILL, last.value.related_pid, 0, 0);
-         wait (&status);
-       }
-
-      /* Kill the current process.  */
-      ptrace (PT_KILL, pid, 0, 0);
-      ret = wait (&status);
-
-      /* 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
    are processes sharing the same VM space.  A multi-threaded process
    is basically a group of such processes.  However, such a grouping
@@ -686,9 +635,6 @@ static struct lwp_info *lwp_list;
 
 /* Number of LWPs in the list.  */
 static int num_lwps;
-
-/* Non-zero if we're running in "threaded" mode.  */
-static int threaded;
 \f
 
 #define GET_LWP(ptid)          ptid_get_lwp (ptid)
@@ -701,9 +647,6 @@ static int threaded;
 ptid_t trap_ptid;
 \f
 
-/* This module's target-specific operations.  */
-static struct target_ops linux_nat_ops;
-
 /* Since we cannot wait (in linux_nat_wait) for the initial process and
    any cloned processes with a single call to waitpid, we have to use
    the WNOHANG flag and call waitpid in a loop.  To optimize
@@ -768,12 +711,10 @@ init_lwp_list (void)
 
   lwp_list = NULL;
   num_lwps = 0;
-  threaded = 0;
 }
 
-/* Add the LWP specified by PID to the list.  If this causes the
-   number of LWPs to become larger than one, go into "threaded" mode.
-   Return a pointer to the structure describing the new LWP.  */
+/* Add the LWP specified by PID to the list.  Return a pointer to the
+   structure describing the new LWP.  */
 
 static struct lwp_info *
 add_lwp (ptid_t ptid)
@@ -792,8 +733,7 @@ add_lwp (ptid_t ptid)
 
   lp->next = lwp_list;
   lwp_list = lp;
-  if (++num_lwps > 1)
-    threaded = 1;
+  ++num_lwps;
 
   return lp;
 }
@@ -814,8 +754,6 @@ delete_lwp (ptid_t ptid)
   if (!lp)
     return;
 
-  /* We don't go back to "non-threaded" mode if the number of threads
-     becomes less than two.  */
   num_lwps--;
 
   if (lpprev)
@@ -867,6 +805,21 @@ iterate_over_lwps (int (*callback) (struct lwp_info *, void *), void *data)
   return NULL;
 }
 
+/* Update our internal state when changing from one fork (checkpoint,
+   et cetera) to another indicated by NEW_PTID.  We can only switch
+   single-threaded applications, so we only create one new LWP, and
+   the previous list is discarded.  */
+
+void
+linux_nat_switch_fork (ptid_t new_ptid)
+{
+  struct lwp_info *lp;
+
+  init_lwp_list ();
+  lp = add_lwp (new_ptid);
+  lp->stopped = 1;
+}
+
 /* Record a PTID for later deletion.  */
 
 struct saved_ptids
@@ -1046,7 +999,8 @@ linux_nat_attach (char *args, int 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)));
+  inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
+  lp = add_lwp (inferior_ptid);
 
   /* Make sure the initial process is stopped.  The user-level threads
      layer might want to poke around in the inferior, and that won't
@@ -1848,134 +1802,6 @@ resumed_callback (struct lwp_info *lp, void *data)
   return lp->resumed;
 }
 
-/* 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)
-   ignores those processes.  */
-
-/* Wait for child PTID to do something.  Return id of the child,
-   minus_one_ptid in case of error; store status into *OURSTATUS.  */
-
-ptid_t
-child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
-{
-  int save_errno;
-  int status;
-  pid_t pid;
-
-  ourstatus->kind = TARGET_WAITKIND_IGNORE;
-
-  do
-    {
-      set_sigint_trap ();      /* Causes SIGINT to be passed on to the
-                                  attached process.  */
-      set_sigio_trap ();
-
-      pid = my_waitpid (GET_PID (ptid), &status, 0);
-      if (pid == -1 && errno == ECHILD)
-       /* Try again with __WCLONE to check cloned processes.  */
-       pid = my_waitpid (GET_PID (ptid), &status, __WCLONE);
-
-      if (debug_linux_nat)
-       {
-         fprintf_unfiltered (gdb_stdlog,
-                             "CW:  waitpid %ld received %s\n",
-                             (long) pid, status_to_str (status));
-       }
-
-      save_errno = errno;
-
-      /* Make sure we don't report an event for the exit of the
-         original program, if we've detached from it.  */
-      if (pid != -1 && !WIFSTOPPED (status) && pid != GET_PID (inferior_ptid))
-       {
-         pid = -1;
-         save_errno = EINTR;
-       }
-
-      /* Check for stop events reported by a process we didn't already
-        know about - in this case, anything other than inferior_ptid.
-
-        If we're expecting to receive stopped processes after fork,
-        vfork, and clone events, then we'll just add the new one to
-        our list and go back to waiting for the event to be reported
-        - the stopped process might be returned from waitpid before
-        or after the event is.  If we want to handle debugging of
-        CLONE_PTRACE processes we need to do more here, i.e. switch
-        to multi-threaded mode.  */
-      if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP
-         && pid != GET_PID (inferior_ptid))
-       {
-         linux_record_stopped_pid (pid);
-         pid = -1;
-         save_errno = EINTR;
-       }
-
-      /* Handle GNU/Linux's extended waitstatus for trace events.  */
-      if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP
-         && status >> 16 != 0)
-       {
-         linux_handle_extended_wait (pid, status, ourstatus);
-
-         /* If we see a clone event, detach the child, and don't
-            report the event.  It would be nice to offer some way to
-            switch into a non-thread-db based threaded mode at this
-            point.  */
-         if (ourstatus->kind == TARGET_WAITKIND_SPURIOUS)
-           {
-             ptrace (PTRACE_DETACH, ourstatus->value.related_pid, 0, 0);
-             ourstatus->kind = TARGET_WAITKIND_IGNORE;
-             ptrace (PTRACE_CONT, pid, 0, 0);
-             pid = -1;
-             save_errno = EINTR;
-           }
-       }
-
-      clear_sigio_trap ();
-      clear_sigint_trap ();
-    }
-  while (pid == -1 && save_errno == EINTR);
-
-  if (pid == -1)
-    {
-      warning (_("Child process unexpectedly missing: %s"),
-              safe_strerror (errno));
-
-      /* Claim it exited with unknown signal.  */
-      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-      ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
-      return minus_one_ptid;
-    }
-
-  if (ourstatus->kind == TARGET_WAITKIND_IGNORE)
-    store_waitstatus (ourstatus, status);
-
-  return pid_to_ptid (pid);
-}
-
 /* Stop an active thread, verify it still exists, then resume it.  */
 
 static int
@@ -2007,6 +1833,19 @@ linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
   pid_t pid = PIDGET (ptid);
   sigset_t flush_mask;
 
+  /* The first time we get here after starting a new inferior, we may
+     not have added it to the LWP list yet - this is the earliest
+     moment at which we know its PID.  */
+  if (num_lwps == 0)
+    {
+      gdb_assert (!is_lwp (inferior_ptid));
+
+      inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
+                                GET_PID (inferior_ptid));
+      lp = add_lwp (inferior_ptid);
+      lp->resumed = 1;
+    }
+
   sigemptyset (&flush_mask);
 
   /* Make sure SIGCHLD is blocked.  */
@@ -2018,9 +1857,8 @@ linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 
 retry:
 
-  /* Make sure there is at least one LWP that has been resumed, at
-     least if there are any LWPs at all.  */
-  gdb_assert (num_lwps == 0 || iterate_over_lwps (resumed_callback, NULL));
+  /* Make sure there is at least one LWP that has been resumed.  */
+  gdb_assert (iterate_over_lwps (resumed_callback, NULL));
 
   /* First check if there is a LWP with a wait status pending.  */
   if (pid == -1)
@@ -2159,23 +1997,20 @@ retry:
              if (options & __WCLONE)
                lp->cloned = 1;
 
-             if (threaded)
-               {
-                 gdb_assert (WIFSTOPPED (status)
-                             && WSTOPSIG (status) == SIGSTOP);
-                 lp->signalled = 1;
-
-                 if (!in_thread_list (inferior_ptid))
-                   {
-                     inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
-                                                GET_PID (inferior_ptid));
-                     add_thread (inferior_ptid);
-                   }
+             gdb_assert (WIFSTOPPED (status)
+                         && WSTOPSIG (status) == SIGSTOP);
+             lp->signalled = 1;
 
-                 add_thread (lp->ptid);
-                 printf_unfiltered (_("[New %s]\n"),
-                                    target_pid_to_str (lp->ptid));
+             if (!in_thread_list (inferior_ptid))
+               {
+                 inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
+                                            GET_PID (inferior_ptid));
+                 add_thread (inferior_ptid);
                }
+
+             add_thread (lp->ptid);
+             printf_unfiltered (_("[New %s]\n"),
+                                target_pid_to_str (lp->ptid));
            }
 
          /* Handle GNU/Linux's extended waitstatus for trace events.  */
@@ -2377,12 +2212,9 @@ retry:
      the comment in cancel_breakpoints_callback to find out why.  */
   iterate_over_lwps (cancel_breakpoints_callback, lp);
 
-  /* If we're not running in "threaded" mode, we'll report the bare
-     process id.  */
-
   if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
     {
-      trap_ptid = (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+      trap_ptid = lp->ptid;
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
                            "LLW: trap_ptid is %s.\n",
@@ -2399,7 +2231,7 @@ retry:
   else
     store_waitstatus (ourstatus, status);
 
-  return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+  return lp->ptid;
 }
 
 static int
@@ -2464,20 +2296,35 @@ kill_wait_callback (struct lwp_info *lp, void *data)
 static void
 linux_nat_kill (void)
 {
-  /* Kill all LWP's ...  */
-  iterate_over_lwps (kill_callback, NULL);
+  struct target_waitstatus last;
+  ptid_t last_ptid;
+  int status;
 
-  /* ... and wait until we've flushed all events.  */
-  iterate_over_lwps (kill_wait_callback, NULL);
+  /* 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.  */
 
-  target_mourn_inferior ();
-}
+  get_last_target_status (&last_ptid, &last);
 
-static void
-linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
-                        int from_tty)
-{
-  linux_ops->to_create_inferior (exec_file, allargs, env, from_tty);
+  if (last.kind == TARGET_WAITKIND_FORKED
+      || last.kind == TARGET_WAITKIND_VFORKED)
+    {
+      ptrace (PT_KILL, last.value.related_pid, 0, 0);
+      wait (&status);
+    }
+
+  if (forks_exist_p ())
+    linux_fork_killall ();
+  else
+    {
+      /* Kill all LWP's ...  */
+      iterate_over_lwps (kill_callback, NULL);
+
+      /* ... and wait until we've flushed all events.  */
+      iterate_over_lwps (kill_wait_callback, NULL);
+    }
+
+  target_mourn_inferior ();
 }
 
 static void
@@ -2492,7 +2339,14 @@ linux_nat_mourn_inferior (void)
   sigprocmask (SIG_SETMASK, &normal_mask, NULL);
   sigemptyset (&blocked_mask);
 
-  linux_ops->to_mourn_inferior ();
+  if (! forks_exist_p ())
+    /* Normal case, no other forks available.  */
+    linux_ops->to_mourn_inferior ();
+  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 ();
 }
 
 static LONGEST
@@ -2537,7 +2391,7 @@ linux_nat_pid_to_str (ptid_t ptid)
 {
   static char buf[64];
 
-  if (is_lwp (ptid))
+  if (lwp_list && lwp_list->next && is_lwp (ptid))
     {
       snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid));
       return buf;
@@ -2546,59 +2400,6 @@ 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)
-{
-#if 0
-  linux_nat_ops.to_open = linux_nat_open;
-#endif
-  linux_nat_ops.to_shortname = "lwp-layer";
-  linux_nat_ops.to_longname = "lwp-layer";
-  linux_nat_ops.to_doc = "Low level threads support (LWP layer)";
-  linux_nat_ops.to_attach = linux_nat_attach;
-  linux_nat_ops.to_detach = linux_nat_detach;
-  linux_nat_ops.to_resume = linux_nat_resume;
-  linux_nat_ops.to_wait = linux_nat_wait;
-  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
-    = 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;
-  linux_nat_ops.to_insert_exec_catchpoint = child_insert_exec_catchpoint;
-
-  linux_nat_ops.to_stratum = thread_stratum;
-  linux_nat_ops.to_has_thread_control = tc_schedlock;
-  linux_nat_ops.to_magic = OPS_MAGIC;
-}
-
 static void
 sigchld_handler (int signo)
 {
@@ -3310,8 +3111,6 @@ linux_target (void)
 #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;
@@ -3325,18 +3124,50 @@ linux_target (void)
   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
+linux_nat_add_target (struct target_ops *t)
+{
+  extern void thread_db_init (struct target_ops *);
+
+  /* Save the provided single-threaded target.  We save this in a separate
+     variable because another target we've inherited from (e.g. inf-ptrace)
+     may have saved a pointer to T; we want to use it for the final
+     process stratum target.  */
+  linux_ops_saved = *t;
+  linux_ops = &linux_ops_saved;
+
+  /* Override some methods for multithreading.  */
+  t->to_attach = linux_nat_attach;
+  t->to_detach = linux_nat_detach;
+  t->to_resume = linux_nat_resume;
+  t->to_wait = linux_nat_wait;
+  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_has_thread_control = tc_schedlock;
+
+  /* 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
+     target, but we want to be on the stack below thread_db, and we
+     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);
+}
+
 void
 _initialize_linux_nat (void)
 {
   struct sigaction action;
-  extern void thread_db_init (struct target_ops *);
 
   add_info ("proc", linux_nat_info_proc_cmd, _("\
 Show /proc process information about any running process.\n\
@@ -3347,10 +3178,6 @@ Specify any of the following keywords for detailed info:\n\
   status   -- list a different bunch of random process info.\n\
   all      -- list all available /proc info."));
 
-  init_linux_nat_ops ();
-  add_target (&linux_nat_ops);
-  thread_db_init (&linux_nat_ops);
-
   /* Save the original signal mask.  */
   sigprocmask (SIG_SETMASK, NULL, &normal_mask);
 
index 92003c9694d450ca8ae8e7a90859090f153fb20c..ecfaab70e955dd86916377da5876286baf258485 100644 (file)
@@ -1,6 +1,6 @@
 /* Native debugging support for GNU/Linux (LWP layer).
 
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -83,3 +83,11 @@ struct lwp_info *iterate_over_lwps (int (*callback) (struct lwp_info *,
 /* Create a prototype generic Linux target.  The client can override
    it with local methods.  */
 struct target_ops * linux_target (void);
+
+/* Register the customized Linux target.  This should be used
+   instead of calling add_target directly.  */
+void linux_nat_add_target (struct target_ops *);
+
+/* Update linux-nat internal state when changing from one fork
+   to another.  */
+void linux_nat_switch_fork (ptid_t new_ptid);
index bfe6435b3d416011244de99265e3f5b1d282ed94..454147b27aa7f2a478f32f2438696b721598e11b 100644 (file)
@@ -1,6 +1,6 @@
 /* Native-dependent code for GNU/Linux m32r.
 
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -250,5 +250,5 @@ _initialize_m32r_linux_nat (void)
   t->to_store_registers = m32r_linux_store_inferior_registers;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 }
index 777330c1ac06647821f40a9dec21ed06114eefb5..0da875e4c168639e85df370a36013d25f62e2f94 100644 (file)
@@ -1,6 +1,6 @@
 /* Motorola m68k native support for GNU/Linux.
 
-   Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -633,7 +633,7 @@ _initialize_m68k_linux_nat (void)
   t->to_store_registers = m68k_linux_store_inferior_registers;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 
   deprecated_add_core_fns (&linux_elf_core_fns);
 }
index 985ff2781d34f3a97618e256f7fda91cba7d3aa2..7796146ddc8ed287a9aeee026e8fb07058666513 100644 (file)
@@ -259,5 +259,5 @@ _initialize_mips_linux_nat (void)
   t->to_fetch_registers = mips64_linux_fetch_registers;
   t->to_store_registers = mips64_linux_store_registers;
 
-  add_target (t);
+  linux_nat_add_target (t);
 }
index d4f8c585e5f3d9278c98f6257d00fc98994ecbcf..769786255a11e0d2c3b734549e9f82320e3f2694 100644 (file)
@@ -1037,5 +1037,5 @@ _initialize_ppc_linux_nat (void)
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 }
index 24ff73f48bdbc8cfa481f34817204a8d60280aec..885c3c5ccfb8ad66b18680c15af8fda3853f7481 100644 (file)
@@ -388,5 +388,5 @@ _initialize_s390_nat (void)
   t->to_remove_watchpoint = s390_remove_watchpoint;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 }
index 9ad30a86d47f9cce56826d3a265d7e4e61dade7e..a234402fd786d754bc058ff5a50796d4b96d6673 100644 (file)
@@ -1,5 +1,5 @@
 /* Native-dependent code for GNU/Linux SPARC.
-   Copyright (C) 2005
+   Copyright (C) 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -39,5 +39,5 @@ _initialize_sparc_linux_nat (void)
   t->to_store_registers = store_inferior_registers;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 }
index 84ff73998fa1a5041786d2af810dd28a8f236719..730d4f9b3f86f8893e41cdd3d3e3e93401fb7cae 100644 (file)
@@ -1,6 +1,6 @@
 /* Native-dependent code for GNU/Linux UltraSPARC.
 
-   Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -57,7 +57,7 @@ _initialize_sparc64_linux_nat (void)
   t->to_store_registers = store_inferior_registers;
 
   /* Register the target.  */
-  add_target (t);
+  linux_nat_add_target (t);
 
   sparc_gregset = &sparc64_linux_ptrace_gregset;
 }