This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: Unify the GNU/Linux native targets


A wart I've been meaning to come back to for ages; I have some fixes for
thread debugging in static binaries that would have been quite ugly
without this, so I took a day to do it.

There are two target vectors in the current incarnation of linux-nat.c.  The
one returned by linux_target () and inherited by target-specific files is
used for non-threaded applications; it handles basic operations including
target-specific extensions to them.  The one built in linux_nat_ops
handles clone and can be used with libthread_db, and delegates to the
single-threaded variant for basic tasks.

This is a bit silly :-)  We still need the separation between single and
multi-threaded vectors for the moment, because targets want to override
the single-threaded primitives rather than the complex multi-threaded
layer.  However, that's all we need the single-threaded vector for.  We
don't ever need to _use_ it.

This patch kills most of the single-threaded vector and arranges to
use the multi-threaded version in all cases.  Some duplicated code
goes away, and it is suddenly much easier to switch back and forth
between "threaded" and "non-threaded" debugging.

One oddity: the Linux native target remains at process_stratum even
though it supports threads.  I think this is right; the thread_stratum
gets used for linux-thread-db.c support which delegates to the process
stratum.  If we had arbitrary stacking instead of strata I might
stack the linux multithreaded bits above the linux single-threaded
bits, but I think this is more natural.

Tested on x86_64-pc-linux-gnu.  Any comments?  Seems like progress?

Depends on my previous linux-fork.c patch, but only trivially.

-- 
Daniel Jacobowitz
CodeSourcery

