+++ /dev/null
-1999-08-13 Jim Kingdon <http://developer.redhat.com/>
-
- Threads code from gdb 4.18-codefusion-990706:
- * infrun.c (signal_stop_update, signal_print_update,
- signal_pass_update): new functions.
- * inferior.h: new prototypes for above functions.
- * target.h (enum strata): add thread stratum.
- * linuxthreads.c: new file. Support for debugging linux threads.
- * config/i386/nm-linux.h: several new prototypes for above.
- * config/i386/linux.mh: add linuxthreads.o to NATDEPFILES.
-
- More threads code from the same place:
- * config/i386/tm-linux.h (REALTIME_LO, REALTIME_HI): Add
- definitions.
- * target.h (enum target_signal): Add TARGET_SIGNAL_REALTIME_32.
- * target.c (signals, target_signal_from_host,
- target_signal_to_host): Add clauses for
- TARGET_SIGNAL_REALTIME_32.
-
- * various files: various minor changes to make the above work
- with GDB 4.18.
-
-diff -Ncr /home/kingdon/work/gdb/gdb/config/i386/linux.mh ./gdb/config/i386/linux.mh
-*** /home/kingdon/work/gdb/gdb/config/i386/linux.mh Thu Apr 15 21:34:19 1999
---- ./gdb/config/i386/linux.mh Fri Aug 13 00:51:14 1999
-***************
-*** 4,7 ****
- XDEPFILES= ser-tcp.o
-
- NAT_FILE= nm-linux.h
-! NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o core-aout.o core-regset.o i386v-nat.o i386v4-nat.o
---- 4,7 ----
- XDEPFILES= ser-tcp.o
-
- NAT_FILE= nm-linux.h
-! NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o core-aout.o core-regset.o i386v-nat.o i386v4-nat.o linuxthreads.o
-diff -Ncr /home/kingdon/work/gdb/gdb/config/i386/nm-linux.h ./gdb/config/i386/nm-linux.h
-*** /home/kingdon/work/gdb/gdb/config/i386/nm-linux.h Thu Jul 8 16:09:02 1999
---- ./gdb/config/i386/nm-linux.h Fri Aug 13 00:49:54 1999
-***************
-*** 71,74 ****
---- 71,92 ----
- extern int
- i386_remove_watchpoint PARAMS ((int pid, CORE_ADDR addr, int len));
-
-+ /* Support for the glibc linuxthreads package. */
-+
-+ #ifdef __STDC__
-+ struct objfile;
-+ #endif
-+
-+ extern void
-+ linuxthreads_new_objfile PARAMS ((struct objfile *objfile));
-+ #define target_new_objfile(OBJFILE) linuxthreads_new_objfile (OBJFILE)
-+
-+ extern char *
-+ linuxthreads_pid_to_str PARAMS ((int pid));
-+ #define target_pid_to_str(PID) linuxthreads_pid_to_str (PID)
-+
-+ extern int
-+ linuxthreads_prepare_to_proceed PARAMS ((int step));
-+ #define PREPARE_TO_PROCEED() linuxthreads_prepare_to_proceed (1)
-+
- #endif /* #ifndef NM_LINUX_H */
-diff -Ncr /home/kingdon/work/gdb/gdb/config/i386/tm-linux.h ./gdb/config/i386/tm-linux.h
-*** /home/kingdon/work/gdb/gdb/config/i386/tm-linux.h Tue Aug 3 16:40:28 1999
---- ./gdb/config/i386/tm-linux.h Sat Aug 14 19:15:35 1999
-***************
-*** 104,107 ****
---- 104,121 ----
-
- extern CORE_ADDR i386_linux_sigtramp_saved_sp PARAMS ((struct frame_info *));
-
-+
-+ /* Some versions of Linux have real-time signal support in the C library, and
-+ some don't. We have to include this file to find out. */
-+ #include <signal.h>
-+
-+ #ifdef __SIGRTMIN
-+ #define REALTIME_LO __SIGRTMIN
-+ #define REALTIME_HI (__SIGRTMAX + 1)
-+ #else
-+ #define REALTIME_LO 32
-+ #define REALTIME_HI 64
-+ #endif
-+
-+
- #endif /* #ifndef TM_LINUX_H */
-diff -Ncr /home/kingdon/work/gdb/gdb/inferior.h ./gdb/inferior.h
-*** /home/kingdon/work/gdb/gdb/inferior.h Thu Jul 8 16:02:22 1999
---- ./gdb/inferior.h Fri Aug 13 00:43:51 1999
-***************
-*** 260,265 ****
---- 260,271 ----
-
- extern int signal_pass_state PARAMS ((int));
-
-+ extern int signal_stop_update PARAMS ((int, int));
-+
-+ extern int signal_print_update PARAMS ((int, int));
-+
-+ extern int signal_pass_update PARAMS ((int, int));
-+
- /* From infcmd.c */
-
- extern void tty_command PARAMS ((char *, int));
-diff -Ncr /home/kingdon/work/gdb/gdb/infrun.c ./gdb/infrun.c
-*** /home/kingdon/work/gdb/gdb/infrun.c Thu Aug 12 11:13:29 1999
---- ./gdb/infrun.c Fri Aug 13 00:33:34 1999
-***************
-*** 3291,3296 ****
---- 3291,3323 ----
- return signal_program[signo];
- }
-
-+ int signal_stop_update (signo, state)
-+ int signo;
-+ int state;
-+ {
-+ int ret = signal_stop[signo];
-+ signal_stop[signo] = state;
-+ return ret;
-+ }
-+
-+ int signal_print_update (signo, state)
-+ int signo;
-+ int state;
-+ {
-+ int ret = signal_print[signo];
-+ signal_print[signo] = state;
-+ return ret;
-+ }
-+
-+ int signal_pass_update (signo, state)
-+ int signo;
-+ int state;
-+ {
-+ int ret = signal_program[signo];
-+ signal_program[signo] = state;
-+ return ret;
-+ }
-+
- static void
- sig_print_header (void)
- {
-diff -Ncr /home/kingdon/work/gdb/gdb/linuxthreads.c ./gdb/linuxthreads.c
-*** /home/kingdon/work/gdb/gdb/linuxthreads.c Wed Dec 31 19:00:00 1969
---- ./gdb/linuxthreads.c Fri Aug 13 00:46:01 1999
-***************
-*** 0 ****
---- 1,1631 ----
-+ /* Low level interface for debugging GNU/Linux threads for GDB,
-+ the GNU debugger.
-+ Copyright 1998, 1999 Free Software Foundation, Inc.
-+
-+ This file is part of GDB.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-+
-+ /* This module implements the debugging interface of the linuxthreads package
-+ of the glibc. This package implements a simple clone()-based implementation
-+ of Posix threads for Linux. To use this module, be sure that you have at
-+ least the version of the linuxthreads package that holds the support of
-+ GDB (currently 0.8 included in the glibc-2.0.7).
-+
-+ Right now, the linuxthreads package does not care of priority scheduling,
-+ so, neither this module does; In particular, the threads are resumed
-+ in any order, which could lead to different scheduling than the one
-+ happening when GDB does not control the execution.
-+
-+ The latest point is that ptrace(PT_ATTACH, ...) is intrusive in Linux:
-+ When a process is attached, then the attaching process becomes the current
-+ parent of the attached process, and the old parent has lost this child.
-+ If the old parent does a wait[...](), then this child is no longer
-+ considered by the kernel as a child of the old parent, thus leading to
-+ results of the call different when the child is attached and when it's not.
-+
-+ A fix has been submitted to the Linux community to solve this problem,
-+ which consequences are not visible to the application itself, but on the
-+ process which may wait() for the completion of the application (mostly,
-+ it may consider that the application no longer exists (errno == ECHILD),
-+ although it does, and thus being unable to get the exit status and resource
-+ usage of the child. If by chance, it is able to wait() for the application
-+ after it has died (by receiving first a SIGCHILD, and then doing a wait(),
-+ then the exit status and resource usage may be wrong, because the
-+ linuxthreads package heavily relies on wait() synchronization to keep
-+ them correct. */
-+
-+ #include <sys/types.h> /* for pid_t */
-+ #include <sys/ptrace.h> /* for PT_* flags */
-+ #include <sys/wait.h> /* for WUNTRACED and __WCLONE flags */
-+ #include <signal.h> /* for struct sigaction and NSIG */
-+ #include <sys/utsname.h>
-+
-+ #include "defs.h"
-+ #include "target.h"
-+ #include "inferior.h"
-+ #include "gdbcore.h"
-+ #include "gdbthread.h"
-+ #include "wait.h"
-+ #include "gdbcmd.h"
-+ #include "breakpoint.h"
-+
-+ #ifndef PT_ATTACH
-+ #define PT_ATTACH PTRACE_ATTACH
-+ #endif
-+ #ifndef PT_KILL
-+ #define PT_KILL PTRACE_KILL
-+ #endif
-+ #ifndef PT_READ_U
-+ #define PT_READ_U PTRACE_PEEKUSR
-+ #endif
-+
-+ #ifdef NSIG
-+ #define LINUXTHREAD_NSIG NSIG
-+ #else
-+ #ifdef _NSIG
-+ #define LINUXTHREAD_NSIG _NSIG
-+ #endif
-+ #endif
-+
-+ extern int child_suppress_run; /* make inftarg.c non-runnable */
-+ struct target_ops linuxthreads_ops; /* Forward declaration */
-+ extern struct target_ops child_ops; /* target vector for inftarg.c */
-+
-+ static CORE_ADDR linuxthreads_handles; /* array of linuxthreads handles */
-+ static CORE_ADDR linuxthreads_manager; /* pid of linuxthreads manager thread */
-+ static CORE_ADDR linuxthreads_initial; /* pid of linuxthreads initial thread */
-+ static CORE_ADDR linuxthreads_debug; /* linuxthreads internal debug flag */
-+ static CORE_ADDR linuxthreads_num; /* number of valid handle entries */
-+
-+ static int linuxthreads_max; /* Maximum number of linuxthreads.
-+ Zero if this executable doesn't use
-+ threads, or wasn't linked with a
-+ debugger-friendly version of the
-+ linuxthreads library. */
-+
-+ static int linuxthreads_sizeof_handle; /* size of a linuxthreads handle */
-+ static int linuxthreads_offset_descr; /* h_descr offset of the linuxthreads
-+ handle */
-+ static int linuxthreads_offset_pid; /* p_pid offset of the linuxthreads
-+ descr */
-+
-+ static int linuxthreads_manager_pid; /* manager pid */
-+ static int linuxthreads_initial_pid; /* initial pid */
-+
-+ /* These variables form a bag of threads with interesting status. If
-+ wait_thread (PID) finds that PID stopped for some interesting
-+ reason (i.e. anything other than stopped with SIGSTOP), then it
-+ records its status in this queue. linuxthreads_wait and
-+ linuxthreads_find_trap extract processes from here. */
-+ static int *linuxthreads_wait_pid; /* wait array of pid */
-+ static int *linuxthreads_wait_status; /* wait array of status */
-+ static int linuxthreads_wait_last; /* index of last valid elt in
-+ linuxthreads_wait_{pid,status} */
-+
-+ static sigset_t linuxthreads_wait_mask; /* sigset with SIGCHLD */
-+
-+ static int linuxthreads_step_pid; /* current stepped pid */
-+ static int linuxthreads_step_signo; /* current stepped target signal */
-+ static int linuxthreads_exit_status; /* exit status of initial thread */
-+
-+ static int linuxthreads_inferior_pid; /* temporary internal inferior pid */
-+ static int linuxthreads_breakpoint_pid; /* last pid that hit a breakpoint */
-+ static int linuxthreads_attach_pending; /* attach command without wait */
-+
-+ static int linuxthreads_breakpoints_inserted; /* any breakpoints inserted */
-+
-+ /* LinuxThreads uses certain signals for communication between
-+ processes; we need to tell GDB to pass them through silently to the
-+ inferior. The LinuxThreads library has global variables we can
-+ read containing the relevant signal numbers, but since the signal
-+ numbers are chosen at run-time, those variables aren't initialized
-+ until the shared library's constructors have had a chance to run. */
-+
-+ struct linuxthreads_signal {
-+
-+ /* The name of the LinuxThreads library variable that contains
-+ the signal number. */
-+ char *var;
-+
-+ /* True if this variable must exist for us to debug properly. */
-+ int required;
-+
-+ /* The variable's address in the inferior, or zero if the
-+ LinuxThreads library hasn't been loaded into this inferior yet. */
-+ CORE_ADDR addr;
-+
-+ /* The signal number, or zero if we don't know yet (either because
-+ we haven't found the variable, or it hasn't been initialized).
-+ This is an actual target signal number that you could pass to
-+ `kill', not a GDB signal number. */
-+ int signal;
-+
-+ /* GDB's original settings for `stop' and `print' for this signal.
-+ We restore them when the user selects a different executable.
-+ Invariant: if sig->signal != 0, then sig->{stop,print} contain
-+ the original settings. */
-+ int stop, print;
-+ };
-+
-+ struct linuxthreads_signal linuxthreads_sig_restart = {
-+ "__pthread_sig_restart", 1, 0, 0, 0
-+ };
-+ struct linuxthreads_signal linuxthreads_sig_cancel = {
-+ "__pthread_sig_cancel", 1, 0, 0, 0
-+ };
-+ struct linuxthreads_signal linuxthreads_sig_debug = {
-+ "__pthread_sig_debug", 0, 0, 0, 0
-+ };
-+
-+ /* A table of breakpoint locations, one per PID. */
-+ static struct linuxthreads_breakpoint {
-+ CORE_ADDR pc; /* PC of breakpoint */
-+ int pid; /* pid of breakpoint */
-+ int step; /* whether the pc has been reached after sstep */
-+ } *linuxthreads_breakpoint_zombie; /* Zombie breakpoints array */
-+ static int linuxthreads_breakpoint_last; /* Last zombie breakpoint */
-+
-+ /* linuxthreads_{insert,remove}_breakpoint pass the breakpoint address
-+ to {insert,remove}_breakpoint via this variable, since
-+ iterate_active_threads doesn't provide any way to pass values
-+ through to the worker function. */
-+ static CORE_ADDR linuxthreads_breakpoint_addr;
-+
-+ #define REMOVE_BREAKPOINT_ZOMBIE(_i) \
-+ { \
-+ if ((_i) < linuxthreads_breakpoint_last) \
-+ linuxthreads_breakpoint_zombie[(_i)] = \
-+ linuxthreads_breakpoint_zombie[linuxthreads_breakpoint_last]; \
-+ linuxthreads_breakpoint_last--; \
-+ }
-+
-+
-+ \f
-+ #ifndef PTRACE_XFER_TYPE
-+ #define PTRACE_XFER_TYPE int
-+ #endif
-+ /* Check to see if the given thread is alive. */
-+ static int
-+ linuxthreads_thread_alive (pid)
-+ int pid;
-+ {
-+ errno = 0;
-+ return ptrace (PT_READ_U, pid, (PTRACE_ARG3_TYPE)0, 0) >= 0 || errno == 0;
-+ }
-+
-+ /* On detach(), find a SIGTRAP status. If stop is non-zero, find a
-+ SIGSTOP one, too.
-+
-+ Make sure PID is ready to run, and free of interference from our
-+ efforts to debug it (e.g., pending SIGSTOP or SIGTRAP signals). If
-+ STOP is zero, just look for a SIGTRAP. If STOP is non-zero, look
-+ for a SIGSTOP, too. Return non-zero if PID is alive and ready to
-+ run; return zero if PID is dead.
-+
-+ PID may or may not be stopped at the moment, and we may or may not
-+ have waited for it already. We check the linuxthreads_wait bag in
-+ case we've already got a status for it. We may possibly wait for
-+ it ourselves.
-+
-+ PID may have signals waiting to be delivered. If they're caused by
-+ our efforts to debug it, accept them with wait, but don't pass them
-+ through to PID. Do pass all other signals through. */
-+ static int
-+ linuxthreads_find_trap (pid, stop)
-+ int pid;
-+ int stop;
-+ {
-+ int i;
-+ int rpid;
-+ int status;
-+ int found_stop = 0;
-+ int found_trap = 0;
-+
-+ /* PID may have any number of signals pending. The kernel will
-+ report each of them to us via wait, and then it's up to us to
-+ pass them along to the process via ptrace, if we so choose.
-+
-+ We need to paw through the whole set until we've found a SIGTRAP
-+ (or a SIGSTOP, if `stop' is set). We don't pass the SIGTRAP (or
-+ SIGSTOP) through, but we do re-send all the others, so PID will
-+ receive them when we resume it. */
-+ int *wstatus = alloca (LINUXTHREAD_NSIG * sizeof (int));
-+ int last = 0;
-+
-+ /* Look at the pending status */
-+ for (i = linuxthreads_wait_last; i >= 0; i--)
-+ if (linuxthreads_wait_pid[i] == pid)
-+ {
-+ status = linuxthreads_wait_status[i];
-+
-+ /* Delete the i'th member of the table. Since the table is
-+ unordered, we can do this simply by copying the table's
-+ last element to the i'th position, and shrinking the table
-+ by one element. */
-+ if (i < linuxthreads_wait_last)
-+ {
-+ linuxthreads_wait_status[i] =
-+ linuxthreads_wait_status[linuxthreads_wait_last];
-+ linuxthreads_wait_pid[i] =
-+ linuxthreads_wait_pid[linuxthreads_wait_last];
-+ }
-+ linuxthreads_wait_last--;
-+
-+ if (!WIFSTOPPED(status)) /* Thread has died */
-+ return 0;
-+
-+ if (WSTOPSIG(status) == SIGTRAP)
-+ {
-+ if (stop)
-+ found_trap = 1;
-+ else
-+ return 1;
-+ }
-+ else if (WSTOPSIG(status) == SIGSTOP)
-+ {
-+ if (stop)
-+ found_stop = 1;
-+ }
-+ else
-+ {
-+ wstatus[0] = status;
-+ last = 1;
-+ }
-+
-+ break;
-+ }
-+
-+ if (stop)
-+ {
-+ /* Make sure that we'll find what we're looking for. */
-+ if (!found_trap)
-+ kill (pid, SIGTRAP);
-+ if (!found_stop)
-+ kill (pid, SIGSTOP);
-+ }
-+
-+ /* Catch all status until SIGTRAP and optionally SIGSTOP show up. */
-+ for (;;)
-+ {
-+ child_resume (pid, 1, TARGET_SIGNAL_0);
-+
-+ for (;;)
-+ {
-+ rpid = waitpid (pid, &status, __WCLONE);
-+ if (rpid > 0)
-+ break;
-+ if (errno == EINTR)
-+ continue;
-+
-+ /* There are a few reasons the wait call above may have
-+ failed. If the thread manager dies, its children get
-+ reparented, and this interferes with GDB waiting for
-+ them, in some cases. Another possibility is that the
-+ initial thread was not cloned, so calling wait with
-+ __WCLONE won't find it. I think neither of these should
-+ occur in modern Linux kernels --- they don't seem to in
-+ 2.0.36. */
-+ rpid = waitpid (pid, &status, 0);
-+ if (rpid > 0)
-+ break;
-+ if (errno != EINTR)
-+ perror_with_name ("waitpid");
-+ }
-+
-+ if (!WIFSTOPPED(status)) /* Thread has died */
-+ return 0;
-+
-+ if (WSTOPSIG(status) == SIGTRAP)
-+ if (!stop || found_stop)
-+ break;
-+ else
-+ found_trap = 1;
-+ else if (WSTOPSIG(status) != SIGSTOP)
-+ wstatus[last++] = status;
-+ else if (stop)
-+ if (found_trap)
-+ break;
-+ else
-+ found_stop = 1;
-+ }
-+
-+ /* Resend any other signals we noticed to the thread, to be received
-+ when we continue it. */
-+ while (--last >= 0)
-+ kill (pid, WSTOPSIG(wstatus[last]));
-+
-+ return 1;
-+ }
-+
-+ /* Cleanup stub for save_inferior_pid. */
-+ static void
-+ restore_inferior_pid (arg)
-+ void *arg;
-+ {
-+ int pid = (int) arg;
-+ inferior_pid = pid;
-+ }
-+
-+ /* Register a cleanup to restore the value of inferior_pid. */
-+ static struct cleanup *
-+ save_inferior_pid ()
-+ {
-+ return make_cleanup (restore_inferior_pid, (void *) inferior_pid);
-+ }
-+
-+ static void
-+ sigchld_handler(signo)
-+ int signo;
-+ {
-+ /* This handler is used to get an EINTR while doing waitpid()
-+ when an event is received */
-+ }
-+
-+ /* Have we already collected a wait status for PID in the
-+ linuxthreads_wait bag? */
-+ static int
-+ linuxthreads_pending_status (pid)
-+ int pid;
-+ {
-+ int i;
-+ for (i = linuxthreads_wait_last; i >= 0; i--)
-+ if (linuxthreads_wait_pid[i] == pid)
-+ return 1;
-+ return 0;
-+ }
-+
-+ \f
-+ /* Internal linuxthreads signal management */
-+
-+ /* Check in OBJFILE for the variable that holds the number for signal SIG.
-+ We assume that we've already found other LinuxThreads-ish variables
-+ in OBJFILE, so we complain if it's required, but not there.
-+ Return true iff things are okay. */
-+ static int
-+ find_signal_var (struct linuxthreads_signal *sig,
-+ struct objfile *objfile)
-+ {
-+ struct minimal_symbol *ms = lookup_minimal_symbol (sig->var, NULL, objfile);
-+
-+ if (! ms)
-+ {
-+ if (sig->required)
-+ {
-+ fprintf_unfiltered (gdb_stderr,
-+ "Unable to find linuxthreads symbol \"%s\"\n",
-+ sig->var);
-+ return 0;
-+ }
-+ else
-+ {
-+ sig->addr = 0;
-+ return 1;
-+ }
-+ }
-+
-+ sig->addr = SYMBOL_VALUE_ADDRESS (ms);
-+
-+ return 1;
-+ }
-+
-+ static int
-+ find_all_signal_vars (struct objfile *objfile)
-+ {
-+ return ( find_signal_var (&linuxthreads_sig_restart, objfile)
-+ && find_signal_var (&linuxthreads_sig_cancel, objfile)
-+ && find_signal_var (&linuxthreads_sig_debug, objfile));
-+ }
-+
-+ /* A struct complaint isn't appropriate here. */
-+ static int complained_cannot_determine_thread_signal_number = 0;
-+
-+ /* Check to see if the variable holding the signal number for SIG has
-+ been initialized yet. If it has, tell GDB to pass that signal
-+ through to the inferior silently. */
-+ static void
-+ check_signal_number (struct linuxthreads_signal *sig)
-+ {
-+ int num;
-+
-+ if (sig->signal)
-+ /* We already know this signal number. */
-+ return;
-+
-+ if (! sig->addr)
-+ /* We don't know the variable's address yet. */
-+ return;
-+
-+ if (target_read_memory (sig->addr, (char *)&num, sizeof (num))
-+ != 0)
-+ {
-+ /* If this happens once, it'll probably happen for all the
-+ signals, so only complain once. */
-+ if (! complained_cannot_determine_thread_signal_number)
-+ warning ("Cannot determine thread signal number; "
-+ "GDB may report spurious signals.");
-+ complained_cannot_determine_thread_signal_number = 1;
-+ return;
-+ }
-+
-+ if (num == 0)
-+ /* It hasn't been initialized yet. */
-+ return;
-+
-+ /* We know sig->signal was zero, and is becoming non-zero, so it's
-+ okay to sample GDB's original settings. */
-+ sig->signal = num;
-+ sig->stop = signal_stop_update (target_signal_from_host (num), 0);
-+ sig->print = signal_print_update (target_signal_from_host (num), 0);
-+ }
-+
-+
-+ static void
-+ check_all_signal_numbers (void)
-+ {
-+ /* If this isn't a LinuxThreads program, quit early. */
-+ if (! linuxthreads_max)
-+ return;
-+
-+ check_signal_number (&linuxthreads_sig_restart);
-+ check_signal_number (&linuxthreads_sig_cancel);
-+ check_signal_number (&linuxthreads_sig_debug);
-+
-+ /* handle linuxthread exit */
-+ if (linuxthreads_sig_debug.signal
-+ || linuxthreads_sig_restart.signal)
-+ {
-+ struct sigaction sact;
-+
-+ sact.sa_handler = sigchld_handler;
-+ sigemptyset(&sact.sa_mask);
-+ sact.sa_flags = 0;
-+ if (linuxthreads_sig_debug.signal > 0)
-+ sigaction(linuxthreads_sig_cancel.signal, &sact, NULL);
-+ else
-+ sigaction(linuxthreads_sig_restart.signal, &sact, NULL);
-+ }
-+ }
-+
-+
-+ /* Restore GDB's original settings for SIG.
-+ This should only be called when we're no longer sure if we're
-+ talking to an executable that uses LinuxThreads, so we clear the
-+ signal number and variable address too. */
-+ static void
-+ restore_signal (struct linuxthreads_signal *sig)
-+ {
-+ if (! sig->signal)
-+ return;
-+
-+ /* We know sig->signal was non-zero, and is becoming zero, so it's
-+ okay to restore GDB's original settings. */
-+ signal_stop_update (target_signal_from_host (sig->signal), sig->stop);
-+ signal_print_update (target_signal_from_host (sig->signal), sig->print);
-+
-+ sig->signal = 0;
-+ sig->addr = 0;
-+ }
-+
-+
-+ /* Restore GDB's original settings for all LinuxThreads signals.
-+ This should only be called when we're no longer sure if we're
-+ talking to an executable that uses LinuxThreads, so we clear the
-+ signal number and variable address too. */
-+ static void
-+ restore_all_signals (void)
-+ {
-+ restore_signal (&linuxthreads_sig_restart);
-+ restore_signal (&linuxthreads_sig_cancel);
-+ restore_signal (&linuxthreads_sig_debug);
-+
-+ /* If it happens again, we should complain again. */
-+ complained_cannot_determine_thread_signal_number = 0;
-+ }
-+
-+
-+ \f
-+
-+ /* Apply FUNC to the pid of each active thread. This consults the
-+ inferior's handle table to find active threads.
-+
-+ If ALL is non-zero, process all threads.
-+ If ALL is zero, skip threads with pending status. */
-+ static void
-+ iterate_active_threads (func, all)
-+ void (*func)(int);
-+ int all;
-+ {
-+ CORE_ADDR descr;
-+ int pid;
-+ int i;
-+ int num;
-+
-+ read_memory (linuxthreads_num, (char *)&num, sizeof (int));
-+
-+ for (i = 0; i < linuxthreads_max && num > 0; i++)
-+ {
-+ read_memory (linuxthreads_handles +
-+ linuxthreads_sizeof_handle * i + linuxthreads_offset_descr,
-+ (char *)&descr, sizeof (void *));
-+ if (descr)
-+ {
-+ num--;
-+ read_memory (descr + linuxthreads_offset_pid,
-+ (char *)&pid, sizeof (pid_t));
-+ if (pid > 0 && pid != linuxthreads_manager_pid
-+ && (all || (!linuxthreads_pending_status (pid))))
-+ (*func)(pid);
-+ }
-+ }
-+
-+ }
-+
-+ /* Insert a thread breakpoint at linuxthreads_breakpoint_addr.
-+ This is the worker function for linuxthreads_insert_breakpoint,
-+ which passes it to iterate_active_threads. */
-+ static void
-+ insert_breakpoint (pid)
-+ int pid;
-+ {
-+ int j;
-+
-+ /* Remove (if any) the positive zombie breakpoint. */
-+ for (j = linuxthreads_breakpoint_last; j >= 0; j--)
-+ if (linuxthreads_breakpoint_zombie[j].pid == pid)
-+ {
-+ if ((linuxthreads_breakpoint_zombie[j].pc - DECR_PC_AFTER_BREAK
-+ == linuxthreads_breakpoint_addr)
-+ && !linuxthreads_breakpoint_zombie[j].step)
-+ REMOVE_BREAKPOINT_ZOMBIE(j);
-+ break;
-+ }
-+ }
-+
-+ /* Note that we're about to remove a thread breakpoint at
-+ linuxthreads_breakpoint_addr.
-+
-+ This is the worker function for linuxthreads_remove_breakpoint,
-+ which passes it to iterate_active_threads. The actual work of
-+ overwriting the breakpoint instruction is done by
-+ child_ops.to_remove_breakpoint; here, we simply create a zombie
-+ breakpoint if the thread's PC is pointing at the breakpoint being
-+ removed. */
-+ static void
-+ remove_breakpoint (pid)
-+ int pid;
-+ {
-+ int j;
-+
-+ /* Insert a positive zombie breakpoint (if needed). */
-+ for (j = 0; j <= linuxthreads_breakpoint_last; j++)
-+ if (linuxthreads_breakpoint_zombie[j].pid == pid)
-+ break;
-+
-+ if (in_thread_list (pid) && linuxthreads_thread_alive (pid))
-+ {
-+ CORE_ADDR pc = read_pc_pid (pid);
-+ if (linuxthreads_breakpoint_addr == pc - DECR_PC_AFTER_BREAK
-+ && j > linuxthreads_breakpoint_last)
-+ {
-+ linuxthreads_breakpoint_zombie[j].pid = pid;
-+ linuxthreads_breakpoint_zombie[j].pc = pc;
-+ linuxthreads_breakpoint_zombie[j].step = 0;
-+ linuxthreads_breakpoint_last++;
-+ }
-+ }
-+ }
-+
-+ /* Kill a thread */
-+ static void
-+ kill_thread (pid)
-+ int pid;
-+ {
-+ if (in_thread_list (pid))
-+ ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0);
-+ else
-+ kill (pid, SIGKILL);
-+ }
-+
-+ /* Resume a thread */
-+ static void
-+ resume_thread (pid)
-+ int pid;
-+ {
-+ if (pid != inferior_pid
-+ && in_thread_list (pid)
-+ && linuxthreads_thread_alive (pid))
-+ if (pid == linuxthreads_step_pid)
-+ child_resume (pid, 1, linuxthreads_step_signo);
-+ else
-+ child_resume (pid, 0, TARGET_SIGNAL_0);
-+ }
-+
-+ /* Detach a thread */
-+ static void
-+ detach_thread (pid)
-+ int pid;
-+ {
-+ if (in_thread_list (pid) && linuxthreads_thread_alive (pid))
-+ {
-+ /* Remove pending SIGTRAP and SIGSTOP */
-+ linuxthreads_find_trap (pid, 1);
-+
-+ inferior_pid = pid;
-+ detach (TARGET_SIGNAL_0);
-+ inferior_pid = linuxthreads_manager_pid;
-+ }
-+ }
-+
-+ /* Stop a thread */
-+ static void
-+ stop_thread (pid)
-+ int pid;
-+ {
-+ if (pid != inferior_pid)
-+ if (in_thread_list (pid))
-+ kill (pid, SIGSTOP);
-+ else if (ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0) == 0)
-+ {
-+ if (!linuxthreads_attach_pending)
-+ printf_unfiltered ("[New %s]\n", target_pid_to_str (pid));
-+ add_thread (pid);
-+ if (linuxthreads_sig_debug.signal)
-+ /* After a new thread in glibc 2.1 signals gdb its existence,
-+ it suspends itself and wait for linuxthreads_sig_restart,
-+ now we can wake up it. */
-+ kill (pid, linuxthreads_sig_restart.signal);
-+ }
-+ else
-+ perror_with_name ("ptrace in stop_thread");
-+ }
-+
-+ /* Wait for a thread */
-+ static void
-+ wait_thread (pid)
-+ int pid;
-+ {
-+ int status;
-+ int rpid;
-+
-+ if (pid != inferior_pid && in_thread_list (pid))
-+ {
-+ for (;;)
-+ {
-+ /* Get first pid status. */
-+ rpid = waitpid(pid, &status, __WCLONE);
-+ if (rpid > 0)
-+ break;
-+ if (errno == EINTR)
-+ continue;
-+
-+ /* There are two reasons this might have failed:
-+
-+ 1) PID is the initial thread, which wasn't cloned, so
-+ passing the __WCLONE flag to waitpid prevented us from
-+ finding it.
-+
-+ 2) The manager thread is the parent of all but the
-+ initial thread; if it dies, the children will all be
-+ reparented to init, which will wait for them. This means
-+ our call to waitpid won't find them.
-+
-+ Actually, based on a casual look at the 2.0.36 kernel
-+ code, I don't think either of these cases happen. But I
-+ don't have things set up for remotely debugging the
-+ kernel, so I'm not sure. And perhaps older kernels
-+ didn't work. */
-+ rpid = waitpid(pid, &status, 0);
-+ if (rpid > 0)
-+ break;
-+ if (errno != EINTR && linuxthreads_thread_alive (pid))
-+ perror_with_name ("waitpid");
-+
-+ /* the thread is dead. */
-+ return;
-+ }
-+ if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP)
-+ {
-+ linuxthreads_wait_pid[++linuxthreads_wait_last] = pid;
-+ linuxthreads_wait_status[linuxthreads_wait_last] = status;
-+ }
-+ }
-+ }
-+
-+ /* Walk through the linuxthreads handles in order to detect all
-+ threads and stop them */
-+ static void
-+ update_stop_threads (test_pid)
-+ int test_pid;
-+ {
-+ struct cleanup *old_chain = NULL;
-+
-+ check_all_signal_numbers ();
-+
-+ if (linuxthreads_manager_pid == 0)
-+ {
-+ if (linuxthreads_manager)
-+ {
-+ if (test_pid > 0 && test_pid != inferior_pid)
-+ {
-+ old_chain = save_inferior_pid ();
-+ inferior_pid = test_pid;
-+ }
-+ read_memory (linuxthreads_manager,
-+ (char *)&linuxthreads_manager_pid, sizeof (pid_t));
-+ }
-+ if (linuxthreads_initial)
-+ {
-+ if (test_pid > 0 && test_pid != inferior_pid)
-+ {
-+ old_chain = save_inferior_pid ();
-+ inferior_pid = test_pid;
-+ }
-+ read_memory(linuxthreads_initial,
-+ (char *)&linuxthreads_initial_pid, sizeof (pid_t));
-+ }
-+ }
-+
-+ if (linuxthreads_manager_pid != 0)
-+ {
-+ if (old_chain == NULL && test_pid > 0 &&
-+ test_pid != inferior_pid && linuxthreads_thread_alive (test_pid))
-+ {
-+ old_chain = save_inferior_pid ();
-+ inferior_pid = test_pid;
-+ }
-+
-+ if (linuxthreads_thread_alive (inferior_pid))
-+ {
-+ if (test_pid > 0)
-+ {
-+ if (test_pid != linuxthreads_manager_pid
-+ && !linuxthreads_pending_status (linuxthreads_manager_pid))
-+ {
-+ stop_thread (linuxthreads_manager_pid);
-+ wait_thread (linuxthreads_manager_pid);
-+ }
-+ if (!in_thread_list (test_pid))
-+ {
-+ if (!linuxthreads_attach_pending)
-+ printf_unfiltered ("[New %s]\n",
-+ target_pid_to_str (test_pid));
-+ add_thread (test_pid);
-+ if (linuxthreads_sig_debug.signal
-+ && inferior_pid == test_pid)
-+ /* After a new thread in glibc 2.1 signals gdb its
-+ existence, it suspends itself and wait for
-+ linuxthreads_sig_restart, now we can wake up
-+ it. */
-+ kill (test_pid, linuxthreads_sig_restart.signal);
-+ }
-+ }
-+ iterate_active_threads (stop_thread, 0);
-+ iterate_active_threads (wait_thread, 0);
-+ }
-+ }
-+
-+ if (old_chain != NULL)
-+ do_cleanups (old_chain);
-+ }
-+
-+ /* This routine is called whenever a new symbol table is read in, or when all
-+ symbol tables are removed. libpthread can only be initialized when it
-+ finds the right variables in libpthread.so. Since it's a shared library,
-+ those variables don't show up until the library gets mapped and the symbol
-+ table is read in. */
-+
-+ void
-+ linuxthreads_new_objfile (objfile)
-+ struct objfile *objfile;
-+ {
-+ struct minimal_symbol *ms;
-+
-+ if (!objfile)
-+ {
-+ /* We're starting an entirely new executable, so we can no
-+ longer be sure that it uses LinuxThreads. Restore the signal
-+ flags to their original states. */
-+ restore_all_signals ();
-+
-+ /* Indicate that we don't know anything's address any more. */
-+ linuxthreads_max = 0;
-+
-+ return;
-+ }
-+
-+ /* If we've already found our variables in another objfile, don't
-+ bother looking for them again. */
-+ if (linuxthreads_max)
-+ return;
-+
-+ if (! lookup_minimal_symbol ("__pthread_initial_thread", NULL, objfile))
-+ /* This object file isn't the pthreads library. */
-+ return;
-+
-+ if ((ms = lookup_minimal_symbol ("__pthread_threads_debug",
-+ NULL, objfile)) == NULL)
-+ {
-+ /* The debugging-aware libpthreads is not present in this objfile */
-+ warning ("\
-+ This program seems to use POSIX threads, but the thread library used\n\
-+ does not support debugging. This may make using GDB difficult. Don't\n\
-+ set breakpoints or single-step through code that might be executed by\n\
-+ any thread other than the main thread.");
-+ return;
-+ }
-+ linuxthreads_debug = SYMBOL_VALUE_ADDRESS (ms);
-+
-+ /* Read internal structures configuration */
-+ if ((ms = lookup_minimal_symbol ("__pthread_sizeof_handle",
-+ NULL, objfile)) == NULL
-+ || target_read_memory (SYMBOL_VALUE_ADDRESS (ms),
-+ (char *)&linuxthreads_sizeof_handle,
-+ sizeof (linuxthreads_sizeof_handle)) != 0)
-+ {
-+ fprintf_unfiltered (gdb_stderr,
-+ "Unable to find linuxthreads symbol \"%s\"\n",
-+ "__pthread_sizeof_handle");
-+ return;
-+ }
-+
-+ if ((ms = lookup_minimal_symbol ("__pthread_offsetof_descr",
-+ NULL, objfile)) == NULL
-+ || target_read_memory (SYMBOL_VALUE_ADDRESS (ms),
-+ (char *)&linuxthreads_offset_descr,
-+ sizeof (linuxthreads_offset_descr)) != 0)
-+ {
-+ fprintf_unfiltered (gdb_stderr,
-+ "Unable to find linuxthreads symbol \"%s\"\n",
-+ "__pthread_offsetof_descr");
-+ return;
-+ }
-+
-+ if ((ms = lookup_minimal_symbol ("__pthread_offsetof_pid",
-+ NULL, objfile)) == NULL
-+ || target_read_memory (SYMBOL_VALUE_ADDRESS (ms),
-+ (char *)&linuxthreads_offset_pid,
-+ sizeof (linuxthreads_offset_pid)) != 0)
-+ {
-+ fprintf_unfiltered (gdb_stderr,
-+ "Unable to find linuxthreads symbol \"%s\"\n",
-+ "__pthread_offsetof_pid");
-+ return;
-+ }
-+
-+ if (! find_all_signal_vars (objfile))
-+ return;
-+
-+ /* Read adresses of internal structures to access */
-+ if ((ms = lookup_minimal_symbol ("__pthread_handles",
-+ NULL, objfile)) == NULL)
-+ {
-+ fprintf_unfiltered (gdb_stderr,
-+ "Unable to find linuxthreads symbol \"%s\"\n",
-+ "__pthread_handles");
-+ return;
-+ }
-+ linuxthreads_handles = SYMBOL_VALUE_ADDRESS (ms);
-+
-+ if ((ms = lookup_minimal_symbol ("__pthread_handles_num",
-+ NULL, objfile)) == NULL)
-+ {
-+ fprintf_unfiltered (gdb_stderr,
-+ "Unable to find linuxthreads symbol \"%s\"\n",
-+ "__pthread_handles_num");
-+ return;
-+ }
-+ linuxthreads_num = SYMBOL_VALUE_ADDRESS (ms);
-+
-+ if ((ms = lookup_minimal_symbol ("__pthread_manager_thread",
-+ NULL, objfile)) == NULL)
-+ {
-+ fprintf_unfiltered (gdb_stderr,
-+ "Unable to find linuxthreads symbol \"%s\"\n",
-+ "__pthread_manager_thread");
-+ return;
-+ }
-+ linuxthreads_manager = SYMBOL_VALUE_ADDRESS (ms) + linuxthreads_offset_pid;
-+
-+ if ((ms = lookup_minimal_symbol ("__pthread_initial_thread",
-+ NULL, objfile)) == NULL)
-+ {
-+ fprintf_unfiltered (gdb_stderr,
-+ "Unable to find linuxthreads symbol \"%s\"\n",
-+ "__pthread_initial_thread");
-+ return;
-+ }
-+ linuxthreads_initial = SYMBOL_VALUE_ADDRESS (ms) + linuxthreads_offset_pid;
-+
-+ /* Search for this last, so it won't be set to a non-zero value unless
-+ we successfully found all the symbols above. */
-+ if ((ms = lookup_minimal_symbol ("__pthread_threads_max",
-+ NULL, objfile)) == NULL
-+ || target_read_memory (SYMBOL_VALUE_ADDRESS (ms),
-+ (char *)&linuxthreads_max,
-+ sizeof (linuxthreads_max)) != 0)
-+ {
-+ fprintf_unfiltered (gdb_stderr,
-+ "Unable to find linuxthreads symbol \"%s\"\n",
-+ "__pthread_threads_max");
-+ return;
-+ }
-+
-+ /* Allocate gdb internal structures */
-+ linuxthreads_wait_pid =
-+ (int *)xmalloc (sizeof (int) * (linuxthreads_max + 1));
-+ linuxthreads_wait_status =
-+ (int *)xmalloc (sizeof (int) * (linuxthreads_max + 1));
-+ linuxthreads_breakpoint_zombie = (struct linuxthreads_breakpoint *)
-+ xmalloc (sizeof (struct linuxthreads_breakpoint) * (linuxthreads_max + 1));
-+
-+ if (inferior_pid && !linuxthreads_attach_pending)
-+ {
-+ int on = 1;
-+ target_write_memory (linuxthreads_debug, (char *)&on, sizeof (on));
-+ linuxthreads_attach_pending = 1;
-+ update_stop_threads (inferior_pid);
-+ linuxthreads_attach_pending = 0;
-+ }
-+ }
-+
-+ /* If we have switched threads from a one that stopped at breakpoint,
-+ return 1 otherwise 0. */
-+
-+ int
-+ linuxthreads_prepare_to_proceed (step)
-+ int step;
-+ {
-+ if (!linuxthreads_max
-+ || !linuxthreads_manager_pid
-+ || !linuxthreads_breakpoint_pid
-+ || !breakpoint_here_p (read_pc_pid (linuxthreads_breakpoint_pid)))
-+ return 0;
-+
-+ if (step)
-+ {
-+ /* Mark the current inferior as single stepping process. */
-+ linuxthreads_step_pid = inferior_pid;
-+ }
-+
-+ linuxthreads_inferior_pid = linuxthreads_breakpoint_pid;
-+ return linuxthreads_breakpoint_pid;
-+ }
-+
-+ /* Convert a pid to printable form. */
-+
-+ char *
-+ linuxthreads_pid_to_str (pid)
-+ int pid;
-+ {
-+ static char buf[100];
-+
-+ sprintf (buf, "%s %d%s", linuxthreads_max ? "Thread" : "Pid", pid,
-+ (pid == linuxthreads_manager_pid) ? " (manager thread)"
-+ : (pid == linuxthreads_initial_pid) ? " (initial thread)"
-+ : "");
-+
-+ return buf;
-+ }
-+
-+ /* Attach to process PID, then initialize for debugging it
-+ and wait for the trace-trap that results from attaching. */
-+
-+ static void
-+ linuxthreads_attach (args, from_tty)
-+ char *args;
-+ int from_tty;
-+ {
-+ if (!args)
-+ error_no_arg ("process-id to attach");
-+
-+ push_target (&linuxthreads_ops);
-+ linuxthreads_breakpoints_inserted = 1;
-+ linuxthreads_breakpoint_last = -1;
-+ linuxthreads_wait_last = -1;
-+ linuxthreads_exit_status = __W_STOPCODE(0);
-+
-+ child_ops.to_attach (args, from_tty);
-+
-+ if (linuxthreads_max)
-+ linuxthreads_attach_pending = 1;
-+ }
-+
-+ /* Take a program previously attached to and detaches it.
-+ The program resumes execution and will no longer stop
-+ on signals, etc. We'd better not have left any breakpoints
-+ in the program or it'll die when it hits one. For this
-+ to work, it may be necessary for the process to have been
-+ previously attached. It *might* work if the program was
-+ started via the normal ptrace (PTRACE_TRACEME). */
-+
-+ static void
-+ linuxthreads_detach (args, from_tty)
-+ char *args;
-+ int from_tty;
-+ {
-+ if (linuxthreads_max)
-+ {
-+ int i;
-+ int pid;
-+ int off = 0;
-+ target_write_memory (linuxthreads_debug, (char *)&off, sizeof (off));
-+
-+ /* Walk through linuxthreads array in order to detach known threads. */
-+ if (linuxthreads_manager_pid != 0)
-+ {
-+ /* Get rid of all positive zombie breakpoints. */
-+ for (i = 0; i <= linuxthreads_breakpoint_last; i++)
-+ {
-+ if (linuxthreads_breakpoint_zombie[i].step)
-+ continue;
-+
-+ pid = linuxthreads_breakpoint_zombie[i].pid;
-+ if (!linuxthreads_thread_alive (pid))
-+ continue;
-+
-+ if (linuxthreads_breakpoint_zombie[i].pc != read_pc_pid (pid))
-+ continue;
-+
-+ /* Continue in STEP mode until the thread pc has moved or
-+ until SIGTRAP is found on the same PC. */
-+ if (linuxthreads_find_trap (pid, 0)
-+ && linuxthreads_breakpoint_zombie[i].pc == read_pc_pid (pid))
-+ write_pc_pid (linuxthreads_breakpoint_zombie[i].pc
-+ - DECR_PC_AFTER_BREAK, pid);
-+ }
-+
-+ /* Detach thread after thread. */
-+ inferior_pid = linuxthreads_manager_pid;
-+ iterate_active_threads (detach_thread, 1);
-+
-+ /* Remove pending SIGTRAP and SIGSTOP */
-+ linuxthreads_find_trap (inferior_pid, 1);
-+
-+ linuxthreads_wait_last = -1;
-+ linuxthreads_exit_status = __W_STOPCODE(0);
-+ }
-+
-+ linuxthreads_inferior_pid = 0;
-+ linuxthreads_breakpoint_pid = 0;
-+ linuxthreads_step_pid = 0;
-+ linuxthreads_step_signo = TARGET_SIGNAL_0;
-+ linuxthreads_manager_pid = 0;
-+ linuxthreads_initial_pid = 0;
-+ linuxthreads_attach_pending = 0;
-+ init_thread_list (); /* Destroy thread info */
-+ }
-+
-+ child_ops.to_detach (args, from_tty);
-+
-+ unpush_target (&linuxthreads_ops);
-+ }
-+
-+ /* Resume execution of process PID. If STEP is nozero, then
-+ just single step it. If SIGNAL is nonzero, restart it with that
-+ signal activated. */
-+
-+ static void
-+ linuxthreads_resume (pid, step, signo)
-+ int pid;
-+ int step;
-+ enum target_signal signo;
-+ {
-+ if (!linuxthreads_max || stop_soon_quietly || linuxthreads_manager_pid == 0)
-+ child_ops.to_resume (pid, step, signo);
-+ else
-+ {
-+ int rpid;
-+ if (linuxthreads_inferior_pid)
-+ {
-+ /* Prepare resume of the last thread that hit a breakpoint */
-+ linuxthreads_breakpoints_inserted = 0;
-+ rpid = linuxthreads_inferior_pid;
-+ linuxthreads_step_signo = signo;
-+ }
-+ else
-+ {
-+ struct cleanup *old_chain = NULL;
-+ int i;
-+
-+ if (pid < 0)
-+ {
-+ linuxthreads_step_pid = step ? inferior_pid : 0;
-+ linuxthreads_step_signo = signo;
-+ rpid = inferior_pid;
-+ }
-+ else
-+ rpid = pid;
-+
-+ if (pid < 0 || !step)
-+ {
-+ linuxthreads_breakpoints_inserted = 1;
-+
-+ /* Walk through linuxthreads array in order to resume threads */
-+ if (pid >= 0 && inferior_pid != pid)
-+ {
-+ old_chain = save_inferior_pid ();
-+ inferior_pid = pid;
-+ }
-+
-+ iterate_active_threads (resume_thread, 0);
-+ if (linuxthreads_manager_pid != inferior_pid
-+ && !linuxthreads_pending_status (linuxthreads_manager_pid))
-+ resume_thread (linuxthreads_manager_pid);
-+ }
-+ else
-+ linuxthreads_breakpoints_inserted = 0;
-+
-+ /* Deal with zombie breakpoint */
-+ for (i = 0; i <= linuxthreads_breakpoint_last; i++)
-+ if (linuxthreads_breakpoint_zombie[i].pid == rpid)
-+ {
-+ if (linuxthreads_breakpoint_zombie[i].pc != read_pc_pid (rpid))
-+ {
-+ /* The current pc is out of zombie breakpoint. */
-+ REMOVE_BREAKPOINT_ZOMBIE(i);
-+ }
-+ break;
-+ }
-+
-+ if (old_chain != NULL)
-+ do_cleanups (old_chain);
-+ }
-+
-+ /* Resume initial thread. */
-+ if (!linuxthreads_pending_status (rpid))
-+ child_ops.to_resume (rpid, step, signo);
-+ }
-+ }
-+
-+ /* Wait for any threads to stop. We may have to convert PID from a thread id
-+ to a LWP id, and vice versa on the way out. */
-+
-+ static int
-+ linuxthreads_wait (int pid, struct target_waitstatus *ourstatus)
-+ {
-+ int status;
-+ int rpid;
-+ int i;
-+ int last;
-+ int *wstatus;
-+
-+ if (linuxthreads_max && !linuxthreads_breakpoints_inserted)
-+ wstatus = alloca (LINUXTHREAD_NSIG * sizeof (int));
-+
-+ /* See if the inferior has chosen values for its signals yet. By
-+ checking for them here, we can be sure we've updated GDB's signal
-+ handling table before the inferior ever gets one of them. (Well,
-+ before we notice, anyway.) */
-+ check_all_signal_numbers ();
-+
-+ for (;;)
-+ {
-+ if (!linuxthreads_max)
-+ rpid = 0;
-+ else if (!linuxthreads_breakpoints_inserted)
-+ {
-+ if (linuxthreads_inferior_pid)
-+ pid = linuxthreads_inferior_pid;
-+ else if (pid < 0)
-+ pid = inferior_pid;
-+ last = rpid = 0;
-+ }
-+ else if (pid < 0 && linuxthreads_wait_last >= 0)
-+ {
-+ status = linuxthreads_wait_status[linuxthreads_wait_last];
-+ rpid = linuxthreads_wait_pid[linuxthreads_wait_last--];
-+ }
-+ else if (pid > 0 && linuxthreads_pending_status (pid))
-+ {
-+ for (i = linuxthreads_wait_last; i >= 0; i--)
-+ if (linuxthreads_wait_pid[i] == pid)
-+ break;
-+ if (i < 0)
-+ rpid = 0;
-+ else
-+ {
-+ status = linuxthreads_wait_status[i];
-+ rpid = pid;
-+ if (i < linuxthreads_wait_last)
-+ {
-+ linuxthreads_wait_status[i] =
-+ linuxthreads_wait_status[linuxthreads_wait_last];
-+ linuxthreads_wait_pid[i] =
-+ linuxthreads_wait_pid[linuxthreads_wait_last];
-+ }
-+ linuxthreads_wait_last--;
-+ }
-+ }
-+ else
-+ rpid = 0;
-+
-+ if (rpid == 0)
-+ {
-+ int save_errno;
-+ sigset_t omask;
-+
-+ set_sigint_trap(); /* Causes SIGINT to be passed on to the
-+ attached process. */
-+ set_sigio_trap ();
-+
-+ sigprocmask(SIG_BLOCK, &linuxthreads_wait_mask, &omask);
-+ for (;;)
-+ {
-+ rpid = waitpid (pid, &status, __WCLONE | WNOHANG);
-+ if (rpid > 0)
-+ break;
-+ if (rpid == 0)
-+ save_errno = 0;
-+ else if (errno != EINTR)
-+ save_errno = errno;
-+ else
-+ continue;
-+
-+ rpid = waitpid (pid, &status, WNOHANG);
-+ if (rpid > 0)
-+ break;
-+ if (rpid < 0)
-+ if (errno == EINTR)
-+ continue;
-+ else if (save_errno != 0)
-+ break;
-+
-+ sigsuspend(&omask);
-+ }
-+ sigprocmask(SIG_SETMASK, &omask, NULL);
-+
-+ save_errno = errno;
-+ clear_sigio_trap ();
-+
-+ clear_sigint_trap();
-+
-+ if (rpid == -1)
-+ {
-+ if (WIFEXITED(linuxthreads_exit_status))
-+ {
-+ store_waitstatus (ourstatus, linuxthreads_exit_status);
-+ return inferior_pid;
-+ }
-+ else
-+ {
-+ fprintf_unfiltered
-+ (gdb_stderr, "Child process unexpectedly missing: %s.\n",
-+ safe_strerror (save_errno));
-+ /* Claim it exited with unknown signal. */
-+ ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-+ ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
-+ return -1;
-+ }
-+ }
-+
-+ /* Signals arrive in any order. So get all signals until SIGTRAP
-+ and resend previous ones to be held after. */
-+ if (linuxthreads_max
-+ && !linuxthreads_breakpoints_inserted
-+ && WIFSTOPPED(status))
-+ if (WSTOPSIG(status) == SIGTRAP)
-+ {
-+ while (--last >= 0)
-+ kill (rpid, WSTOPSIG(wstatus[last]));
-+
-+ /* insert negative zombie breakpoint */
-+ for (i = 0; i <= linuxthreads_breakpoint_last; i++)
-+ if (linuxthreads_breakpoint_zombie[i].pid == rpid)
-+ break;
-+ if (i > linuxthreads_breakpoint_last)
-+ {
-+ linuxthreads_breakpoint_zombie[i].pid = rpid;
-+ linuxthreads_breakpoint_last++;
-+ }
-+ linuxthreads_breakpoint_zombie[i].pc = read_pc_pid (rpid);
-+ linuxthreads_breakpoint_zombie[i].step = 1;
-+ }
-+ else
-+ {
-+ if (WSTOPSIG(status) != SIGSTOP)
-+ {
-+ for (i = 0; i < last; i++)
-+ if (wstatus[i] == status)
-+ break;
-+ if (i >= last)
-+ wstatus[last++] = status;
-+ }
-+ child_resume (rpid, 1, TARGET_SIGNAL_0);
-+ continue;
-+ }
-+ if (linuxthreads_inferior_pid)
-+ linuxthreads_inferior_pid = 0;
-+ }
-+
-+ if (linuxthreads_max && !stop_soon_quietly)
-+ {
-+ if (linuxthreads_max
-+ && WIFSTOPPED(status)
-+ && WSTOPSIG(status) == SIGSTOP)
-+ {
-+ /* Skip SIGSTOP signals. */
-+ if (!linuxthreads_pending_status (rpid))
-+ if (linuxthreads_step_pid == rpid)
-+ child_resume (rpid, 1, linuxthreads_step_signo);
-+ else
-+ child_resume (rpid, 0, TARGET_SIGNAL_0);
-+ continue;
-+ }
-+
-+ /* Do no report exit status of cloned threads. */
-+ if (WIFEXITED(status))
-+ {
-+ if (rpid == linuxthreads_initial_pid)
-+ linuxthreads_exit_status = status;
-+
-+ /* Remove any zombie breakpoint. */
-+ for (i = 0; i <= linuxthreads_breakpoint_last; i++)
-+ if (linuxthreads_breakpoint_zombie[i].pid == rpid)
-+ {
-+ REMOVE_BREAKPOINT_ZOMBIE(i);
-+ break;
-+ }
-+ if (pid > 0)
-+ pid = -1;
-+ continue;
-+ }
-+
-+ /* Deal with zombie breakpoint */
-+ for (i = 0; i <= linuxthreads_breakpoint_last; i++)
-+ if (linuxthreads_breakpoint_zombie[i].pid == rpid)
-+ break;
-+
-+ if (i <= linuxthreads_breakpoint_last)
-+ {
-+ /* There is a potential zombie breakpoint */
-+ if (WIFEXITED(status)
-+ || linuxthreads_breakpoint_zombie[i].pc != read_pc_pid (rpid))
-+ {
-+ /* The current pc is out of zombie breakpoint. */
-+ REMOVE_BREAKPOINT_ZOMBIE(i);
-+ }
-+ else if (!linuxthreads_breakpoint_zombie[i].step
-+ && WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
-+ {
-+ /* This is a real one ==> decrement PC and restart. */
-+ write_pc_pid (linuxthreads_breakpoint_zombie[i].pc
-+ - DECR_PC_AFTER_BREAK, rpid);
-+ if (linuxthreads_step_pid == rpid)
-+ child_resume (rpid, 1, linuxthreads_step_signo);
-+ else
-+ child_resume (rpid, 0, TARGET_SIGNAL_0);
-+ continue;
-+ }
-+ }
-+
-+ /* Walk through linuxthreads array in order to stop them */
-+ if (linuxthreads_breakpoints_inserted)
-+ update_stop_threads (rpid);
-+
-+ }
-+ else if (rpid != inferior_pid)
-+ continue;
-+
-+ store_waitstatus (ourstatus, status);
-+
-+ if (linuxthreads_attach_pending && !stop_soon_quietly)
-+ {
-+ int on = 1;
-+ target_write_memory (linuxthreads_debug, (char *)&on, sizeof (on));
-+ update_stop_threads (rpid);
-+ linuxthreads_attach_pending = 0;
-+ }
-+
-+ if (linuxthreads_breakpoints_inserted
-+ && WIFSTOPPED(status)
-+ && WSTOPSIG(status) == SIGTRAP)
-+ linuxthreads_breakpoint_pid = rpid;
-+ else if (linuxthreads_breakpoint_pid)
-+ linuxthreads_breakpoint_pid = 0;
-+
-+ return rpid;
-+ }
-+ }
-+
-+ /* Fork an inferior process, and start debugging it with ptrace. */
-+
-+ static void
-+ linuxthreads_create_inferior (exec_file, allargs, env)
-+ char *exec_file;
-+ char *allargs;
-+ char **env;
-+ {
-+ if (!exec_file && !exec_bfd)
-+ {
-+ error ("No executable file specified.\n\
-+ Use the \"file\" or \"exec-file\" command.");
-+ return;
-+ }
-+
-+ push_target (&linuxthreads_ops);
-+ linuxthreads_breakpoints_inserted = 1;
-+ linuxthreads_breakpoint_last = -1;
-+ linuxthreads_wait_last = -1;
-+ linuxthreads_exit_status = __W_STOPCODE(0);
-+
-+ if (linuxthreads_max)
-+ linuxthreads_attach_pending = 1;
-+
-+ child_ops.to_create_inferior (exec_file, allargs, env);
-+ }
-+
-+ /* Clean up after the inferior dies. */
-+
-+ static void
-+ linuxthreads_mourn_inferior ()
-+ {
-+ if (linuxthreads_max)
-+ {
-+ int off = 0;
-+ target_write_memory (linuxthreads_debug, (char *)&off, sizeof (off));
-+
-+ linuxthreads_inferior_pid = 0;
-+ linuxthreads_breakpoint_pid = 0;
-+ linuxthreads_step_pid = 0;
-+ linuxthreads_step_signo = TARGET_SIGNAL_0;
-+ linuxthreads_manager_pid = 0;
-+ linuxthreads_initial_pid = 0;
-+ linuxthreads_attach_pending = 0;
-+ init_thread_list(); /* Destroy thread info */
-+ }
-+
-+ child_ops.to_mourn_inferior ();
-+
-+ unpush_target (&linuxthreads_ops);
-+ }
-+
-+ /* Kill the inferior process */
-+
-+ static void
-+ linuxthreads_kill ()
-+ {
-+ int rpid;
-+ int status;
-+
-+ if (inferior_pid == 0)
-+ return;
-+
-+ if (linuxthreads_max && linuxthreads_manager_pid != 0)
-+ {
-+ /* Remove all threads status. */
-+ inferior_pid = linuxthreads_manager_pid;
-+ iterate_active_threads (kill_thread, 1);
-+ }
-+
-+ kill_thread (inferior_pid);
-+
-+ #if 0
-+ /* doing_quit_force solves a real problem, but I think a properly
-+ placed call to catch_errors would do the trick much more cleanly. */
-+ if (doing_quit_force >= 0)
-+ {
-+ if (linuxthreads_max && linuxthreads_manager_pid != 0)
-+ {
-+ /* Wait for thread to complete */
-+ while ((rpid = waitpid (-1, &status, __WCLONE)) > 0)
-+ if (!WIFEXITED(status))
-+ kill_thread (rpid);
-+
-+ while ((rpid = waitpid (-1, &status, 0)) > 0)
-+ if (!WIFEXITED(status))
-+ kill_thread (rpid);
-+ }
-+ else
-+ while ((rpid = waitpid (inferior_pid, &status, 0)) > 0)
-+ if (!WIFEXITED(status))
-+ ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0);
-+ }
-+ #endif
-+
-+ /* Wait for all threads. */
-+ do
-+ rpid = waitpid (-1, &status, __WCLONE | WNOHANG);
-+ while (rpid > 0 || errno == EINTR);
-+
-+ do
-+ rpid = waitpid (-1, &status, WNOHANG);
-+ while (rpid > 0 || errno == EINTR);
-+
-+ linuxthreads_mourn_inferior ();
-+ }
-+
-+ /* Insert a breakpoint */
-+
-+ static int
-+ linuxthreads_insert_breakpoint (addr, contents_cache)
-+ CORE_ADDR addr;
-+ char *contents_cache;
-+ {
-+ if (linuxthreads_max && linuxthreads_manager_pid != 0)
-+ {
-+ linuxthreads_breakpoint_addr = addr;
-+ iterate_active_threads (insert_breakpoint, 1);
-+ insert_breakpoint (linuxthreads_manager_pid);
-+ }
-+
-+ return child_ops.to_insert_breakpoint (addr, contents_cache);
-+ }
-+
-+ /* Remove a breakpoint */
-+
-+ static int
-+ linuxthreads_remove_breakpoint (addr, contents_cache)
-+ CORE_ADDR addr;
-+ char *contents_cache;
-+ {
-+ if (linuxthreads_max && linuxthreads_manager_pid != 0)
-+ {
-+ linuxthreads_breakpoint_addr = addr;
-+ iterate_active_threads (remove_breakpoint, 1);
-+ remove_breakpoint (linuxthreads_manager_pid);
-+ }
-+
-+ return child_ops.to_remove_breakpoint (addr, contents_cache);
-+ }
-+
-+ /* Mark our target-struct as eligible for stray "run" and "attach" commands. */
-+
-+ static int
-+ linuxthreads_can_run ()
-+ {
-+ return child_suppress_run;
-+ }
-+ \f
-+ static void
-+ init_linuxthreads_ops ()
-+ {
-+ linuxthreads_ops.to_shortname = "linuxthreads";
-+ linuxthreads_ops.to_longname = "LINUX threads and pthread.";
-+ linuxthreads_ops.to_doc = "LINUX threads and pthread support.";
-+ linuxthreads_ops.to_attach = linuxthreads_attach;
-+ linuxthreads_ops.to_detach = linuxthreads_detach;
-+ linuxthreads_ops.to_resume = linuxthreads_resume;
-+ linuxthreads_ops.to_wait = linuxthreads_wait;
-+ linuxthreads_ops.to_kill = linuxthreads_kill;
-+ linuxthreads_ops.to_can_run = linuxthreads_can_run;
-+ linuxthreads_ops.to_stratum = thread_stratum;
-+ linuxthreads_ops.to_insert_breakpoint = linuxthreads_insert_breakpoint;
-+ linuxthreads_ops.to_remove_breakpoint = linuxthreads_remove_breakpoint;
-+ linuxthreads_ops.to_create_inferior = linuxthreads_create_inferior;
-+ linuxthreads_ops.to_mourn_inferior = linuxthreads_mourn_inferior;
-+ linuxthreads_ops.to_thread_alive = linuxthreads_thread_alive;
-+ linuxthreads_ops.to_magic = OPS_MAGIC;
-+ }
-+
-+ void
-+ _initialize_linuxthreads ()
-+ {
-+ struct sigaction sact;
-+
-+ init_linuxthreads_ops ();
-+ add_target (&linuxthreads_ops);
-+ child_suppress_run = 1;
-+
-+ /* Attach SIGCHLD handler */
-+ sact.sa_handler = sigchld_handler;
-+ sigemptyset (&sact.sa_mask);
-+ sact.sa_flags = 0;
-+ sigaction (SIGCHLD, &sact, NULL);
-+
-+ /* initialize SIGCHLD mask */
-+ sigemptyset (&linuxthreads_wait_mask);
-+ sigaddset (&linuxthreads_wait_mask, SIGCHLD);
-+ }
-diff -Ncr /home/kingdon/work/gdb/gdb/target.c ./gdb/target.c
-*** /home/kingdon/work/gdb/gdb/target.c Thu Aug 12 11:13:38 1999
---- ./gdb/target.c Sat Aug 14 19:49:45 1999
-***************
-*** 1238,1243 ****
---- 1238,1244 ----
- {"SIG61", "Real-time event 61"},
- {"SIG62", "Real-time event 62"},
- {"SIG63", "Real-time event 63"},
-+ {"SIG32", "Real-time event 32"},
-
- #if defined(MACH) || defined(__MACH__)
- /* Mach exceptions */
-***************
-*** 1571,1578 ****
-
- #if defined (REALTIME_LO)
- if (hostsig >= REALTIME_LO && hostsig < REALTIME_HI)
-! return (enum target_signal)
-! (hostsig - 33 + (int) TARGET_SIGNAL_REALTIME_33);
- #endif
- return TARGET_SIGNAL_UNKNOWN;
- }
---- 1572,1587 ----
-
- #if defined (REALTIME_LO)
- if (hostsig >= REALTIME_LO && hostsig < REALTIME_HI)
-! {
-! /* This block of TARGET_SIGNAL_REALTIME value is in order. */
-! if (33 <= hostsig && hostsig <= 63)
-! return (enum target_signal)
-! (hostsig - 33 + (int) TARGET_SIGNAL_REALTIME_33);
-! else if (hostsig == 32)
-! return TARGET_SIGNAL_REALTIME_32;
-! else
-! error ("GDB bug: target.c (target_signal_from_host): unrecognized real-time signal");
-! }
- #endif
- return TARGET_SIGNAL_UNKNOWN;
- }
-***************
-*** 1619,1624 ****
---- 1628,1635 ----
- case TARGET_SIGNAL_PRIO:
- return SIGPRIO;
- #endif
-+
-+ case TARGET_SIGNAL_REALTIME_32: return 32; /* by definition */
-
- /* Mach exceptions. Assumes that the values for EXC_ are positive! */
- #if defined (EXC_BAD_ACCESS) && defined (_NSIG)
-diff -Ncr /home/kingdon/work/gdb/gdb/target.h ./gdb/target.h
-*** /home/kingdon/work/gdb/gdb/target.h Thu Aug 12 11:13:38 1999
---- ./gdb/target.h Sat Aug 14 19:07:48 1999
-***************
-*** 48,54 ****
- file_stratum, /* Executable files, etc */
- core_stratum, /* Core dump files */
- download_stratum, /* Downloading of remote targets */
-! process_stratum /* Executing processes */
- };
-
- enum thread_control_capabilities {
---- 48,55 ----
- file_stratum, /* Executable files, etc */
- core_stratum, /* Core dump files */
- download_stratum, /* Downloading of remote targets */
-! process_stratum, /* Executing processes */
-! thread_stratum /* Executing threads */
- };
-
- enum thread_control_capabilities {
-***************
-*** 214,219 ****
---- 215,227 ----
- TARGET_EXC_SOFTWARE = 80,
- TARGET_EXC_BREAKPOINT = 81,
- #endif
-+
-+ /* Yes, this pains me, too. But LynxOS didn't have SIG32, and now
-+ Linux does, and we can't disturb the numbering, since it's part
-+ of the protocol. Note that in some GDB's TARGET_SIGNAL_REALTIME_32
-+ is number 76. */
-+ TARGET_SIGNAL_REALTIME_32,
-+
- /* Some signal we don't know about. */
- TARGET_SIGNAL_UNKNOWN,
-