summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jacobowitz <dan@debian.org>2006-03-24 23:08:16 +0000
committerDaniel Jacobowitz <dan@debian.org>2006-03-24 23:08:16 +0000
commit1a97c76ee0fc8202bc42e95fcd64c56a866a5344 (patch)
treef8a7a3ccb4fb31e4b5cc30a65720af39c9fb2a93
parent56e6302ac87ce280352297bc5298e9bdc489f8bf (diff)
downloadgdb-1a97c76ee0fc8202bc42e95fcd64c56a866a5344.tar.gz
* 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.
-rw-r--r--gdb/ChangeLog44
-rw-r--r--gdb/Makefile.in3
-rw-r--r--gdb/alpha-linux-nat.c4
-rw-r--r--gdb/amd64-linux-nat.c5
-rw-r--r--gdb/arm-linux-nat.c4
-rw-r--r--gdb/hppa-linux-nat.c4
-rw-r--r--gdb/i386-linux-nat.c4
-rw-r--r--gdb/ia64-linux-nat.c4
-rw-r--r--gdb/linux-fork.c5
-rw-r--r--gdb/linux-nat.c417
-rw-r--r--gdb/linux-nat.h10
-rw-r--r--gdb/m32r-linux-nat.c4
-rw-r--r--gdb/m68klinux-nat.c4
-rw-r--r--gdb/mips-linux-nat.c2
-rw-r--r--gdb/ppc-linux-nat.c2
-rw-r--r--gdb/s390-nat.c2
-rw-r--r--gdb/sparc-linux-nat.c4
-rw-r--r--gdb/sparc64-linux-nat.c4
18 files changed, 205 insertions, 321 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index bf4c68d0adc..d982e29246e 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,49 @@
2006-03-24 Daniel Jacobowitz <dan@codesourcery.com>
+ * linux-nat.c (linux_ops_saved): New.
+ (super_mourn_inferior, kill_inferior, threaded, linux_nat_ops)
+ (child_mourn_inferior, child_wait, linux_nat_create_inferior)
+ (linux_nat_fetch_registers, linux_nat_store_registers)
+ (linux_nat_child_post_startup_inferior, init_linux_nat_ops): Delete.
+ (init_lwp_list): Don't set threaded.
+ (add_lwp): Don't modify threaded.
+ (delete_lwp): Don't mention non-threaded mode.
+ (linux_nat_switch_fork): New.
+ (linux_nat_attach): Update inferior_ptid.
+ (linux_nat_wait): Handle num_lwps == 0 at entry. Don't check
+ threaded flag.
+ (linux_nat_kill): Handle pending forks and saved forks.
+ (linux_nat_mourn_inferior): Handle saved forks.
+ (linux_nat_pid_to_str): Don't use the LWP form when there is
+ only one thread.
+ (linux_target): Don't set to_wait, to_kill, or to_mourn_inferior.
+ (linux_nat_add_target): New.
+ (_initialize_linux_nat): Don't initialize the linux native target
+ here.
+ * linux-nat.h (linux_nat_add_target, linux_nat_switch_fork): New
+ prototypes.
+ * linux-fork.c: Include "linux-nat.h".
+ (add_fork): Update initial PID.
+ (fork_load_infrun_state): Call linux_nat_switch_fork.
+ * Makefile.in (linux-fork.o): Update.
+
+ * alpha-linux-nat.c (_initialize_alpha_linux_nat): Use
+ linux_nat_add_target instead of add_target.
+ * amd64-linux-nat.c (_initialize_amd64_linux_nat): Likewise.
+ * arm-linux-nat.c (_initialize_arm_linux_nat): Likewise.
+ * hppa-linux-nat.c (_initialize_hppa_linux_nat): Likewise.
+ * ia64-linux-nat.c (_initialize_ia64_linux_nat): Likewise.
+ * i386-linux-nat.c (_initialize_i386_linux_nat): Likewise.
+ * m32r-linux-nat.c (_initialize_m32r_linux_nat): Likewise.
+ * m68klinux-nat.c (_initialize_m68k_linux_nat): Likewise.
+ * mips-linux-nat.c (_initialize_mips_linux_nat): Likewise.
+ * ppc-linux-nat.c (_initialize_ppc_linux_nat): Likewise.
+ * s390-nat.c (_initialize_s390_nat): Likewise.
+ * sparc-linux-nat.c (_initialize_sparc_linux_nat): Likewise.
+ * sparc64-linux-nat.c (_initialize_sparc64_linux_nat): Likewise.
+
+2006-03-24 Daniel Jacobowitz <dan@codesourcery.com>
+
* linux-fork.c: Include "gdb_assert.h".
(fork_load_infrun_state): Set inferior_ptid and stop_pc here.
Update the register cache and selected frame also.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 29aa218a37a..1ad9738eef5 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -2190,7 +2190,8 @@ linespec.o: linespec.c $(defs_h) $(symtab_h) $(frame_h) $(command_h) \
$(completer_h) $(cp_abi_h) $(parser_defs_h) $(block_h) \
$(objc_lang_h) $(linespec_h) $(exceptions_h)
linux-fork.o: linux-fork.c $(defs_h) $(inferior_h) $(regcache_h) $(gdbcmd_h) \
- $(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_h)
+ $(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_h) \
+ $(linux_nat_h)
linux-nat.o: linux-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdb_string_h) \
$(gdb_wait_h) $(gdb_assert_h) $(linux_nat_h) $(gdbthread_h) \
$(gdbcmd_h) $(regcache_h) $(inf_ptrace.h) $(auxv.h) $(elf_bfd_h) \
diff --git a/gdb/alpha-linux-nat.c b/gdb/alpha-linux-nat.c
index c8559921ec7..183a7a41253 100644
--- a/gdb/alpha-linux-nat.c
+++ b/gdb/alpha-linux-nat.c
@@ -1,5 +1,5 @@
/* Low level Alpha GNU/Linux interface, for GDB when running native.
- Copyright (C) 2005
+ Copyright (C) 2005, 2006
Free Software Foundation, Inc.
This file is part of GDB.
@@ -28,5 +28,5 @@ void _initialialize_alpha_linux_nat (void);
void
_initialize_alpha_linux_nat (void)
{
- add_target (linux_target ());
+ linux_nat_add_target (linux_target ());
}
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index 8fa6df9ab82..b4a71125a3e 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -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);
}
diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c
index 16298cc284b..8023026a209 100644
--- a/gdb/arm-linux-nat.c
+++ b/gdb/arm-linux-nat.c
@@ -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);
}
diff --git a/gdb/hppa-linux-nat.c b/gdb/hppa-linux-nat.c
index 48ad5335d47..394c46d7b66 100644
--- a/gdb/hppa-linux-nat.c
+++ b/gdb/hppa-linux-nat.c
@@ -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);
}
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 8fbbd4fcc27..05501e214e3 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -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);
}
diff --git a/gdb/ia64-linux-nat.c b/gdb/ia64-linux-nat.c
index 6de171b1c19..e2230815d1d 100644
--- a/gdb/ia64-linux-nat.c
+++ b/gdb/ia64-linux-nat.c
@@ -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);
}
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index 88bea6169ba..bb4468268c2 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -27,6 +27,7 @@
#include "gdb_assert.h"
#include "gdb_string.h"
#include "linux-fork.h"
+#include "linux-nat.h"
#include <sys/ptrace.h>
#include <sys/wait.h>
@@ -84,7 +85,7 @@ add_fork (pid_t pid)
}
fp = XZALLOC (struct fork_info);
- fp->ptid = pid_to_ptid (pid);
+ fp->ptid = ptid_build (pid, pid, 0);
fp->num = ++highest_fork_num;
fp->next = fork_list;
fork_list = fp;
@@ -241,6 +242,8 @@ fork_load_infrun_state (struct fork_info *fp)
inferior_ptid = fp->ptid;
+ linux_nat_switch_fork (inferior_ptid);
+
if (fp->savedregs && fp->clobber_regs)
regcache_cpy (current_regcache, fp->savedregs);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 2ba5d7d1647..88e0d7d24d9 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -88,6 +88,7 @@
/* The single-threaded native GNU/Linux target_ops. We save a pointer for
the use of the multi-threaded target. */
static struct target_ops *linux_ops;
+static struct target_ops linux_ops_saved;
/* The saved to_xfer_partial method, inherited from inf-ptrace.c.
Called by our to_xfer_partial. */
@@ -97,10 +98,6 @@ static LONGEST (*super_xfer_partial) (struct target_ops *,
const gdb_byte *,
ULONGEST, LONGEST);
-/* The saved to_mourn_inferior method, inherited from inf-ptrace.c.
- Called by our to_mourn_inferior. */
-static void (*super_mourn_inferior) (void);
-
static int debug_linux_nat;
static void
show_debug_linux_nat (struct ui_file *file, int from_tty,
@@ -600,54 +597,6 @@ child_insert_exec_catchpoint (int pid)
error (_("Your system does not support exec catchpoints."));
}
-void
-kill_inferior (void)
-{
- int status;
- int pid = PIDGET (inferior_ptid);
- struct target_waitstatus last;
- ptid_t last_ptid;
- int ret;
-
- if (pid == 0)
- return;
-
- /* First cut -- let's crudely do everything inline. */
- if (forks_exist_p ())
- {
- linux_fork_killall ();
- }
- else
- {
- /* If we're stopped while forking and we haven't followed yet,
- kill the other task. We need to do this first because the
- parent will be sleeping if this is a vfork. */
-
- get_last_target_status (&last_ptid, &last);
-
- if (last.kind == TARGET_WAITKIND_FORKED
- || last.kind == TARGET_WAITKIND_VFORKED)
- {
- ptrace (PT_KILL, last.value.related_pid, 0, 0);
- wait (&status);
- }
-
- /* Kill the current process. */
- ptrace (PT_KILL, pid, 0, 0);
- ret = wait (&status);
-
- /* We might get a SIGCHLD instead of an exit status. This is
- aggravated by the first kill above - a child has just died. */
-
- while (ret == pid && WIFSTOPPED (status))
- {
- ptrace (PT_KILL, pid, 0, 0);
- ret = wait (&status);
- }
- }
- target_mourn_inferior ();
-}
-
/* On GNU/Linux there are no real LWP's. The closest thing to LWP's
are processes sharing the same VM space. A multi-threaded process
is basically a group of such processes. However, such a grouping
@@ -686,9 +635,6 @@ static struct lwp_info *lwp_list;
/* Number of LWPs in the list. */
static int num_lwps;
-
-/* Non-zero if we're running in "threaded" mode. */
-static int threaded;
#define GET_LWP(ptid) ptid_get_lwp (ptid)
@@ -701,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
@@ -768,12 +711,10 @@ init_lwp_list (void)
lwp_list = NULL;
num_lwps = 0;
- threaded = 0;
}
-/* Add the LWP specified by PID to the list. If this causes the
- number of LWPs to become larger than one, go into "threaded" mode.
- Return a pointer to the structure describing the new LWP. */
+/* Add the LWP specified by PID to the list. Return a pointer to the
+ structure describing the new LWP. */
static struct lwp_info *
add_lwp (ptid_t ptid)
@@ -792,8 +733,7 @@ add_lwp (ptid_t ptid)
lp->next = lwp_list;
lwp_list = lp;
- if (++num_lwps > 1)
- threaded = 1;
+ ++num_lwps;
return lp;
}
@@ -814,8 +754,6 @@ delete_lwp (ptid_t ptid)
if (!lp)
return;
- /* We don't go back to "non-threaded" mode if the number of threads
- becomes less than two. */
num_lwps--;
if (lpprev)
@@ -867,6 +805,21 @@ iterate_over_lwps (int (*callback) (struct lwp_info *, void *), void *data)
return NULL;
}
+/* Update our internal state when changing from one fork (checkpoint,
+ et cetera) to another indicated by NEW_PTID. We can only switch
+ single-threaded applications, so we only create one new LWP, and
+ the previous list is discarded. */
+
+void
+linux_nat_switch_fork (ptid_t new_ptid)
+{
+ struct lwp_info *lp;
+
+ init_lwp_list ();
+ lp = add_lwp (new_ptid);
+ lp->stopped = 1;
+}
+
/* Record a PTID for later deletion. */
struct saved_ptids
@@ -1046,7 +999,8 @@ linux_nat_attach (char *args, int from_tty)
linux_ops->to_attach (args, from_tty);
/* Add the initial process as the first LWP to the list. */
- lp = add_lwp (BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid)));
+ inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
+ lp = add_lwp (inferior_ptid);
/* Make sure the initial process is stopped. The user-level threads
layer might want to poke around in the inferior, and that won't
@@ -1848,134 +1802,6 @@ resumed_callback (struct lwp_info *lp, void *data)
return lp->resumed;
}
-/* Local mourn_inferior -- we need to override mourn_inferior
- so that we can do something clever if one of several forks
- has exited. */
-
-static void
-child_mourn_inferior (void)
-{
- int status;
-
- if (! forks_exist_p ())
- {
- /* Normal case, no other forks available. */
- super_mourn_inferior ();
- return;
- }
- else
- {
- /* Multi-fork case. The current inferior_ptid has exited, but
- there are other viable forks to debug. Delete the exiting
- one and context-switch to the first available. */
- linux_fork_mourn_inferior ();
- }
-}
-
-/* We need to override child_wait to support attaching to cloned
- processes, since a normal wait (as done by the default version)
- ignores those processes. */
-
-/* Wait for child PTID to do something. Return id of the child,
- minus_one_ptid in case of error; store status into *OURSTATUS. */
-
-ptid_t
-child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
-{
- int save_errno;
- int status;
- pid_t pid;
-
- ourstatus->kind = TARGET_WAITKIND_IGNORE;
-
- do
- {
- set_sigint_trap (); /* Causes SIGINT to be passed on to the
- attached process. */
- set_sigio_trap ();
-
- pid = my_waitpid (GET_PID (ptid), &status, 0);
- if (pid == -1 && errno == ECHILD)
- /* Try again with __WCLONE to check cloned processes. */
- pid = my_waitpid (GET_PID (ptid), &status, __WCLONE);
-
- if (debug_linux_nat)
- {
- fprintf_unfiltered (gdb_stdlog,
- "CW: waitpid %ld received %s\n",
- (long) pid, status_to_str (status));
- }
-
- save_errno = errno;
-
- /* Make sure we don't report an event for the exit of the
- original program, if we've detached from it. */
- if (pid != -1 && !WIFSTOPPED (status) && pid != GET_PID (inferior_ptid))
- {
- pid = -1;
- save_errno = EINTR;
- }
-
- /* Check for stop events reported by a process we didn't already
- know about - in this case, anything other than inferior_ptid.
-
- If we're expecting to receive stopped processes after fork,
- vfork, and clone events, then we'll just add the new one to
- our list and go back to waiting for the event to be reported
- - the stopped process might be returned from waitpid before
- or after the event is. If we want to handle debugging of
- CLONE_PTRACE processes we need to do more here, i.e. switch
- to multi-threaded mode. */
- if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP
- && pid != GET_PID (inferior_ptid))
- {
- linux_record_stopped_pid (pid);
- pid = -1;
- save_errno = EINTR;
- }
-
- /* Handle GNU/Linux's extended waitstatus for trace events. */
- if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP
- && status >> 16 != 0)
- {
- linux_handle_extended_wait (pid, status, ourstatus);
-
- /* If we see a clone event, detach the child, and don't
- report the event. It would be nice to offer some way to
- switch into a non-thread-db based threaded mode at this
- point. */
- if (ourstatus->kind == TARGET_WAITKIND_SPURIOUS)
- {
- ptrace (PTRACE_DETACH, ourstatus->value.related_pid, 0, 0);
- ourstatus->kind = TARGET_WAITKIND_IGNORE;
- ptrace (PTRACE_CONT, pid, 0, 0);
- pid = -1;
- save_errno = EINTR;
- }
- }
-
- clear_sigio_trap ();
- clear_sigint_trap ();
- }
- while (pid == -1 && save_errno == EINTR);
-
- if (pid == -1)
- {
- warning (_("Child process unexpectedly missing: %s"),
- safe_strerror (errno));
-
- /* Claim it exited with unknown signal. */
- ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
- ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
- return minus_one_ptid;
- }
-
- if (ourstatus->kind == TARGET_WAITKIND_IGNORE)
- store_waitstatus (ourstatus, status);
-
- return pid_to_ptid (pid);
-}
-
/* Stop an active thread, verify it still exists, then resume it. */
static int
@@ -2007,6 +1833,19 @@ linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
pid_t pid = PIDGET (ptid);
sigset_t flush_mask;
+ /* The first time we get here after starting a new inferior, we may
+ not have added it to the LWP list yet - this is the earliest
+ moment at which we know its PID. */
+ if (num_lwps == 0)
+ {
+ gdb_assert (!is_lwp (inferior_ptid));
+
+ inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
+ GET_PID (inferior_ptid));
+ lp = add_lwp (inferior_ptid);
+ lp->resumed = 1;
+ }
+
sigemptyset (&flush_mask);
/* Make sure SIGCHLD is blocked. */
@@ -2018,9 +1857,8 @@ linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
retry:
- /* Make sure there is at least one LWP that has been resumed, at
- least if there are any LWPs at all. */
- gdb_assert (num_lwps == 0 || iterate_over_lwps (resumed_callback, NULL));
+ /* Make sure there is at least one LWP that has been resumed. */
+ gdb_assert (iterate_over_lwps (resumed_callback, NULL));
/* First check if there is a LWP with a wait status pending. */
if (pid == -1)
@@ -2159,23 +1997,20 @@ retry:
if (options & __WCLONE)
lp->cloned = 1;
- if (threaded)
- {
- gdb_assert (WIFSTOPPED (status)
- && WSTOPSIG (status) == SIGSTOP);
- lp->signalled = 1;
-
- if (!in_thread_list (inferior_ptid))
- {
- inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
- GET_PID (inferior_ptid));
- add_thread (inferior_ptid);
- }
+ gdb_assert (WIFSTOPPED (status)
+ && WSTOPSIG (status) == SIGSTOP);
+ lp->signalled = 1;
- add_thread (lp->ptid);
- printf_unfiltered (_("[New %s]\n"),
- target_pid_to_str (lp->ptid));
+ if (!in_thread_list (inferior_ptid))
+ {
+ inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
+ GET_PID (inferior_ptid));
+ add_thread (inferior_ptid);
}
+
+ add_thread (lp->ptid);
+ printf_unfiltered (_("[New %s]\n"),
+ target_pid_to_str (lp->ptid));
}
/* Handle GNU/Linux's extended waitstatus for trace events. */
@@ -2377,12 +2212,9 @@ retry:
the comment in cancel_breakpoints_callback to find out why. */
iterate_over_lwps (cancel_breakpoints_callback, lp);
- /* If we're not running in "threaded" mode, we'll report the bare
- process id. */
-
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
{
- trap_ptid = (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+ trap_ptid = lp->ptid;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLW: trap_ptid is %s.\n",
@@ -2399,7 +2231,7 @@ retry:
else
store_waitstatus (ourstatus, status);
- return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+ return lp->ptid;
}
static int
@@ -2464,20 +2296,35 @@ kill_wait_callback (struct lwp_info *lp, void *data)
static void
linux_nat_kill (void)
{
- /* Kill all LWP's ... */
- iterate_over_lwps (kill_callback, NULL);
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+ int status;
- /* ... and wait until we've flushed all events. */
- iterate_over_lwps (kill_wait_callback, NULL);
+ /* If we're stopped while forking and we haven't followed yet,
+ kill the other task. We need to do this first because the
+ parent will be sleeping if this is a vfork. */
- target_mourn_inferior ();
-}
+ get_last_target_status (&last_ptid, &last);
-static void
-linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
- int from_tty)
-{
- linux_ops->to_create_inferior (exec_file, allargs, env, from_tty);
+ if (last.kind == TARGET_WAITKIND_FORKED
+ || last.kind == TARGET_WAITKIND_VFORKED)
+ {
+ ptrace (PT_KILL, last.value.related_pid, 0, 0);
+ wait (&status);
+ }
+
+ if (forks_exist_p ())
+ linux_fork_killall ();
+ else
+ {
+ /* Kill all LWP's ... */
+ iterate_over_lwps (kill_callback, NULL);
+
+ /* ... and wait until we've flushed all events. */
+ iterate_over_lwps (kill_wait_callback, NULL);
+ }
+
+ target_mourn_inferior ();
}
static void
@@ -2492,7 +2339,14 @@ linux_nat_mourn_inferior (void)
sigprocmask (SIG_SETMASK, &normal_mask, NULL);
sigemptyset (&blocked_mask);
- linux_ops->to_mourn_inferior ();
+ if (! forks_exist_p ())
+ /* Normal case, no other forks available. */
+ linux_ops->to_mourn_inferior ();
+ else
+ /* Multi-fork case. The current inferior_ptid has exited, but
+ there are other viable forks to debug. Delete the exiting
+ one and context-switch to the first available. */
+ linux_fork_mourn_inferior ();
}
static LONGEST
@@ -2537,7 +2391,7 @@ linux_nat_pid_to_str (ptid_t ptid)
{
static char buf[64];
- if (is_lwp (ptid))
+ if (lwp_list && lwp_list->next && is_lwp (ptid))
{
snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid));
return buf;
@@ -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 for detailed info:\n\
status -- list a different bunch of random process info.\n\
all -- list all available /proc info."));
- init_linux_nat_ops ();
- add_target (&linux_nat_ops);
- thread_db_init (&linux_nat_ops);
-
/* Save the original signal mask. */
sigprocmask (SIG_SETMASK, NULL, &normal_mask);
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 92003c9694d..ecfaab70e95 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -1,6 +1,6 @@
/* Native debugging support for GNU/Linux (LWP layer).
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GDB.
@@ -83,3 +83,11 @@ struct lwp_info *iterate_over_lwps (int (*callback) (struct lwp_info *,
/* Create a prototype generic Linux target. The client can override
it with local methods. */
struct target_ops * linux_target (void);
+
+/* Register the customized Linux target. This should be used
+ instead of calling add_target directly. */
+void linux_nat_add_target (struct target_ops *);
+
+/* Update linux-nat internal state when changing from one fork
+ to another. */
+void linux_nat_switch_fork (ptid_t new_ptid);
diff --git a/gdb/m32r-linux-nat.c b/gdb/m32r-linux-nat.c
index bfe6435b3d4..454147b27aa 100644
--- a/gdb/m32r-linux-nat.c
+++ b/gdb/m32r-linux-nat.c
@@ -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);
}
diff --git a/gdb/m68klinux-nat.c b/gdb/m68klinux-nat.c
index 777330c1ac0..0da875e4c16 100644
--- a/gdb/m68klinux-nat.c
+++ b/gdb/m68klinux-nat.c
@@ -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);
}
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index 985ff2781d3..7796146ddc8 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -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);
}
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index d4f8c585e5f..769786255a1 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -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);
}
diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c
index 24ff73f48bd..885c3c5ccfb 100644
--- a/gdb/s390-nat.c
+++ b/gdb/s390-nat.c
@@ -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);
}
diff --git a/gdb/sparc-linux-nat.c b/gdb/sparc-linux-nat.c
index 9ad30a86d47..a234402fd78 100644
--- a/gdb/sparc-linux-nat.c
+++ b/gdb/sparc-linux-nat.c
@@ -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);
}
diff --git a/gdb/sparc64-linux-nat.c b/gdb/sparc64-linux-nat.c
index 84ff73998fa..730d4f9b3f8 100644
--- a/gdb/sparc64-linux-nat.c
+++ b/gdb/sparc64-linux-nat.c
@@ -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;
}