2006-02-27  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.
	(set_linux_target): New.
	(_initialize_linux_nat): Don't initialize the linux native target
	here.
	* linux-nat.h (set_linux_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
	set_linux_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.

Index: src/gdb/i386-linux-nat.c
===================================================================
--- src.orig/gdb/i386-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/i386-linux-nat.c	2006-02-27 12:56:15.000000000 -0500
@@ -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);
+  set_linux_target (t);
 }
Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/linux-nat.c	2006-02-27 12:47:52.000000000 -0500
@@ -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) (st
 				      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,56 +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 ();
-      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.  */
-
-      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
@@ -688,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;
 
 
 #define GET_LWP(ptid)		ptid_get_lwp (ptid)
@@ -703,9 +647,6 @@ static int threaded;
 ptid_t trap_ptid;
 
 
-/* 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
@@ -770,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)
@@ -794,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;
 }
@@ -816,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)
@@ -869,6 +805,21 @@ iterate_over_lwps (int (*callback) (stru
   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
@@ -1048,7 +999,8 @@ linux_nat_attach (char *args, int from_t
   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
@@ -1850,134 +1802,6 @@ resumed_callback (struct lwp_info *lp, v
   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
@@ -2009,6 +1833,19 @@ linux_nat_wait (ptid_t ptid, struct targ
   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.  */
@@ -2020,9 +1857,8 @@ linux_nat_wait (ptid_t ptid, struct targ
 
 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)
@@ -2161,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.  */
@@ -2379,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",
@@ -2401,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
@@ -2466,6 +2296,32 @@ kill_wait_callback (struct lwp_info *lp,
 static void
 linux_nat_kill (void)
 {
+  struct target_waitstatus last;
+  ptid_t last_ptid;
+  int status;
+
+  /* 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);
+    }
+
+  /* First cut -- let's crudely do everything inline.  */
+  if (forks_exist_p ())
+    {
+      linux_fork_killall ();
+      pop_target ();
+      generic_mourn_inferior ();
+      return;
+    }
+
   /* Kill all LWP's ...  */
   iterate_over_lwps (kill_callback, NULL);
 
@@ -2476,13 +2332,6 @@ linux_nat_kill (void)
 }
 
 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);
-}
-
-static void
 linux_nat_mourn_inferior (void)
 {
   trap_ptid = null_ptid;
@@ -2494,7 +2343,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
@@ -2539,7 +2395,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;
@@ -2549,59 +2405,6 @@ linux_nat_pid_to_str (ptid_t 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)
 {
   /* Do nothing.  The only reason for this handler is that it allows
@@ -3312,8 +3115,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;
@@ -3327,18 +3128,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
+set_linux_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\
@@ -3349,10 +3182,6 @@ Specify any of the following keywords fo
   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: src/gdb/linux-nat.h
===================================================================
--- src.orig/gdb/linux-nat.h	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/linux-nat.h	2006-02-27 12:56:19.000000000 -0500
@@ -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 
 /* 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 set_linux_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: src/gdb/alpha-linux-nat.c
===================================================================
--- src.orig/gdb/alpha-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/alpha-linux-nat.c	2006-02-27 12:56:21.000000000 -0500
@@ -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 (voi
 void
 _initialize_alpha_linux_nat (void)
 {
-  add_target (linux_target ());
+  set_linux_target (linux_target ());
 }
Index: src/gdb/amd64-linux-nat.c
===================================================================
--- src.orig/gdb/amd64-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/amd64-linux-nat.c	2006-02-27 12:56:29.000000000 -0500
@@ -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);
+  set_linux_target (t);
 }
Index: src/gdb/arm-linux-nat.c
===================================================================
--- src.orig/gdb/arm-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/arm-linux-nat.c	2006-02-27 12:56:33.000000000 -0500
@@ -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);
+  set_linux_target (t);
 }
Index: src/gdb/hppa-linux-nat.c
===================================================================
--- src.orig/gdb/hppa-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/hppa-linux-nat.c	2006-02-27 12:56:37.000000000 -0500
@@ -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);
+  set_linux_target (t);
 }
Index: src/gdb/ia64-linux-nat.c
===================================================================
--- src.orig/gdb/ia64-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/ia64-linux-nat.c	2006-02-27 12:56:40.000000000 -0500
@@ -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);
+  set_linux_target (t);
 }
Index: src/gdb/m32r-linux-nat.c
===================================================================
--- src.orig/gdb/m32r-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/m32r-linux-nat.c	2006-02-27 12:56:44.000000000 -0500
@@ -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);
+  set_linux_target (t);
 }
Index: src/gdb/m68klinux-nat.c
===================================================================
--- src.orig/gdb/m68klinux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/m68klinux-nat.c	2006-02-27 12:56:48.000000000 -0500
@@ -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);
+  set_linux_target (t);
 
   deprecated_add_core_fns (&linux_elf_core_fns);
 }
Index: src/gdb/mips-linux-nat.c
===================================================================
--- src.orig/gdb/mips-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/mips-linux-nat.c	2006-02-27 12:56:55.000000000 -0500
@@ -1,6 +1,7 @@
 /* Native-dependent code for GNU/Linux on MIPS processors.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -70,5 +71,5 @@ void _initialize_mips_linux_nat (void);
 void
 _initialize_mips_linux_nat (void)
 {
-  add_target (linux_target ());
+  set_linux_target (linux_target ());
 }
Index: src/gdb/ppc-linux-nat.c
===================================================================
--- src.orig/gdb/ppc-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/ppc-linux-nat.c	2006-02-27 12:44:45.000000000 -0500
@@ -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);
+  set_linux_target (t);
 }
Index: src/gdb/s390-nat.c
===================================================================
--- src.orig/gdb/s390-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/s390-nat.c	2006-02-27 12:44:45.000000000 -0500
@@ -388,5 +388,5 @@ _initialize_s390_nat (void)
   t->to_remove_watchpoint = s390_remove_watchpoint;
 
   /* Register the target.  */
-  add_target (t);
+  set_linux_target (t);
 }
Index: src/gdb/sparc-linux-nat.c
===================================================================
--- src.orig/gdb/sparc-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/sparc-linux-nat.c	2006-02-27 12:57:02.000000000 -0500
@@ -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);
+  set_linux_target (t);
 }
Index: src/gdb/sparc64-linux-nat.c
===================================================================
--- src.orig/gdb/sparc64-linux-nat.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/sparc64-linux-nat.c	2006-02-27 12:57:05.000000000 -0500
@@ -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);
+  set_linux_target (t);
 
   sparc_gregset = &sparc64_linux_ptrace_gregset;
 }
Index: src/gdb/linux-fork.c
===================================================================
--- src.orig/gdb/linux-fork.c	2006-02-27 12:44:42.000000000 -0500
+++ src/gdb/linux-fork.c	2006-02-27 12:44:45.000000000 -0500
@@ -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>
@@ -85,7 +86,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;
@@ -242,6 +243,8 @@ fork_load_infrun_state (struct fork_info
 
   inferior_ptid = fp->ptid;
 
+  linux_nat_switch_fork (inferior_ptid);
+
   if (fp->savedregs && fp->clobber_regs)
     regcache_cpy (current_regcache, fp->savedregs);
 
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2006-02-27 12:44:41.000000000 -0500
+++ src/gdb/Makefile.in	2006-02-27 14:16:21.000000000 -0500
@@ -2188,7 +2188,8 @@ linespec.o: linespec.c $(defs_h) $(symta
 	$(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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]