From f973ed9c9fe95754a838acaf31312265b6d9320f Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Fri, 24 Mar 2006 23:08:16 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 44 +++++ gdb/Makefile.in | 3 +- gdb/alpha-linux-nat.c | 4 +- gdb/amd64-linux-nat.c | 5 +- gdb/arm-linux-nat.c | 4 +- gdb/hppa-linux-nat.c | 4 +- gdb/i386-linux-nat.c | 4 +- gdb/ia64-linux-nat.c | 4 +- gdb/linux-fork.c | 5 +- gdb/linux-nat.c | 417 ++++++++++++---------------------------- gdb/linux-nat.h | 10 +- gdb/m32r-linux-nat.c | 4 +- gdb/m68klinux-nat.c | 4 +- gdb/mips-linux-nat.c | 2 +- gdb/ppc-linux-nat.c | 2 +- gdb/s390-nat.c | 2 +- gdb/sparc-linux-nat.c | 4 +- gdb/sparc64-linux-nat.c | 4 +- 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,3 +1,47 @@ +2006-03-24 Daniel Jacobowitz + + * 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 * linux-fork.c: Include "gdb_assert.h". 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 #include @@ -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; @@ -2546,59 +2400,6 @@ linux_nat_pid_to_str (ptid_t ptid) return normal_pid_to_str (ptid); } -static void -linux_nat_fetch_registers (int regnum) -{ - /* to_fetch_registers will honor the LWP ID, so we can use it directly. */ - linux_ops->to_fetch_registers (regnum); -} - -static void -linux_nat_store_registers (int regnum) -{ - /* to_store_registers will honor the LWP ID, so we can use it directly. */ - linux_ops->to_store_registers (regnum); -} - -static void -linux_nat_child_post_startup_inferior (ptid_t ptid) -{ - linux_ops->to_post_startup_inferior (ptid); -} - -static void -init_linux_nat_ops (void) -{ -#if 0 - linux_nat_ops.to_open = linux_nat_open; -#endif - linux_nat_ops.to_shortname = "lwp-layer"; - linux_nat_ops.to_longname = "lwp-layer"; - linux_nat_ops.to_doc = "Low level threads support (LWP layer)"; - linux_nat_ops.to_attach = linux_nat_attach; - linux_nat_ops.to_detach = linux_nat_detach; - linux_nat_ops.to_resume = linux_nat_resume; - linux_nat_ops.to_wait = linux_nat_wait; - linux_nat_ops.to_fetch_registers = linux_nat_fetch_registers; - linux_nat_ops.to_store_registers = linux_nat_store_registers; - linux_nat_ops.to_xfer_partial = linux_nat_xfer_partial; - linux_nat_ops.to_kill = linux_nat_kill; - linux_nat_ops.to_create_inferior = linux_nat_create_inferior; - linux_nat_ops.to_mourn_inferior = linux_nat_mourn_inferior; - linux_nat_ops.to_thread_alive = linux_nat_thread_alive; - linux_nat_ops.to_pid_to_str = linux_nat_pid_to_str; - linux_nat_ops.to_post_startup_inferior - = linux_nat_child_post_startup_inferior; - linux_nat_ops.to_post_attach = child_post_attach; - linux_nat_ops.to_insert_fork_catchpoint = child_insert_fork_catchpoint; - linux_nat_ops.to_insert_vfork_catchpoint = child_insert_vfork_catchpoint; - linux_nat_ops.to_insert_exec_catchpoint = child_insert_exec_catchpoint; - - linux_nat_ops.to_stratum = thread_stratum; - linux_nat_ops.to_has_thread_control = tc_schedlock; - linux_nat_ops.to_magic = OPS_MAGIC; -} - static void sigchld_handler (int signo) { @@ -3310,8 +3111,6 @@ linux_target (void) #else t = inf_ptrace_trad_target (linux_register_u_offset); #endif - t->to_wait = child_wait; - t->to_kill = kill_inferior; t->to_insert_fork_catchpoint = child_insert_fork_catchpoint; t->to_insert_vfork_catchpoint = child_insert_vfork_catchpoint; t->to_insert_exec_catchpoint = child_insert_exec_catchpoint; @@ -3325,18 +3124,50 @@ linux_target (void) super_xfer_partial = t->to_xfer_partial; t->to_xfer_partial = linux_xfer_partial; - super_mourn_inferior = t->to_mourn_inferior; - t->to_mourn_inferior = child_mourn_inferior; - - linux_ops = t; return t; } +void +linux_nat_add_target (struct target_ops *t) +{ + extern void thread_db_init (struct target_ops *); + + /* Save the provided single-threaded target. We save this in a separate + variable because another target we've inherited from (e.g. inf-ptrace) + may have saved a pointer to T; we want to use it for the final + process stratum target. */ + linux_ops_saved = *t; + linux_ops = &linux_ops_saved; + + /* Override some methods for multithreading. */ + t->to_attach = linux_nat_attach; + t->to_detach = linux_nat_detach; + t->to_resume = linux_nat_resume; + t->to_wait = linux_nat_wait; + t->to_xfer_partial = linux_nat_xfer_partial; + t->to_kill = linux_nat_kill; + t->to_mourn_inferior = linux_nat_mourn_inferior; + t->to_thread_alive = linux_nat_thread_alive; + t->to_pid_to_str = linux_nat_pid_to_str; + t->to_has_thread_control = tc_schedlock; + + /* We don't change the stratum; this target will sit at + process_stratum and thread_db will set at thread_stratum. This + is a little strange, since this is a multi-threaded-capable + target, but we want to be on the stack below thread_db, and we + also want to be used for single-threaded processes. */ + + add_target (t); + + /* TODO: Eliminate this and have libthread_db use + find_target_beneath. */ + thread_db_init (t); +} + void _initialize_linux_nat (void) { struct sigaction action; - extern void thread_db_init (struct target_ops *); add_info ("proc", linux_nat_info_proc_cmd, _("\ Show /proc process information about any running process.\n\ @@ -3347,10 +3178,6 @@ Specify any of the following keywords for detailed info:\n\ status -- list a different bunch of random process info.\n\ all -- list all available /proc info.")); - init_linux_nat_ops (); - add_target (&linux_nat_ops); - thread_db_init (&linux_nat_ops); - /* Save the original signal mask. */ sigprocmask (SIG_SETMASK, NULL, &normal_mask); 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; } -- 2.30.2