Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* RFC: Unify the GNU/Linux native targets
@ 2006-02-27 19:44 Daniel Jacobowitz
  2006-02-27 20:40 ` Mark Kettenis
  2006-03-11  1:44 ` Michael Snyder
  0 siblings, 2 replies; 5+ messages in thread
From: Daniel Jacobowitz @ 2006-02-27 19:44 UTC (permalink / raw)
  To: gdb-patches

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;
 \f
 
 #define GET_LWP(ptid)		ptid_get_lwp (ptid)
@@ -703,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
@@ -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) \


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Unify the GNU/Linux native targets
  2006-02-27 19:44 RFC: Unify the GNU/Linux native targets Daniel Jacobowitz
@ 2006-02-27 20:40 ` Mark Kettenis
  2006-02-27 20:51   ` Daniel Jacobowitz
  2006-03-11  1:44 ` Michael Snyder
  1 sibling, 1 reply; 5+ messages in thread
From: Mark Kettenis @ 2006-02-27 20:40 UTC (permalink / raw)
  To: gdb-patches

> Date: Mon, 27 Feb 2006 14:28:07 -0500
> From: Daniel Jacobowitz <drow@false.org>
> 
> 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.

What does this mean for running GDB on older Linux kernels?  (Dropping
support for older kernels isn't necessarily bad, as long as we still
support Linux 2.4, but we should document it somehow).

> 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.

Cool!

> 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.

That isn't necessarily a bad thing; inf_ttrace() is also inherently
multi-threaded.  I think the single-threaded/multi-threaded dichotomy
really isn't the right way to view this.  It's more a
kernel-threads/user-level-threads dichotomy.  Of course Linux is
somewhere halfway between this, since it is (still) impossible to ask
the kernel what LWP's belong to a particular process.

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

I have one request; could you rename set_linux_target() to
linux_nat_add_target().  I think that better expresses the fact that
this function actually is the Linux native specific version of
add_target.

> 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.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Unify the GNU/Linux native targets
  2006-02-27 20:40 ` Mark Kettenis
@ 2006-02-27 20:51   ` Daniel Jacobowitz
  0 siblings, 0 replies; 5+ messages in thread
From: Daniel Jacobowitz @ 2006-02-27 20:51 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: gdb-patches

On Mon, Feb 27, 2006 at 09:36:25PM +0100, Mark Kettenis wrote:
> What does this mean for running GDB on older Linux kernels?  (Dropping
> support for older kernels isn't necessarily bad, as long as we still
> support Linux 2.4, but we should document it somehow).

Nothing at all.  There should be no functionality change with this
patch, nor does it imply removing anything.

It would make it simpler to add support for clone debugging without
libthread_db, if someone wanted to work on that, though - and that will
require 2.6.

> That isn't necessarily a bad thing; inf_ttrace() is also inherently
> multi-threaded.  I think the single-threaded/multi-threaded dichotomy
> really isn't the right way to view this.  It's more a
> kernel-threads/user-level-threads dichotomy.

Yes, I agree.

> Of course Linux is
> somewhere halfway between this, since it is (still) impossible to ask
> the kernel what LWP's belong to a particular process.

Eh?  No, that's not true with NPTL.

drow@caradoc:~% pidof firefox-bin    
8984
drow@caradoc:~% ls /proc/8984/task
18696/  6171/  6172/  6173/  8984/  8989/  8990/
drow@caradoc:~% grep Tgid /proc/6171/status
Tgid:   8984

> > Tested on x86_64-pc-linux-gnu.  Any comments?  Seems like progress?
> 
> I have one request; could you rename set_linux_target() to
> linux_nat_add_target().  I think that better expresses the fact that
> this function actually is the Linux native specific version of
> add_target.

Sure, I'll rename it.

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Unify the GNU/Linux native targets
  2006-02-27 19:44 RFC: Unify the GNU/Linux native targets Daniel Jacobowitz
  2006-02-27 20:40 ` Mark Kettenis
@ 2006-03-11  1:44 ` Michael Snyder
  2006-03-25  0:06   ` Daniel Jacobowitz
  1 sibling, 1 reply; 5+ messages in thread
From: Michael Snyder @ 2006-03-11  1:44 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches

Daniel Jacobowitz wrote:
> 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, this seems fairly sane, at least with respect to forks.
It does touch code that is also touched by my recent patch,
though, so merge carefully.   ;-)

This, for instance,

+
+  /* 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 ...  */

would want to be modified so as to read something like:

	linux_fork_killall ();
	target_mourn_inferior ();
	return;

(I think...)


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Unify the GNU/Linux native targets
  2006-03-11  1:44 ` Michael Snyder
@ 2006-03-25  0:06   ` Daniel Jacobowitz
  0 siblings, 0 replies; 5+ messages in thread
From: Daniel Jacobowitz @ 2006-03-25  0:06 UTC (permalink / raw)
  To: Michael Snyder; +Cc: gdb-patches

On Fri, Mar 10, 2006 at 12:05:53PM -0800, Michael Snyder wrote:
> Daniel, this seems fairly sane, at least with respect to forks.
> It does touch code that is also touched by my recent patch,
> though, so merge carefully.   ;-)

