X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Flin-lwp.c;h=df91aa7696333b46d6cf7721cf1768bf235a0379;hb=552585edcb260c9c83ef910eaccd3237b0290842;hp=2d2a2b6d9f579c6e96515f8a0a2ca40296b5cc5d;hpb=b08cfdb65e8c728ddefa375b3d0953773e3e761a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/lin-lwp.c b/gdb/lin-lwp.c index 2d2a2b6d9f..df91aa7696 100644 --- a/gdb/lin-lwp.c +++ b/gdb/lin-lwp.c @@ -1,5 +1,5 @@ -/* Multi-threaded debugging support for Linux (LWP layer). - Copyright 2000, 2001 Free Software Foundation, Inc. +/* Multi-threaded debugging support for GNU/Linux (LWP layer). + Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GDB. @@ -21,8 +21,13 @@ #include "defs.h" #include "gdb_assert.h" +#include "gdb_string.h" #include #include +#ifdef HAVE_TKILL_SYSCALL +#include +#include +#endif #include #include "gdb_wait.h" @@ -33,64 +38,42 @@ #include "gdbcmd.h" static int debug_lin_lwp; -extern const char *strsignal (int sig); +extern char *strsignal (int sig); + +#include "linux-nat.h" -/* On 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 is - almost entirely a user-space issue; the kernel doesn't enforce such - a grouping at all (this might change in the future). In general, - we'll rely on the threads library (i.e. the LinuxThreads library) - to provide such a grouping. +/* 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 + is almost entirely a user-space issue; the kernel doesn't enforce + such a grouping at all (this might change in the future). In + general, we'll rely on the threads library (i.e. the GNU/Linux + Threads library) to provide such a grouping. It is perfectly well possible to write a multi-threaded application without the assistance of a threads library, by using the clone system call directly. This module should be able to give some rudimentary support for debugging such applications if developers specify the CLONE_PTRACE flag in the clone system call, and are - using Linux 2.4 or above. + using the Linux kernel 2.4 or above. - Note that there are some peculiarities in Linux that affect this - code: + Note that there are some peculiarities in GNU/Linux that affect + this code: - In general one should specify the __WCLONE flag to waitpid in order to make it report events for any of the cloned processes (and leave it out for the initial process). However, if a cloned process has exited the exit status is only reported if the - __WCLONE flag is absent. Linux 2.4 has a __WALL flag, but we - cannot use it since GDB must work on older systems too. + __WCLONE flag is absent. Linux kernel 2.4 has a __WALL flag, but + we cannot use it since GDB must work on older systems too. - When a traced, cloned process exits and is waited for by the debugger, the kernel reassigns it to the original parent and - keeps it around as a "zombie". Somehow, the LinuxThreads library - doesn't notice this, which leads to the "zombie problem": When - debugged a multi-threaded process that spawns a lot of threads - will run out of processes, even if the threads exit, because the - "zombies" stay around. */ - -/* Structure describing a LWP. */ -struct lwp_info -{ - /* The process id of the LWP. This is a combination of the LWP id - and overall process id. */ - ptid_t ptid; - - /* Non-zero if we sent this LWP a SIGSTOP (but the LWP didn't report - it back yet). */ - int signalled; - - /* Non-zero if this LWP is stopped. */ - int stopped; - - /* If non-zero, a pending wait status. */ - int status; - - /* Non-zero if we were stepping this LWP. */ - int step; - - /* Next LWP in list. */ - struct lwp_info *next; -}; + keeps it around as a "zombie". Somehow, the GNU/Linux Threads + library doesn't notice this, which leads to the "zombie problem": + When debugged a multi-threaded process that spawns a lot of + threads will run out of processes, even if the threads exit, + because the "zombies" stay around. */ /* List of known LWPs. */ static struct lwp_info *lwp_list; @@ -107,8 +90,6 @@ static int threaded; #define is_lwp(ptid) (GET_LWP (ptid) != 0) #define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0) -#define is_cloned(pid) (GET_LWP (pid) != GET_PID (pid)) - /* If the last reported event was a SIGTRAP, this variable is set to the process id of the LWP/thread that got it. */ ptid_t trap_ptid; @@ -144,8 +125,28 @@ static sigset_t blocked_mask; /* Prototypes for local functions. */ static int stop_wait_callback (struct lwp_info *lp, void *data); +static int lin_lwp_thread_alive (ptid_t ptid); +/* Convert wait status STATUS to a string. Used for printing debug + messages only. */ + +static char * +status_to_str (int status) +{ + static char buf[64]; + if (WIFSTOPPED (status)) + snprintf (buf, sizeof (buf), "%s (stopped)", + strsignal (WSTOPSIG (status))); + else if (WIFSIGNALED (status)) + snprintf (buf, sizeof (buf), "%s (terminated)", + strsignal (WSTOPSIG (status))); + else + snprintf (buf, sizeof (buf), "%d (exited)", WEXITSTATUS (status)); + + return buf; +} + /* Initialize the list of LWPs. Note that this module, contrary to what GDB's generic threads layer does for its thread list, re-initializes the LWP lists whenever we mourn or detach (which @@ -249,50 +250,16 @@ find_lwp_pid (ptid_t ptid) struct lwp_info * iterate_over_lwps (int (*callback) (struct lwp_info *, void *), void *data) { - struct lwp_info *lp; - - for (lp = lwp_list; lp; lp = lp->next) - if ((*callback) (lp, data)) - return lp; - - return NULL; -} - - -/* Implementation of the PREPARE_TO_PROCEED hook for the Linux LWP - layer. - - Note that this implementation is potentially redundant now that - default_prepare_to_proceed() has been added. */ + struct lwp_info *lp, *lpnext; -int -lin_lwp_prepare_to_proceed (void) -{ - if (! ptid_equal (trap_ptid, null_ptid) - && ! ptid_equal (inferior_ptid, trap_ptid)) + for (lp = lwp_list; lp; lp = lpnext) { - /* Switched over from TRAP_PID. */ - CORE_ADDR stop_pc = read_pc (); - CORE_ADDR trap_pc; - - /* Avoid switching where it wouldn't do any good, i.e. if both - threads are at the same breakpoint. */ - trap_pc = read_pc_pid (trap_ptid); - if (trap_pc != stop_pc && breakpoint_here_p (trap_pc)) - { - /* User hasn't deleted the breakpoint. Return non-zero, and - switch back to TRAP_PID. */ - inferior_ptid = trap_ptid; - - /* FIXME: Is this stuff really necessary? */ - flush_cached_frames (); - registers_changed (); - - return 1; - } + lpnext = lp->next; + if ((*callback) (lp, data)) + return lp; } - return 0; + return NULL; } @@ -315,42 +282,112 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose) gdb_assert (is_lwp (ptid)); + /* Make sure SIGCHLD is blocked. We don't want SIGCHLD events + to interrupt either the ptrace() or waitpid() calls below. */ + if (!sigismember (&blocked_mask, SIGCHLD)) + { + sigaddset (&blocked_mask, SIGCHLD); + sigprocmask (SIG_BLOCK, &blocked_mask, NULL); + } + if (verbose) printf_filtered ("[New %s]\n", target_pid_to_str (ptid)); - /* We assume that we're already tracing the initial process. */ - if (is_cloned (ptid) && ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0) - error ("Can't attach %s: %s", target_pid_to_str (ptid), strerror (errno)); - lp = find_lwp_pid (ptid); if (lp == NULL) lp = add_lwp (ptid); - if (is_cloned (ptid)) - lp->signalled = 1; + /* We assume that we're already attached to any LWP that has an + id equal to the overall process id. */ + if (GET_LWP (ptid) != GET_PID (ptid)) + { + pid_t pid; + int status; + + if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0) + error ("Can't attach %s: %s", target_pid_to_str (ptid), + safe_strerror (errno)); + + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n", + target_pid_to_str (ptid)); + + pid = waitpid (GET_LWP (ptid), &status, 0); + if (pid == -1 && errno == ECHILD) + { + /* Try again with __WCLONE to check cloned processes. */ + pid = waitpid (GET_LWP (ptid), &status, __WCLONE); + lp->cloned = 1; + } + + gdb_assert (pid == GET_LWP (ptid) + && WIFSTOPPED (status) && WSTOPSIG (status)); + + child_post_attach (pid); + + lp->stopped = 1; + + if (debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "LLAL: waitpid %s received %s\n", + target_pid_to_str (ptid), + status_to_str (status)); + } + } + else + { + /* We assume that the LWP representing the original process + is already stopped. Mark it as stopped in the data structure + that the lin-lwp layer uses to keep track of threads. Note + that this won't have already been done since the main thread + will have, we assume, been stopped by an attach from a + different layer. */ + lp->stopped = 1; + } } static void lin_lwp_attach (char *args, int from_tty) { struct lwp_info *lp; + pid_t pid; + int status; /* FIXME: We should probably accept a list of process id's, and attach all of them. */ child_ops.to_attach (args, from_tty); /* Add the initial process as the first LWP to the list. */ - lp = add_lwp (BUILD_LWP (PIDGET (inferior_ptid), PIDGET (inferior_ptid))); + lp = add_lwp (BUILD_LWP (GET_PID (inferior_ptid), GET_PID (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 work if things haven't stabilized yet. */ - lp->signalled = 1; - stop_wait_callback (lp, NULL); - gdb_assert (lp->status == 0); + pid = waitpid (GET_PID (inferior_ptid), &status, 0); + if (pid == -1 && errno == ECHILD) + { + warning ("%s is a cloned process", target_pid_to_str (inferior_ptid)); + + /* Try again with __WCLONE to check cloned processes. */ + pid = waitpid (GET_PID (inferior_ptid), &status, __WCLONE); + lp->cloned = 1; + } + + gdb_assert (pid == GET_PID (inferior_ptid) + && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP); + + lp->stopped = 1; /* Fake the SIGSTOP that core GDB expects. */ lp->status = W_STOPCODE (SIGSTOP); + lp->resumed = 1; + if (debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "LLA: waitpid %ld, faking SIGSTOP\n", (long) pid); + } } static int @@ -359,29 +396,52 @@ detach_callback (struct lwp_info *lp, void *data) gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status)); if (debug_lin_lwp && lp->status) - fprintf_unfiltered (gdb_stdlog, "Pending %s for LWP %ld on detach.\n", - strsignal (WSTOPSIG (lp->status)), GET_LWP (lp->ptid)); + fprintf_unfiltered (gdb_stdlog, "DC: Pending %s for %s on detach.\n", + strsignal (WSTOPSIG (lp->status)), + target_pid_to_str (lp->ptid)); while (lp->signalled && lp->stopped) { + errno = 0; if (ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, WSTOPSIG (lp->status)) < 0) error ("Can't continue %s: %s", target_pid_to_str (lp->ptid), - strerror (errno)); + safe_strerror (errno)); + + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "DC: PTRACE_CONTINUE (%s, 0, %s) (OK)\n", + target_pid_to_str (lp->ptid), + status_to_str (lp->status)); lp->stopped = 0; + lp->signalled = 0; lp->status = 0; - stop_wait_callback (lp, NULL); + /* FIXME drow/2003-08-26: There was a call to stop_wait_callback + here. But since lp->signalled was cleared above, + stop_wait_callback didn't do anything; the process was left + running. Shouldn't we be waiting for it to stop? + I've removed the call, since stop_wait_callback now does do + something when called with lp->signalled == 0. */ gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status)); } - if (is_cloned (lp->ptid)) + /* We don't actually detach from the LWP that has an id equal to the + overall process id just yet. */ + if (GET_LWP (lp->ptid) != GET_PID (lp->ptid)) { + errno = 0; if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0, WSTOPSIG (lp->status)) < 0) error ("Can't detach %s: %s", target_pid_to_str (lp->ptid), - strerror (errno)); + safe_strerror (errno)); + + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "PTRACE_DETACH (%s, %s, 0) (OK)\n", + target_pid_to_str (lp->ptid), + strsignal (WSTOPSIG (lp->status))); delete_lwp (lp->ptid); } @@ -394,7 +454,7 @@ lin_lwp_detach (char *args, int from_tty) { iterate_over_lwps (detach_callback, NULL); - /* Only the initial (uncloned) process should be left right now. */ + /* Only the initial process should be left right now. */ gdb_assert (num_lwps == 1); trap_ptid = null_ptid; @@ -411,25 +471,6 @@ lin_lwp_detach (char *args, int from_tty) } -struct private_thread_info -{ - int lwpid; -}; - -/* Return non-zero if TP corresponds to the LWP specified by DATA - (which is assumed to be a pointer to a `struct lwp_info'. */ - -static int -find_lwp_callback (struct thread_info *tp, void *data) -{ - struct lwp_info *lp = data; - - if (tp->private->lwpid == GET_LWP (lp->ptid)) - return 1; - - return 0; -} - /* Resume LP. */ static int @@ -439,28 +480,11 @@ resume_callback (struct lwp_info *lp, void *data) { struct thread_info *tp; -#if 1 - /* FIXME: kettenis/2000-08-26: This should really be handled - properly by core GDB. */ - - tp = find_thread_pid (lp->ptid); - if (tp == NULL) - tp = iterate_over_threads (find_lwp_callback, lp); - gdb_assert (tp); - - /* If we were previously stepping the thread, and now continue - the thread we must invalidate the stepping range. However, - if there is a step_resume breakpoint for this thread, we must - preserve the stepping range to make it possible to continue - stepping once we hit it. */ - if (tp->step_range_end && tp->step_resume_breakpoint == NULL) - { - gdb_assert (lp->step); - tp->step_range_start = tp->step_range_end = 0; - } -#endif - child_resume (pid_to_ptid (GET_LWP (lp->ptid)), 0, TARGET_SIGNAL_0); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "RC: PTRACE_CONT %s, 0, 0 (resume sibling)\n", + target_pid_to_str (lp->ptid)); lp->stopped = 0; lp->step = 0; } @@ -468,20 +492,36 @@ resume_callback (struct lwp_info *lp, void *data) return 0; } +static int +resume_clear_callback (struct lwp_info *lp, void *data) +{ + lp->resumed = 0; + return 0; +} + +static int +resume_set_callback (struct lwp_info *lp, void *data) +{ + lp->resumed = 1; + return 0; +} + static void lin_lwp_resume (ptid_t ptid, int step, enum target_signal signo) { struct lwp_info *lp; int resume_all; - /* Apparently the interpretation of PID is dependent on STEP: If - STEP is non-zero, a specific PID means `step only this process - id'. But if STEP is zero, then PID means `continue *all* - processes, but give the signal only to this one'. */ - resume_all = (PIDGET (ptid) == -1) || !step; + /* A specific PTID means `step only this process id'. */ + resume_all = (PIDGET (ptid) == -1); + + if (resume_all) + iterate_over_lwps (resume_set_callback, NULL); + else + iterate_over_lwps (resume_clear_callback, NULL); /* If PID is -1, it's the current inferior that should be - handled special. */ + handled specially. */ if (PIDGET (ptid) == -1) ptid = inferior_ptid; @@ -493,18 +533,21 @@ lin_lwp_resume (ptid_t ptid, int step, enum target_signal signo) /* Remember if we're stepping. */ lp->step = step; + /* Mark this LWP as resumed. */ + lp->resumed = 1; + /* If we have a pending wait status for this thread, there is no point in resuming the process. */ if (lp->status) { /* FIXME: What should we do if we are supposed to continue - this thread with a signal? */ + this thread with a signal? */ gdb_assert (signo == TARGET_SIGNAL_0); return; } /* Mark LWP as not stopped to prevent it from being continued by - resume_callback. */ + resume_callback. */ lp->stopped = 0; } @@ -512,20 +555,136 @@ lin_lwp_resume (ptid_t ptid, int step, enum target_signal signo) iterate_over_lwps (resume_callback, NULL); child_resume (ptid, step, signo); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "LLR: %s %s, %s (resume event thread)\n", + step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT", + target_pid_to_str (ptid), + signo ? strsignal (signo) : "0"); } +/* Issue kill to specified lwp. */ + +static int tkill_failed; + +static int +kill_lwp (int lwpid, int signo) +{ + errno = 0; + +/* Use tkill, if possible, in case we are using nptl threads. If tkill + fails, then we are not using nptl threads and we should be using kill. */ + +#ifdef HAVE_TKILL_SYSCALL + if (!tkill_failed) + { + int ret = syscall (__NR_tkill, lwpid, signo); + if (errno != ENOSYS) + return ret; + errno = 0; + tkill_failed = 1; + } +#endif + + return kill (lwpid, signo); +} + +/* Wait for LP to stop. Returns the wait status, or 0 if the LWP has + exited. */ + +static int +wait_lwp (struct lwp_info *lp) +{ + pid_t pid; + int status; + int thread_dead = 0; + + gdb_assert (!lp->stopped); + gdb_assert (lp->status == 0); + + pid = waitpid (GET_LWP (lp->ptid), &status, 0); + if (pid == -1 && errno == ECHILD) + { + pid = waitpid (GET_LWP (lp->ptid), &status, __WCLONE); + if (pid == -1 && errno == ECHILD) + { + /* The thread has previously exited. We need to delete it now + because in the case of NPTL threads, there won't be an + exit event unless it is the main thread. */ + thread_dead = 1; + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, "WL: %s vanished.\n", + target_pid_to_str (lp->ptid)); + } + } + + if (!thread_dead) + { + gdb_assert (pid == GET_LWP (lp->ptid)); + + if (debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "WL: waitpid %s received %s\n", + target_pid_to_str (lp->ptid), + status_to_str (status)); + } + } + + /* Check if the thread has exited. */ + if (WIFEXITED (status) || WIFSIGNALED (status)) + { + thread_dead = 1; + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, "WL: %s exited.\n", + target_pid_to_str (lp->ptid)); + } + + if (thread_dead) + { + if (in_thread_list (lp->ptid)) + { + /* Core GDB cannot deal with us deleting the current thread. */ + if (!ptid_equal (lp->ptid, inferior_ptid)) + delete_thread (lp->ptid); + printf_unfiltered ("[%s exited]\n", + target_pid_to_str (lp->ptid)); + } + + delete_lwp (lp->ptid); + return 0; + } + + gdb_assert (WIFSTOPPED (status)); + + return status; +} + /* Send a SIGSTOP to LP. */ static int stop_callback (struct lwp_info *lp, void *data) { - if (! lp->stopped && ! lp->signalled) + if (!lp->stopped && !lp->signalled) { int ret; - ret = kill (GET_LWP (lp->ptid), SIGSTOP); - gdb_assert (ret == 0); + if (debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "SC: kill %s ****\n", + target_pid_to_str (lp->ptid)); + } + errno = 0; + ret = kill_lwp (GET_LWP (lp->ptid), SIGSTOP); + if (debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "SC: lwp kill %d %s\n", + ret, + errno ? safe_strerror (errno) : "ERRNO-OK"); + } lp->signalled = 1; gdb_assert (lp->status == 0); @@ -534,99 +693,139 @@ stop_callback (struct lwp_info *lp, void *data) return 0; } -/* Wait until LP is stopped. */ +/* Wait until LP is stopped. If DATA is non-null it is interpreted as + a pointer to a set of signals to be flushed immediately. */ static int stop_wait_callback (struct lwp_info *lp, void *data) { - if (! lp->stopped && lp->signalled) + sigset_t *flush_mask = data; + + if (!lp->stopped) { - pid_t pid; int status; - gdb_assert (lp->status == 0); - - pid = waitpid (GET_LWP (lp->ptid), &status, - is_cloned (lp->ptid) ? __WCLONE : 0); - if (pid == -1 && errno == ECHILD) - /* OK, the proccess has disappeared. We'll catch the actual - exit event in lin_lwp_wait. */ + status = wait_lwp (lp); + if (status == 0) return 0; - gdb_assert (pid == GET_LWP (lp->ptid)); - - if (WIFEXITED (status) || WIFSIGNALED (status)) + /* Ignore any signals in FLUSH_MASK. */ + if (flush_mask && sigismember (flush_mask, WSTOPSIG (status))) { - gdb_assert (num_lwps > 1); - - if (in_thread_list (lp->ptid)) + if (!lp->signalled) { - /* Core GDB cannot deal with us deleting the current - thread. */ - if (!ptid_equal (lp->ptid, inferior_ptid)) - delete_thread (lp->ptid); - printf_unfiltered ("[%s exited]\n", - target_pid_to_str (lp->ptid)); + lp->stopped = 1; + return 0; } + + errno = 0; + ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); if (debug_lin_lwp) - fprintf_unfiltered (gdb_stdlog, - "%s exited.\n", target_pid_to_str (lp->ptid)); + fprintf_unfiltered (gdb_stdlog, + "PTRACE_CONT %s, 0, 0 (%s)\n", + target_pid_to_str (lp->ptid), + errno ? safe_strerror (errno) : "OK"); - delete_lwp (lp->ptid); - return 0; + return stop_wait_callback (lp, flush_mask); } - gdb_assert (WIFSTOPPED (status)); - lp->stopped = 1; - if (WSTOPSIG (status) != SIGSTOP) { - if (WSTOPSIG (status) == SIGTRAP - && breakpoint_inserted_here_p (read_pc_pid (pid_to_ptid (pid)) - - DECR_PC_AFTER_BREAK)) + if (WSTOPSIG (status) == SIGTRAP) { /* If a LWP other than the LWP that we're reporting an - event for has hit a GDB breakpoint (as opposed to - some random trap signal), then just arrange for it to - hit it again later. We don't keep the SIGTRAP status - and don't forward the SIGTRAP signal to the LWP. We - will handle the current event, eventually we will - resume all LWPs, and this one will get its breakpoint - trap again. - - If we do not do this, then we run the risk that the - user will delete or disable the breakpoint, but the - thread will have already tripped on it. */ - + event for has hit a GDB breakpoint (as opposed to + some random trap signal), then just arrange for it to + hit it again later. We don't keep the SIGTRAP status + and don't forward the SIGTRAP signal to the LWP. We + will handle the current event, eventually we will + resume all LWPs, and this one will get its breakpoint + trap again. + + If we do not do this, then we run the risk that the + user will delete or disable the breakpoint, but the + thread will have already tripped on it. */ + + /* Now resume this LWP and get the SIGSTOP event. */ + errno = 0; + ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); if (debug_lin_lwp) - fprintf_unfiltered (gdb_stdlog, - "Tripped breakpoint at %lx in LWP %d" - " while waiting for SIGSTOP.\n", - (long) read_pc_pid (lp->ptid), pid); - - /* Set the PC to before the trap. */ - if (DECR_PC_AFTER_BREAK) - write_pc_pid (read_pc_pid (pid_to_ptid (pid)) - - DECR_PC_AFTER_BREAK, - pid_to_ptid (pid)); + { + fprintf_unfiltered (gdb_stdlog, + "PTRACE_CONT %s, 0, 0 (%s)\n", + target_pid_to_str (lp->ptid), + errno ? safe_strerror (errno) : "OK"); + + fprintf_unfiltered (gdb_stdlog, + "SWC: Candidate SIGTRAP event in %s\n", + target_pid_to_str (lp->ptid)); + } + /* Hold the SIGTRAP for handling by lin_lwp_wait. */ + stop_wait_callback (lp, data); + /* If there's another event, throw it back into the queue. */ + if (lp->status) + { + if (debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "SWC: kill %s, %s\n", + target_pid_to_str (lp->ptid), + status_to_str ((int) status)); + } + kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status)); + } + /* Save the sigtrap event. */ + lp->status = status; + return 0; } else { - if (debug_lin_lwp) - fprintf_unfiltered (gdb_stdlog, - "Received %s in LWP %d while waiting for SIGSTOP.\n", - strsignal (WSTOPSIG (status)), pid); - /* The thread was stopped with a signal other than - SIGSTOP, and didn't accidentiliy trip a breakpoint. - Record the wait status. */ - lp->status = status; + SIGSTOP, and didn't accidentally trip a breakpoint. */ + + if (debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "SWC: Pending event %s in %s\n", + status_to_str ((int) status), + target_pid_to_str (lp->ptid)); + } + /* Now resume this LWP and get the SIGSTOP event. */ + errno = 0; + ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "SWC: PTRACE_CONT %s, 0, 0 (%s)\n", + target_pid_to_str (lp->ptid), + errno ? safe_strerror (errno) : "OK"); + + /* Hold this event/waitstatus while we check to see if + there are any more (we still want to get that SIGSTOP). */ + stop_wait_callback (lp, data); + /* If the lp->status field is still empty, use it to hold + this event. If not, then this event must be returned + to the event queue of the LWP. */ + if (lp->status == 0) + lp->status = status; + else + { + if (debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "SWC: kill %s, %s\n", + target_pid_to_str (lp->ptid), + status_to_str ((int) status)); + } + kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status)); + } + return 0; } } else { /* We caught the SIGSTOP that we intended to catch, so - there's no SIGSTOP pending. */ + there's no SIGSTOP pending. */ + lp->stopped = 1; lp->signalled = 0; } } @@ -634,12 +833,96 @@ stop_wait_callback (struct lwp_info *lp, void *data) return 0; } +/* Check whether PID has any pending signals in FLUSH_MASK. If so set + the appropriate bits in PENDING, and return 1 - otherwise return 0. */ + +static int +lin_lwp_has_pending (int pid, sigset_t *pending, sigset_t *flush_mask) +{ + sigset_t blocked, ignored; + int i; + + linux_proc_pending_signals (pid, pending, &blocked, &ignored); + + if (!flush_mask) + return 0; + + for (i = 1; i < NSIG; i++) + if (sigismember (pending, i)) + if (!sigismember (flush_mask, i) + || sigismember (&blocked, i) + || sigismember (&ignored, i)) + sigdelset (pending, i); + + if (sigisemptyset (pending)) + return 0; + + return 1; +} + +/* DATA is interpreted as a mask of signals to flush. If LP has + signals pending, and they are all in the flush mask, then arrange + to flush them. LP should be stopped, as should all other threads + it might share a signal queue with. */ + +static int +flush_callback (struct lwp_info *lp, void *data) +{ + sigset_t *flush_mask = data; + sigset_t pending, intersection, blocked, ignored; + int pid, status; + + /* Normally, when an LWP exits, it is removed from the LWP list. The + last LWP isn't removed till later, however. So if there is only + one LWP on the list, make sure it's alive. */ + if (lwp_list == lp && lp->next == NULL) + if (!lin_lwp_thread_alive (lp->ptid)) + return 0; + + /* Just because the LWP is stopped doesn't mean that new signals + can't arrive from outside, so this function must be careful of + race conditions. However, because all threads are stopped, we + can assume that the pending mask will not shrink unless we resume + the LWP, and that it will then get another signal. We can't + control which one, however. */ + + if (lp->status) + { + if (debug_lin_lwp) + printf_unfiltered ("FC: LP has pending status %06x\n", lp->status); + if (WIFSTOPPED (lp->status) && sigismember (flush_mask, WSTOPSIG (lp->status))) + lp->status = 0; + } + + while (lin_lwp_has_pending (GET_LWP (lp->ptid), &pending, flush_mask)) + { + int ret; + + errno = 0; + ret = ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stderr, + "FC: Sent PTRACE_CONT, ret %d %d\n", ret, errno); + + lp->stopped = 0; + stop_wait_callback (lp, flush_mask); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stderr, + "FC: Wait finished; saved status is %d\n", + lp->status); + } + + return 0; +} + /* Return non-zero if LP has a wait status pending. */ static int status_callback (struct lwp_info *lp, void *data) { - return (lp->status != 0); + /* Only report a pending wait status if we pretend that this has + indeed been resumed. */ + return (lp->status != 0 && lp->resumed); } /* Return non-zero if LP isn't stopped. */ @@ -647,7 +930,265 @@ status_callback (struct lwp_info *lp, void *data) static int running_callback (struct lwp_info *lp, void *data) { - return (lp->stopped == 0); + return (lp->stopped == 0 || (lp->status != 0 && lp->resumed)); +} + +/* Count the LWP's that have had events. */ + +static int +count_events_callback (struct lwp_info *lp, void *data) +{ + int *count = data; + + gdb_assert (count != NULL); + + /* Count only LWPs that have a SIGTRAP event pending. */ + if (lp->status != 0 + && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP) + (*count)++; + + return 0; +} + +/* Select the LWP (if any) that is currently being single-stepped. */ + +static int +select_singlestep_lwp_callback (struct lwp_info *lp, void *data) +{ + if (lp->step && lp->status != 0) + return 1; + else + return 0; +} + +/* Select the Nth LWP that has had a SIGTRAP event. */ + +static int +select_event_lwp_callback (struct lwp_info *lp, void *data) +{ + int *selector = data; + + gdb_assert (selector != NULL); + + /* Select only LWPs that have a SIGTRAP event pending. */ + if (lp->status != 0 + && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP) + if ((*selector)-- == 0) + return 1; + + return 0; +} + +static int +cancel_breakpoints_callback (struct lwp_info *lp, void *data) +{ + struct lwp_info *event_lp = data; + + /* Leave the LWP that has been elected to receive a SIGTRAP alone. */ + if (lp == event_lp) + return 0; + + /* If a LWP other than the LWP that we're reporting an event for has + hit a GDB breakpoint (as opposed to some random trap signal), + then just arrange for it to hit it again later. We don't keep + the SIGTRAP status and don't forward the SIGTRAP signal to the + LWP. We will handle the current event, eventually we will resume + all LWPs, and this one will get its breakpoint trap again. + + If we do not do this, then we run the risk that the user will + delete or disable the breakpoint, but the LWP will have already + tripped on it. */ + + if (lp->status != 0 + && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP + && breakpoint_inserted_here_p (read_pc_pid (lp->ptid) - + DECR_PC_AFTER_BREAK)) + { + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "CBC: Push back breakpoint for %s\n", + target_pid_to_str (lp->ptid)); + + /* Back up the PC if necessary. */ + if (DECR_PC_AFTER_BREAK) + write_pc_pid (read_pc_pid (lp->ptid) - DECR_PC_AFTER_BREAK, lp->ptid); + + /* Throw away the SIGTRAP. */ + lp->status = 0; + } + + return 0; +} + +/* Select one LWP out of those that have events pending. */ + +static void +select_event_lwp (struct lwp_info **orig_lp, int *status) +{ + int num_events = 0; + int random_selector; + struct lwp_info *event_lp; + + /* Record the wait status for the origional LWP. */ + (*orig_lp)->status = *status; + + /* Give preference to any LWP that is being single-stepped. */ + event_lp = iterate_over_lwps (select_singlestep_lwp_callback, NULL); + if (event_lp != NULL) + { + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "SEL: Select single-step %s\n", + target_pid_to_str (event_lp->ptid)); + } + else + { + /* No single-stepping LWP. Select one at random, out of those + which have had SIGTRAP events. */ + + /* First see how many SIGTRAP events we have. */ + iterate_over_lwps (count_events_callback, &num_events); + + /* Now randomly pick a LWP out of those that have had a SIGTRAP. */ + random_selector = (int) + ((num_events * (double) rand ()) / (RAND_MAX + 1.0)); + + if (debug_lin_lwp && num_events > 1) + fprintf_unfiltered (gdb_stdlog, + "SEL: Found %d SIGTRAP events, selecting #%d\n", + num_events, random_selector); + + event_lp = iterate_over_lwps (select_event_lwp_callback, + &random_selector); + } + + if (event_lp != NULL) + { + /* Switch the event LWP. */ + *orig_lp = event_lp; + *status = event_lp->status; + } + + /* Flush the wait status for the event LWP. */ + (*orig_lp)->status = 0; +} + +/* Return non-zero if LP has been resumed. */ + +static int +resumed_callback (struct lwp_info *lp, void *data) +{ + return lp->resumed; +} + +#ifdef CHILD_WAIT + +/* 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; + + do + { + set_sigint_trap (); /* Causes SIGINT to be passed on to the + attached process. */ + set_sigio_trap (); + + pid = waitpid (GET_PID (ptid), &status, 0); + if (pid == -1 && errno == ECHILD) + /* Try again with __WCLONE to check cloned processes. */ + pid = waitpid (GET_PID (ptid), &status, __WCLONE); + + if (debug_lin_lwp) + { + 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; + } + + 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; + } + + /* Handle GNU/Linux's extended waitstatus for trace events. */ + if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) + return linux_handle_extended_wait (pid, status, ourstatus); + + store_waitstatus (ourstatus, status); + return pid_to_ptid (pid); +} + +#endif + +/* Stop an active thread, verify it still exists, then resume it. */ + +static int +stop_and_resume_callback (struct lwp_info *lp, void *data) +{ + struct lwp_info *ptr; + + if (!lp->stopped && !lp->signalled) + { + stop_callback (lp, NULL); + stop_wait_callback (lp, NULL); + /* Resume if the lwp still exists. */ + for (ptr = lwp_list; ptr; ptr = ptr->next) + if (lp == ptr) + { + resume_callback (lp, NULL); + resume_set_callback (lp, NULL); + } + } + return 0; } static ptid_t @@ -657,30 +1198,38 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) int options = 0; int status = 0; pid_t pid = PIDGET (ptid); + sigset_t flush_mask; + + sigemptyset (&flush_mask); /* Make sure SIGCHLD is blocked. */ - if (! sigismember (&blocked_mask, SIGCHLD)) + if (!sigismember (&blocked_mask, SIGCHLD)) { sigaddset (&blocked_mask, SIGCHLD); sigprocmask (SIG_BLOCK, &blocked_mask, NULL); } - retry: +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)); /* First check if there is a LWP with a wait status pending. */ if (pid == -1) { - /* Any LWP will do. */ + /* Any LWP that's been resumed will do. */ lp = iterate_over_lwps (status_callback, NULL); if (lp) { - if (debug_lin_lwp) - fprintf_unfiltered (gdb_stdlog, - "Using pending wait status for LWP %ld.\n", - GET_LWP (lp->ptid)); - status = lp->status; lp->status = 0; + + if (debug_lin_lwp && status) + fprintf_unfiltered (gdb_stdlog, + "LLW: Using pending wait status %s for %s.\n", + status_to_str (status), + target_pid_to_str (lp->ptid)); } /* But if we don't fine one, we'll have to wait, and check both @@ -691,9 +1240,9 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) else if (is_lwp (ptid)) { if (debug_lin_lwp) - fprintf_unfiltered (gdb_stdlog, - "Waiting for specific LWP %ld.\n", - GET_LWP (ptid)); + fprintf_unfiltered (gdb_stdlog, + "LLW: Waiting for specific LWP %s.\n", + target_pid_to_str (ptid)); /* We have a specific LWP to check. */ lp = find_lwp_pid (ptid); @@ -701,42 +1250,49 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) status = lp->status; lp->status = 0; - if (debug_lin_lwp) - if (status) - fprintf_unfiltered (gdb_stdlog, - "Using pending wait status for LWP %ld.\n", - GET_LWP (lp->ptid)); + if (debug_lin_lwp && status) + fprintf_unfiltered (gdb_stdlog, + "LLW: Using pending wait status %s for %s.\n", + status_to_str (status), + target_pid_to_str (lp->ptid)); /* If we have to wait, take into account whether PID is a cloned process or not. And we have to convert it to something that the layer beneath us can understand. */ - options = is_cloned (lp->ptid) ? __WCLONE : 0; + options = lp->cloned ? __WCLONE : 0; pid = GET_LWP (ptid); } if (status && lp->signalled) { /* A pending SIGSTOP may interfere with the normal stream of - events. In a typical case where interference is a problem, - we have a SIGSTOP signal pending for LWP A while - single-stepping it, encounter an event in LWP B, and take the - pending SIGSTOP while trying to stop LWP A. After processing - the event in LWP B, LWP A is continued, and we'll never see - the SIGTRAP associated with the last time we were - single-stepping LWP A. */ + events. In a typical case where interference is a problem, + we have a SIGSTOP signal pending for LWP A while + single-stepping it, encounter an event in LWP B, and take the + pending SIGSTOP while trying to stop LWP A. After processing + the event in LWP B, LWP A is continued, and we'll never see + the SIGTRAP associated with the last time we were + single-stepping LWP A. */ /* Resume the thread. It should halt immediately returning the - pending SIGSTOP. */ + pending SIGSTOP. */ + registers_changed (); child_resume (pid_to_ptid (GET_LWP (lp->ptid)), lp->step, - TARGET_SIGNAL_0); + TARGET_SIGNAL_0); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s %s, 0, 0 (expect SIGSTOP)\n", + lp->step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT", + target_pid_to_str (lp->ptid)); lp->stopped = 0; + gdb_assert (lp->resumed); /* This should catch the pending SIGSTOP. */ stop_wait_callback (lp, NULL); } - set_sigint_trap (); /* Causes SIGINT to be passed on to the - attached process. */ + set_sigint_trap (); /* Causes SIGINT to be passed on to the + attached process. */ set_sigio_trap (); while (status == 0) @@ -748,20 +1304,64 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) { gdb_assert (pid == -1 || lwpid == pid); + if (debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "LLW: waitpid %ld received %s\n", + (long) lwpid, status_to_str (status)); + } + lp = find_lwp_pid (pid_to_ptid (lwpid)); - if (! lp) + + /* Check for stop events reported by a process we didn't + already know about - anything not already in our LWP + list. + + 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 (WIFSTOPPED (status) && !lp) + { + linux_record_stopped_pid (lwpid); + status = 0; + continue; + } + + /* Make sure we don't report an event for the exit of an LWP not in + our list, i.e. not part of the current process. This can happen + if we detach from a program we original forked and then it + exits. */ + if (!WIFSTOPPED (status) && !lp) + { + status = 0; + continue; + } + + /* NOTE drow/2003-06-17: This code seems to be meant for debugging + CLONE_PTRACE processes which do not use the thread library - + otherwise we wouldn't find the new LWP this way. That doesn't + currently work, and the following code is currently unreachable + due to the two blocks above. If it's fixed some day, this code + should be broken out into a function so that we can also pick up + LWPs from the new interface. */ + if (!lp) { lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid))); + if (options & __WCLONE) + lp->cloned = 1; + if (threaded) { gdb_assert (WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP); lp->signalled = 1; - if (! in_thread_list (inferior_ptid)) + if (!in_thread_list (inferior_ptid)) { inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), - GET_PID (inferior_ptid)); + GET_PID (inferior_ptid)); add_thread (inferior_ptid); } @@ -771,23 +1371,74 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) } } - /* Make sure we don't report a TARGET_WAITKIND_EXITED or - TARGET_WAITKIND_SIGNALLED event if there are still LWP's - left in the process. */ + /* Check if the thread has exited. */ if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1) { if (in_thread_list (lp->ptid)) { /* Core GDB cannot deal with us deleting the current - thread. */ - if (! ptid_equal (lp->ptid, inferior_ptid)) + thread. */ + if (!ptid_equal (lp->ptid, inferior_ptid)) delete_thread (lp->ptid); printf_unfiltered ("[%s exited]\n", target_pid_to_str (lp->ptid)); } + + /* If this is the main thread, we must stop all threads and + verify if they are still alive. This is because in the nptl + thread model, there is no signal issued for exiting LWPs + other than the main thread. We only get the main thread + exit signal once all child threads have already exited. + If we stop all the threads and use the stop_wait_callback + to check if they have exited we can determine whether this + signal should be ignored or whether it means the end of the + debugged application, regardless of which threading model + is being used. */ + if (GET_PID (lp->ptid) == GET_LWP (lp->ptid)) + { + lp->stopped = 1; + iterate_over_lwps (stop_and_resume_callback, NULL); + } + if (debug_lin_lwp) - fprintf_unfiltered (gdb_stdlog, - "%s exited.\n", + fprintf_unfiltered (gdb_stdlog, + "LLW: %s exited.\n", + target_pid_to_str (lp->ptid)); + + delete_lwp (lp->ptid); + + /* If there is at least one more LWP, then the exit signal + was not the end of the debugged application and should be + ignored. */ + if (num_lwps > 0) + { + /* Make sure there is at least one thread running. */ + gdb_assert (iterate_over_lwps (running_callback, NULL)); + + /* Discard the event. */ + status = 0; + continue; + } + } + + /* Check if the current LWP has previously exited. In the nptl + thread model, LWPs other than the main thread do not issue + signals when they exit so we must check whenever the thread + has stopped. A similar check is made in stop_wait_callback(). */ + if (num_lwps > 1 && !lin_lwp_thread_alive (lp->ptid)) + { + if (in_thread_list (lp->ptid)) + { + /* Core GDB cannot deal with us deleting the current + thread. */ + if (!ptid_equal (lp->ptid, inferior_ptid)) + delete_thread (lp->ptid); + printf_unfiltered ("[%s exited]\n", + target_pid_to_str (lp->ptid)); + } + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s exited.\n", target_pid_to_str (lp->ptid)); delete_lwp (lp->ptid); @@ -801,21 +1452,30 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) } /* Make sure we don't report a SIGSTOP that we sent - ourselves in an attempt to stop an LWP. */ - if (lp->signalled && WIFSTOPPED (status) - && WSTOPSIG (status) == SIGSTOP) + ourselves in an attempt to stop an LWP. */ + if (lp->signalled + && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP) { if (debug_lin_lwp) - fprintf_unfiltered (gdb_stdlog, - "Delayed SIGSTOP caught for %s.\n", + fprintf_unfiltered (gdb_stdlog, + "LLW: Delayed SIGSTOP caught for %s.\n", target_pid_to_str (lp->ptid)); /* This is a delayed SIGSTOP. */ lp->signalled = 0; + registers_changed (); child_resume (pid_to_ptid (GET_LWP (lp->ptid)), lp->step, - TARGET_SIGNAL_0); + TARGET_SIGNAL_0); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s %s, 0, 0 (discard SIGSTOP)\n", + lp->step ? + "PTRACE_SINGLESTEP" : "PTRACE_CONT", + target_pid_to_str (lp->ptid)); + lp->stopped = 0; + gdb_assert (lp->resumed); /* Discard the event. */ status = 0; @@ -859,31 +1519,83 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) && signal_print_state (signo) == 0 && signal_pass_state (signo) == 1) { + /* FIMXE: kettenis/2001-06-06: Should we resume all threads + here? It is not clear we should. GDB may not expect + other threads to run. On the other hand, not resuming + newly attached threads may cause an unwanted delay in + getting them running. */ + registers_changed (); child_resume (pid_to_ptid (GET_LWP (lp->ptid)), lp->step, signo); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s %s, %s (preempt 'handle')\n", + lp->step ? + "PTRACE_SINGLESTEP" : "PTRACE_CONT", + target_pid_to_str (lp->ptid), + signo ? strsignal (signo) : "0"); lp->stopped = 0; status = 0; goto retry; } + + if (signo == TARGET_SIGNAL_INT && signal_pass_state (signo) == 0) + { + /* If ^C/BREAK is typed at the tty/console, SIGINT gets + forwarded to the entire process group, that is, all LWP's + will receive it. Since we only want to report it once, + we try to flush it from all LWPs except this one. */ + sigaddset (&flush_mask, SIGINT); + } } /* This LWP is stopped now. */ lp->stopped = 1; + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, "LLW: Candidate event %s in %s.\n", + status_to_str (status), target_pid_to_str (lp->ptid)); + /* Now stop all other LWP's ... */ iterate_over_lwps (stop_callback, NULL); /* ... and wait until all of them have reported back that they're no longer running. */ - iterate_over_lwps (stop_wait_callback, NULL); + iterate_over_lwps (stop_wait_callback, &flush_mask); + iterate_over_lwps (flush_callback, &flush_mask); + + /* If we're not waiting for a specific LWP, choose an event LWP from + among those that have had events. Giving equal priority to all + LWPs that have had events helps prevent starvation. */ + if (pid == -1) + select_event_lwp (&lp, &status); + + /* Now that we've selected our final event LWP, cancel any + breakpoints in other LWPs that have hit a GDB breakpoint. See + 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 = (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid))); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "LLW: trap_ptid is %s.\n", + target_pid_to_str (trap_ptid)); + } else trap_ptid = null_ptid; + /* Handle GNU/Linux's extended waitstatus for trace events. */ + if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) + { + linux_handle_extended_wait (ptid_get_pid (trap_ptid), + status, ourstatus); + return trap_ptid; + } + store_waitstatus (ourstatus, status); return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid))); } @@ -891,7 +1603,14 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) static int kill_callback (struct lwp_info *lp, void *data) { + errno = 0; ptrace (PTRACE_KILL, GET_LWP (lp->ptid), 0, 0); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "KC: PTRACE_KILL %s, 0, 0 (%s)\n", + target_pid_to_str (lp->ptid), + errno ? safe_strerror (errno) : "OK"); + return 0; } @@ -907,11 +1626,17 @@ kill_wait_callback (struct lwp_info *lp, void *data) /* For cloned processes we must check both with __WCLONE and without, since the exit status of a cloned process isn't reported with __WCLONE. */ - if (is_cloned (lp->ptid)) + if (lp->cloned) { do { pid = waitpid (GET_LWP (lp->ptid), NULL, __WCLONE); + if (pid != (pid_t) -1 && debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "KWC: wait %s received unknown.\n", + target_pid_to_str (lp->ptid)); + } } while (pid == GET_LWP (lp->ptid)); @@ -921,6 +1646,12 @@ kill_wait_callback (struct lwp_info *lp, void *data) do { pid = waitpid (GET_LWP (lp->ptid), NULL, 0); + if (pid != (pid_t) -1 && debug_lin_lwp) + { + fprintf_unfiltered (gdb_stdlog, + "KWC: wait %s received unk.\n", + target_pid_to_str (lp->ptid)); + } } while (pid == GET_LWP (lp->ptid)); @@ -946,7 +1677,7 @@ lin_lwp_create_inferior (char *exec_file, char *allargs, char **env) child_ops.to_create_inferior (exec_file, allargs, env); } -static void +static void lin_lwp_mourn_inferior (void) { trap_ptid = null_ptid; @@ -961,36 +1692,9 @@ lin_lwp_mourn_inferior (void) child_ops.to_mourn_inferior (); } -static void -lin_lwp_fetch_registers (int regno) -{ - struct cleanup *old_chain = save_inferior_ptid (); - - if (is_lwp (inferior_ptid)) - inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid)); - - fetch_inferior_registers (regno); - - do_cleanups (old_chain); -} - -static void -lin_lwp_store_registers (int regno) -{ - struct cleanup *old_chain = save_inferior_ptid (); - - if (is_lwp (inferior_ptid)) - inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid)); - - store_inferior_registers (regno); - - do_cleanups (old_chain); -} - static int lin_lwp_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, - struct mem_attrib *attrib, - struct target_ops *target) + struct mem_attrib *attrib, struct target_ops *target) { struct cleanup *old_chain = save_inferior_ptid (); int xfer; @@ -998,7 +1702,9 @@ lin_lwp_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, if (is_lwp (inferior_ptid)) inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid)); - xfer = child_xfer_memory (memaddr, myaddr, len, write, attrib, target); + xfer = linux_proc_xfer_memory (memaddr, myaddr, len, write, attrib, target); + if (xfer == 0) + xfer = child_xfer_memory (memaddr, myaddr, len, write, attrib, target); do_cleanups (old_chain); return xfer; @@ -1011,6 +1717,11 @@ lin_lwp_thread_alive (ptid_t ptid) errno = 0; ptrace (PTRACE_PEEKUSER, GET_LWP (ptid), 0, 0); + if (debug_lin_lwp) + fprintf_unfiltered (gdb_stdlog, + "LLTA: PTRACE_PEEKUSER %s, 0, 0 (%s)\n", + target_pid_to_str (ptid), + errno ? safe_strerror (errno) : "OK"); if (errno) return 0; @@ -1044,14 +1755,22 @@ init_lin_lwp_ops (void) lin_lwp_ops.to_detach = lin_lwp_detach; lin_lwp_ops.to_resume = lin_lwp_resume; lin_lwp_ops.to_wait = lin_lwp_wait; - lin_lwp_ops.to_fetch_registers = lin_lwp_fetch_registers; - lin_lwp_ops.to_store_registers = lin_lwp_store_registers; + /* fetch_inferior_registers and store_inferior_registers will + honor the LWP id, so we can use them directly. */ + lin_lwp_ops.to_fetch_registers = fetch_inferior_registers; + lin_lwp_ops.to_store_registers = store_inferior_registers; lin_lwp_ops.to_xfer_memory = lin_lwp_xfer_memory; lin_lwp_ops.to_kill = lin_lwp_kill; lin_lwp_ops.to_create_inferior = lin_lwp_create_inferior; lin_lwp_ops.to_mourn_inferior = lin_lwp_mourn_inferior; lin_lwp_ops.to_thread_alive = lin_lwp_thread_alive; lin_lwp_ops.to_pid_to_str = lin_lwp_pid_to_str; + lin_lwp_ops.to_post_startup_inferior = child_post_startup_inferior; + lin_lwp_ops.to_post_attach = child_post_attach; + lin_lwp_ops.to_insert_fork_catchpoint = child_insert_fork_catchpoint; + lin_lwp_ops.to_insert_vfork_catchpoint = child_insert_vfork_catchpoint; + lin_lwp_ops.to_insert_exec_catchpoint = child_insert_exec_catchpoint; + lin_lwp_ops.to_stratum = thread_stratum; lin_lwp_ops.to_has_thread_control = tc_schedlock; lin_lwp_ops.to_magic = OPS_MAGIC; @@ -1091,16 +1810,15 @@ _initialize_lin_lwp (void) sigemptyset (&blocked_mask); add_show_from_set (add_set_cmd ("lin-lwp", no_class, var_zinteger, - (char *) &debug_lin_lwp, - "Set debugging of linux lwp module.\n\ -Enables printf debugging output.\n", - &setdebuglist), - &showdebuglist); + (char *) &debug_lin_lwp, + "Set debugging of GNU/Linux lwp module.\n\ +Enables printf debugging output.\n", &setdebuglist), &showdebuglist); } /* FIXME: kettenis/2000-08-26: The stuff on this page is specific to - the LinuxThreads library and therefore doesn't really belong here. */ + the GNU/Linux Threads library and therefore doesn't really belong + here. */ /* Read variable NAME in the target and return its value if found. Otherwise return zero. It is assumed that the type of the variable @@ -1144,10 +1862,11 @@ lin_thread_get_thread_signals (sigset_t *set) sigaddset (set, restart); sigaddset (set, cancel); - /* The LinuxThreads library makes terminating threads send a special - "cancel" signal instead of SIGCHLD. Make sure we catch those (to - prevent them from terminating GDB itself, which is likely to be - their default action) and treat them the same way as SIGCHLD. */ + /* The GNU/Linux Threads library makes terminating threads send a + special "cancel" signal instead of SIGCHLD. Make sure we catch + those (to prevent them from terminating GDB itself, which is + likely to be their default action) and treat them the same way as + SIGCHLD. */ action.sa_handler = sigchld_handler; sigemptyset (&action.sa_mask);