Yep, one conflict.  Committed as attached.

-- 
Daniel Jacobowitz
CodeSourcery

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.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.794
diff -u -p -r1.794 Makefile.in
--- Makefile.in	24 Mar 2006 22:44:05 -0000	1.794
+++ Makefile.in	24 Mar 2006 22:48:15 -0000
@@ -2190,7 +2190,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: alpha-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/alpha-linux-nat.c,v
retrieving revision 1.2
diff -u -p -r1.2 alpha-linux-nat.c
--- alpha-linux-nat.c	17 Dec 2005 22:33:59 -0000	1.2
+++ alpha-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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 ());
+  linux_nat_add_target (linux_target ());
 }
Index: amd64-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/amd64-linux-nat.c,v
retrieving revision 1.11
diff -u -p -r1.11 amd64-linux-nat.c
--- amd64-linux-nat.c	17 Dec 2005 22:33:59 -0000	1.11
+++ amd64-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: arm-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v
retrieving revision 1.25
diff -u -p -r1.25 arm-linux-nat.c
--- arm-linux-nat.c	17 Dec 2005 22:33:59 -0000	1.25
+++ arm-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: hppa-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-linux-nat.c,v
retrieving revision 1.12
diff -u -p -r1.12 hppa-linux-nat.c
--- hppa-linux-nat.c	17 Dec 2005 22:34:00 -0000	1.12
+++ hppa-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: i386-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v
retrieving revision 1.68
diff -u -p -r1.68 i386-linux-nat.c
--- i386-linux-nat.c	17 Dec 2005 22:34:01 -0000	1.68
+++ i386-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: ia64-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-linux-nat.c,v
retrieving revision 1.30
diff -u -p -r1.30 ia64-linux-nat.c
--- ia64-linux-nat.c	17 Dec 2005 22:34:01 -0000	1.30
+++ ia64-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: linux-fork.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-fork.c,v
retrieving revision 1.5
diff -u -p -r1.5 linux-fork.c
--- linux-fork.c	24 Mar 2006 22:44:05 -0000	1.5
+++ linux-fork.c	24 Mar 2006 22:48:15 -0000
@@ -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
 
   inferior_ptid = fp->ptid;
 
+  linux_nat_switch_fork (inferior_ptid);
+
   if (fp->savedregs && fp->clobber_regs)
     regcache_cpy (current_regcache, fp->savedregs);
 
Index: linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.39
diff -u -p -r1.39 linux-nat.c
--- linux-nat.c	10 Mar 2006 20:15:42 -0000	1.39
+++ linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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,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) (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
@@ -1046,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
@@ -1848,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
@@ -2007,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.  */
@@ -2018,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)
@@ -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,
 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;
@@ -2547,59 +2401,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
@@ -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 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: linux-nat.h
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.h,v
retrieving revision 1.9
diff -u -p -r1.9 linux-nat.h
--- linux-nat.h	17 Dec 2005 22:34:01 -0000	1.9
+++ linux-nat.h	24 Mar 2006 22:48:15 -0000
@@ -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 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: m32r-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/m32r-linux-nat.c,v
retrieving revision 1.4
diff -u -p -r1.4 m32r-linux-nat.c
--- m32r-linux-nat.c	17 Dec 2005 22:34:01 -0000	1.4
+++ m32r-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: m68klinux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/m68klinux-nat.c,v
retrieving revision 1.30
diff -u -p -r1.30 m68klinux-nat.c
--- m68klinux-nat.c	17 Dec 2005 22:34:01 -0000	1.30
+++ m68klinux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: mips-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-linux-nat.c,v
retrieving revision 1.13
diff -u -p -r1.13 mips-linux-nat.c
--- mips-linux-nat.c	15 Mar 2006 17:13:36 -0000	1.13
+++ mips-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: ppc-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-linux-nat.c,v
retrieving revision 1.59
diff -u -p -r1.59 ppc-linux-nat.c
--- ppc-linux-nat.c	26 Feb 2006 23:42:59 -0000	1.59
+++ ppc-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: s390-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/s390-nat.c,v
retrieving revision 1.18
diff -u -p -r1.18 s390-nat.c
--- s390-nat.c	8 Feb 2006 07:00:06 -0000	1.18
+++ s390-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: sparc-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/sparc-linux-nat.c,v
retrieving revision 1.8
diff -u -p -r1.8 sparc-linux-nat.c
--- sparc-linux-nat.c	17 Dec 2005 22:34:02 -0000	1.8
+++ sparc-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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: sparc64-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/sparc64-linux-nat.c,v
retrieving revision 1.4
diff -u -p -r1.4 sparc64-linux-nat.c
--- sparc64-linux-nat.c	17 Dec 2005 22:34:02 -0000	1.4
+++ sparc64-linux-nat.c	24 Mar 2006 22:48:15 -0000
@@ -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;
 }


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2006-03-24 23:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-02-27 19:44 RFC: Unify the GNU/Linux native targets Daniel Jacobowitz
2006-02-27 20:40 ` Mark Kettenis
2006-02-27 20:51   ` Daniel Jacobowitz
2006-03-11  1:44 ` Michael Snyder
2006-03-25  0:06   ` Daniel Jacobowitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox