From 3780c3370815a315927580bcd22ce5e361cc9950 Mon Sep 17 00:00:00 2001 From: Michael Snyder Date: Wed, 21 May 1997 23:33:33 +0000 Subject: [PATCH] Wed May 21 16:03:25 1997 Michael Snyder * procfs.c (init_procinfo): new function, abstracts some code shared by create_procinfo and do_attach; (procfs_set_inferior_syscall_traps): new function, abstracts some code needed by procfs_init_inferior, do_attach, and procfs_lwp_creation_handler; (procfs_first_available): new function, find any LWP that's runnable; (procfs_thread_alive): replace stub function with real implementation; (procfs_lwp_creation_handler): fix bug starting new child threads; (info_proc): bug fixes and enhancements for the "INFO PROCESSES" command; (close_procinfo_file): call new function "delete_thread" to cleanup GDB's thread database; (proc_init_failed): add new argument "kill", to control whether process is killed (so this function can be shared by create_procinfo and do_attach); (procfs_exit_handler): handle exit from an attached process, and cleanup procinfo handles when the process exits; (procfs_resume, procfs_wait): cleanup after a thread when it exits; (do_attach, do_detach): handle attached processes with multiple threads; plus some general improvements in the diagnostic output. * sol-thread.c (sol_thread_alive): replace stub with real implementation; (thread_to_lwp, lwp_to_thread): enhance to handle threads that may have exited; (sol_thread_attach): add startup setup stuff; (sol_thread_detach): add unpush_target call; (sol_thread_mourn_inferior): add unpush_target call; (sol_thread_wait, sol_thread_resume): enhance to deal with thread exit cleanly; (sol_thread_new_objfile, sol_thread_pid_to_str): detect unsuccessful startup and don't crash; plus some general cleanup. * thread.c (delete_thread): new function, allows targets to notify gdb when a thread is no longer valid. * infrun.c (wait_for_inferior): don't try to detect a new thread on receiving a TARGET_EXITED event. --- gdb/ChangeLog | 40 +++ gdb/procfs.c | 858 +++++++++++++++++++++++++++++++++---------------------- gdb/sol-thread.c | 167 ++++++++--- gdb/thread.c | 30 +- 4 files changed, 715 insertions(+), 380 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8fdbff9..17ba1e8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,43 @@ +Wed May 21 16:03:25 1997 Michael Snyder + + * procfs.c (init_procinfo): new function, abstracts some code + shared by create_procinfo and do_attach; + (procfs_set_inferior_syscall_traps): new function, abstracts + some code needed by procfs_init_inferior, do_attach, and + procfs_lwp_creation_handler; (procfs_first_available): new + function, find any LWP that's runnable; (procfs_thread_alive): + replace stub function with real implementation; + (procfs_lwp_creation_handler): fix bug starting new child + threads; (info_proc): bug fixes and enhancements for the + "INFO PROCESSES" command; (close_procinfo_file): call new + function "delete_thread" to cleanup GDB's thread database; + (proc_init_failed): add new argument "kill", to control whether + process is killed (so this function can be shared by + create_procinfo and do_attach); (procfs_exit_handler): handle + exit from an attached process, and cleanup procinfo handles + when the process exits; (procfs_resume, procfs_wait): cleanup + after a thread when it exits; (do_attach, do_detach): handle + attached processes with multiple threads; plus some general + improvements in the diagnostic output. + * sol-thread.c (sol_thread_alive): replace stub with real + implementation; (thread_to_lwp, lwp_to_thread): enhance to + handle threads that may have exited; (sol_thread_attach): add + startup setup stuff; (sol_thread_detach): add unpush_target + call; (sol_thread_mourn_inferior): add unpush_target call; + (sol_thread_wait, sol_thread_resume): enhance to deal with + thread exit cleanly; (sol_thread_new_objfile, + sol_thread_pid_to_str): detect unsuccessful startup and + don't crash; plus some general cleanup. + * thread.c (delete_thread): new function, allows targets to + notify gdb when a thread is no longer valid. + * infrun.c (wait_for_inferior): don't try to detect a new + thread on receiving a TARGET_EXITED event. + +Tue May 20 09:32:02 1997 Andrew Cagney + + * remote-sim.c (gdbsim_open): Pass callback struct. + (init_callbacks): Remove call to sim_set_callbacks. + Thu May 15 07:56:50 1997 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) * config/rs6000/tm-rs6000.h (SIG_FRAME_LR_OFFSET): Define. diff --git a/gdb/procfs.c b/gdb/procfs.c index 9d3c969..c6a74a3 100644 --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -181,14 +181,15 @@ struct procinfo { struct sig_ctl saved_trace; /* Saved traced signal set */ struct sys_ctl saved_exitset; /* Saved traced system call exit set */ struct sys_ctl saved_entryset;/* Saved traced system call entry set */ - int num_syscall_handlers; /* Number of syscall handlers currently installed */ - struct procfs_syscall_handler *syscall_handlers; /* Pointer to list of syscall trap handlers */ + int num_syscall_handlers; /* Number of syscall trap handlers + currently installed */ + /* Pointer to list of syscall trap handlers */ + struct procfs_syscall_handler *syscall_handlers; int new_child; /* Non-zero if it's a new thread */ }; /* List of inferior process information */ static struct procinfo *procinfo_list = NULL; - static struct pollfd *poll_list; /* pollfds used for waiting on /proc */ static int num_poll_list = 0; /* Number of entries in poll_list */ @@ -248,6 +249,15 @@ static struct trans pr_flag_table[] = #if defined (PR_PCOMPAT) { PR_PCOMPAT, "PR_PCOMPAT", "Ptrace compatibility mode in effect" }, #endif +#if defined (PR_MSACCT) + { PR_MSACCT, "PR_MSACCT", "Microstate accounting enabled" }, +#endif +#if defined (PR_BPTADJ) + { PR_BPTADJ, "PR_BPTADJ", "Breakpoint PC adjustment in effect" }, +#endif +#if defined (PR_ASLWP) + { PR_ASLWP, "PR_ASLWP", "Asynchronus signal LWP" }, +#endif { 0, NULL, NULL } }; @@ -261,9 +271,6 @@ static struct trans pr_why_table[] = #if defined (PR_SIGNALLED) { PR_SIGNALLED, "PR_SIGNALLED", "Receipt of a traced signal" }, #endif -#if defined (PR_FAULTED) - { PR_FAULTED, "PR_FAULTED", "Incurred a traced hardware fault" }, -#endif #if defined (PR_SYSENTRY) { PR_SYSENTRY, "PR_SYSENTRY", "Entry to a traced system call" }, #endif @@ -273,9 +280,15 @@ static struct trans pr_why_table[] = #if defined (PR_JOBCONTROL) { PR_JOBCONTROL, "PR_JOBCONTROL", "Default job control stop signal action" }, #endif +#if defined (PR_FAULTED) + { PR_FAULTED, "PR_FAULTED", "Incurred a traced hardware fault" }, +#endif #if defined (PR_SUSPENDED) { PR_SUSPENDED, "PR_SUSPENDED", "Process suspended" }, #endif +#if defined (PR_CHECKPOINT) + { PR_CHECKPOINT, "PR_CHECKPOINT", "(???)" }, +#endif { 0, NULL, NULL } }; @@ -502,7 +515,7 @@ static void close_proc_file PARAMS ((struct procinfo *)); static void unconditionally_kill_inferior PARAMS ((struct procinfo *)); -static NORETURN void proc_init_failed PARAMS ((struct procinfo *, char *)) ATTR_NORETURN; +static NORETURN void proc_init_failed PARAMS ((struct procinfo *, char *, int)) ATTR_NORETURN; static void info_proc PARAMS ((char *, int)); @@ -538,8 +551,8 @@ static void notice_signals PARAMS ((struct procinfo *, struct sig_ctl *)); static struct procinfo *find_procinfo PARAMS ((pid_t pid, int okfail)); -static int procfs_read_status PARAMS ((struct procinfo *)); static int procfs_write_pcwstop PARAMS ((struct procinfo *)); +static int procfs_read_status PARAMS ((struct procinfo *)); static void procfs_write_pckill PARAMS ((struct procinfo *)); typedef int syscall_func_t PARAMS ((struct procinfo *pi, int syscall_num, @@ -684,6 +697,22 @@ add_fd (pi) num_poll_list++; } +/* + +LOCAL FUNCTION + + remove_fd -- Remove the fd from the poll/select list + +SYNOPSIS + + static void remove_fd (struct procinfo *); + +DESCRIPTION + + Remove the fd of the supplied procinfo from the list of fds used + for poll/select operations. + */ + static void remove_fd (pi) struct procinfo *pi; @@ -859,7 +888,8 @@ wait_fd () for (i = 0; i < num_poll_list && num_fds > 0; i++) { - if ((poll_list[i].revents & (POLLWRNORM|POLLPRI|POLLERR|POLLHUP|POLLNVAL)) == 0) + if (0 == (poll_list[i].revents & + (POLLWRNORM | POLLPRI | POLLERR | POLLHUP | POLLNVAL))) continue; for (pi = procinfo_list; pi; pi = pi->next) { @@ -867,8 +897,11 @@ wait_fd () { if (!procfs_read_status(pi)) { - print_sys_errmsg (pi->pathname, errno); - error ("procfs_read_status failed"); + /* The LWP has apparently terminated. */ + if (info_verbose) + printf_filtered ("LWP %d doesn't respond.\n", + (pi->pid >> 16) & 0xffff); + /* could call close_proc_file here, but I'm afraid to... */ } num_fds--; @@ -1549,23 +1582,23 @@ init_syscall_table () #if defined (SYS_settimeofday) syscall_table[SYS_settimeofday] = "settimeofday"; #endif -#if defined (SYS_lwpcreate) - syscall_table[SYS_lwpcreate] = "lwpcreate"; +#if defined (SYS_lwp_create) + syscall_table[SYS_lwp_create] = "_lwp_create"; #endif -#if defined (SYS_lwpexit) - syscall_table[SYS_lwpexit] = "lwpexit"; +#if defined (SYS_lwp_exit) + syscall_table[SYS_lwp_exit] = "_lwp_exit"; #endif -#if defined (SYS_lwpwait) - syscall_table[SYS_lwpwait] = "lwpwait"; +#if defined (SYS_lwp_wait) + syscall_table[SYS_lwp_wait] = "_lwp_wait"; #endif -#if defined (SYS_lwpself) - syscall_table[SYS_lwpself] = "lwpself"; +#if defined (SYS_lwp_self) + syscall_table[SYS_lwp_self] = "_lwp_self"; #endif -#if defined (SYS_lwpinfo) - syscall_table[SYS_lwpinfo] = "lwpinfo"; +#if defined (SYS_lwp_info) + syscall_table[SYS_lwp_info] = "_lwp_info"; #endif -#if defined (SYS_lwpprivate) - syscall_table[SYS_lwpprivate] = "lwpprivate"; +#if defined (SYS_lwp_private) + syscall_table[SYS_lwp_private] = "_lwp_private"; #endif #if defined (SYS_processor_bind) syscall_table[SYS_processor_bind] = "processor_bind"; @@ -1600,8 +1633,8 @@ init_syscall_table () #if defined (SYS_ftruncate) syscall_table[SYS_ftruncate] = "ftruncate"; #endif -#if defined (SYS_lwpkill) - syscall_table[SYS_lwpkill] = "lwpkill"; +#if defined (SYS_lwp_kill) + syscall_table[SYS_lwp_kill] = "_lwp_kill"; #endif #if defined (SYS_sigwait) syscall_table[SYS_sigwait] = "sigwait"; @@ -1630,11 +1663,11 @@ init_syscall_table () #if defined (SYS_getksym) syscall_table[SYS_getksym] = "getksym"; #endif -#if defined (SYS_lwpsuspend) - syscall_table[SYS_lwpsuspend] = "lwpsuspend"; +#if defined (SYS_lwp_suspend) + syscall_table[SYS_lwp_suspend] = "_lwp_suspend"; #endif -#if defined (SYS_lwpcontinue) - syscall_table[SYS_lwpcontinue] = "lwpcontinue"; +#if defined (SYS_lwp_continue) + syscall_table[SYS_lwp_continue] = "_lwp_continue"; #endif #if defined (SYS_priocntllst) syscall_table[SYS_priocntllst] = "priocntllst"; @@ -1643,10 +1676,10 @@ init_syscall_table () syscall_table[SYS_sleep] = "sleep"; #endif #if defined (SYS_lwp_sema_wait) - syscall_table[SYS_lwp_sema_wait] = "lwp_sema_wait"; + syscall_table[SYS_lwp_sema_wait] = "_lwp_sema_wait"; #endif #if defined (SYS_lwp_sema_post) - syscall_table[SYS_lwp_sema_post] = "lwp_sema_post"; + syscall_table[SYS_lwp_sema_post] = "_lwp_sema_post"; #endif #if defined (SYS_lwp_sema_trywait) syscall_table[SYS_lwp_sema_trywait] = "lwp_sema_trywait"; @@ -1928,17 +1961,17 @@ procfs_store_registers (regno) LOCAL FUNCTION - create_procinfo - initialize access to a /proc entry + init_procinfo - setup a procinfo struct and connect it to a process SYNOPSIS - struct procinfo * create_procinfo (int pid) + struct procinfo * init_procinfo (int pid) DESCRIPTION Allocate a procinfo structure, open the /proc file and then set up the set of signals and faults that are to be traced. Returns a pointer to - the new procinfo structure. + the new procinfo structure. NOTES @@ -1948,21 +1981,16 @@ NOTES */ static struct procinfo * -create_procinfo (pid) +init_procinfo (pid, kill) int pid; + int kill; { - struct procinfo *pi; - struct sig_ctl sctl; - struct flt_ctl fctl; - - pi = find_procinfo (pid, 1); - if (pi != NULL) - return pi; /* All done! It already exists */ - - pi = (struct procinfo *) xmalloc (sizeof (struct procinfo)); + struct procinfo *pi = (struct procinfo *) + xmalloc (sizeof (struct procinfo)); + memset ((char *) pi, 0, sizeof (*pi)); if (!open_proc_file (pid, pi, O_RDWR, 1)) - proc_init_failed (pi, "can't open process file"); + proc_init_failed (pi, "can't open process file", kill); /* open_proc_file may modify pid. */ @@ -1975,14 +2003,34 @@ create_procinfo (pid) add_fd (pi); /* Add to list for poll/select */ - pi->num_syscall_handlers = 0; - pi->syscall_handlers = NULL; + /* Remember some things about the inferior that we will, or might, change + so that we can restore them when we detach. */ #ifdef UNIXWARE + memcpy ((char *) &pi->saved_trace.sigset, + (char *) &pi->prstatus.pr_sigtrace, sizeof (sigset_t)); + memcpy ((char *) &pi->saved_fltset.fltset, + (char *) &pi->prstatus.pr_flttrace, sizeof (fltset_t)); + memcpy ((char *) &pi->saved_entryset.sysset, + (char *) &pi->prstatus.pr_sysentry, sizeof (sysset_t)); + memcpy ((char *) &pi->saved_exitset.sysset, + (char *) &pi->prstatus.pr_sysexit, sizeof (sysset_t)); + + /* Set up trace and fault sets, as gdb expects them. */ + prfillset (&sctl.sigset); - notice_signals (pi, &sctl); + notice_signals (pi, &sctl); prfillset (&fctl.fltset); prdelset (&fctl.fltset, FLTPAGE); -#else /* UNIXWARE */ + +#else /* ! UNIXWARE */ + ioctl (pi->ctl_fd, PIOCGTRACE, &pi->saved_trace.sigset); + ioctl (pi->ctl_fd, PIOCGHOLD, &pi->saved_sighold.sigset); + ioctl (pi->ctl_fd, PIOCGFAULT, &pi->saved_fltset.fltset); + ioctl (pi->ctl_fd, PIOCGENTRY, &pi->saved_entryset.sysset); + ioctl (pi->ctl_fd, PIOCGEXIT, &pi->saved_exitset.sysset); + + /* Set up trace and fault sets, as gdb expects them. */ + memset ((char *) &pi->prrun, 0, sizeof (pi->prrun)); prfillset (&pi->prrun.pr_trace); procfs_notice_signals (pid); @@ -1994,24 +2042,63 @@ create_procinfo (pid) #endif /* UNIXWARE */ if (!procfs_read_status (pi)) - proc_init_failed (pi, "procfs_read_status failed"); + proc_init_failed (pi, "procfs_read_status failed", kill); -/* A bug in Solaris (2.5 at least) causes PIOCWSTOP to hang on LWPs that are - already stopped, even if they all have PR_ASYNC set. */ + return pi; +} + +/* + +LOCAL FUNCTION + + create_procinfo - initialize access to a /proc entry + +SYNOPSIS + + struct procinfo * create_procinfo (int pid) + +DESCRIPTION + + Allocate a procinfo structure, open the /proc file and then set up the + set of signals and faults that are to be traced. Returns a pointer to + the new procinfo structure. + +NOTES + + If proc_init_failed ever gets called, control returns to the command + processing loop via the standard error handling code. + + */ + +static struct procinfo * +create_procinfo (pid) + int pid; +{ + struct procinfo *pi; + struct sig_ctl sctl; + struct flt_ctl fctl; + + pi = find_procinfo (pid, 1); + if (pi != NULL) + return pi; /* All done! It already exists */ + + pi = init_procinfo (pid, 1); #ifndef UNIXWARE +/* A bug in Solaris (2.5 at least) causes PIOCWSTOP to hang on LWPs that are + already stopped, even if they all have PR_ASYNC set. */ if (!(pi->prstatus.pr_flags & PR_STOPPED)) #endif if (!procfs_write_pcwstop (pi)) - proc_init_failed (pi, "procfs_write_pcwstop failed"); + proc_init_failed (pi, "procfs_write_pcwstop failed", 1); #ifdef PROCFS_USE_READ_WRITE fctl.cmd = PCSFAULT; if (write (pi->ctl_fd, (char *) &fctl, sizeof (struct flt_ctl)) < 0) - proc_init_failed (pi, "PCSFAULT failed"); + proc_init_failed (pi, "PCSFAULT failed", 1); #else if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->prrun.pr_fault) < 0) - proc_init_failed (pi, "PIOCSFAULT failed"); + proc_init_failed (pi, "PIOCSFAULT failed", 1); #endif return pi; @@ -2047,15 +2134,37 @@ procfs_exit_handler (pi, syscall_num, why, rtnvalp, statvalp) int *rtnvalp; int *statvalp; { + struct procinfo *temp_pi, *next_pi; + pi->prrun.pr_flags = PRCFAULT; if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0) perror_with_name (pi->pathname); - *rtnvalp = wait (statvalp); - if (*rtnvalp >= 0) - *rtnvalp = pi->pid; + if (attach_flag) + { + /* Claim it exited (don't call wait). */ + if (info_verbose) + printf_filtered ("(attached process has exited)\n"); + *statvalp = 0; + *rtnvalp = inferior_pid; + } + else + { + *rtnvalp = wait (statvalp); + if (*rtnvalp >= 0) + *rtnvalp = pi->pid; + } + /* Close ALL open proc file handles, + except the one that called SYS_exit. */ + for (temp_pi = procinfo_list; temp_pi; temp_pi = next_pi) + { + next_pi = temp_pi->next; + if (temp_pi == pi) + continue; /* Handled below */ + close_proc_file (temp_pi); + } return 1; } @@ -2223,39 +2332,24 @@ procfs_fork_handler (pi, syscall_num, why, rtnvalp, statvalp) LOCAL FUNCTION - procfs_init_inferior - initialize target vector and access to a - /proc entry + procfs_set_inferior_syscall_traps - setup the syscall traps SYNOPSIS - int procfs_init_inferior (int pid) + void procfs_set_inferior_syscall_traps (struct procinfo *pip) DESCRIPTION - When gdb starts an inferior, this function is called in the parent - process immediately after the fork. It waits for the child to stop - on the return from the exec system call (the child itself takes care - of ensuring that this is set up), then sets up the set of signals - and faults that are to be traced. Returns the pid, which may have had - the thread-id added to it. - -NOTES - - If proc_init_failed ever gets called, control returns to the command - processing loop via the standard error handling code. + Called for each "procinfo" (process, thread, or LWP) in the + inferior, to register for notification of and handlers for + syscall traps in the inferior. */ -static int -procfs_init_inferior (pid) - int pid; +static void +procfs_set_inferior_syscall_traps (pip) + struct procinfo *pip; { - struct procinfo *pip; - - push_target (&procfs_ops); - - pip = create_procinfo (pid); - #ifndef PIOCSSPCACT procfs_set_syscall_trap (pip, SYS_exit, PROCFS_SYSCALL_ENTRY, procfs_exit_handler); @@ -2297,6 +2391,46 @@ procfs_init_inferior (pid) procfs_set_syscall_trap (pip, SYS_lwp_create, PROCFS_SYSCALL_EXIT, procfs_lwp_creation_handler); #endif +} + +/* + +LOCAL FUNCTION + + procfs_init_inferior - initialize target vector and access to a + /proc entry + +SYNOPSIS + + int procfs_init_inferior (int pid) + +DESCRIPTION + + When gdb starts an inferior, this function is called in the parent + process immediately after the fork. It waits for the child to stop + on the return from the exec system call (the child itself takes care + of ensuring that this is set up), then sets up the set of signals + and faults that are to be traced. Returns the pid, which may have had + the thread-id added to it. + +NOTES + + If proc_init_failed ever gets called, control returns to the command + processing loop via the standard error handling code. + + */ + +static int +procfs_init_inferior (pid) + int pid; +{ + struct procinfo *pip; + + push_target (&procfs_ops); + + pip = create_procinfo (pid); + + procfs_set_inferior_syscall_traps (pip); /* create_procinfo may change the pid, so we have to update inferior_pid here before calling other gdb routines that need the right pid. */ @@ -2863,131 +2997,93 @@ do_attach (pid) struct procinfo *pi; struct sig_ctl sctl; struct flt_ctl fctl; + int nlwp, *lwps; - pi = (struct procinfo *) xmalloc (sizeof (struct procinfo)); - - if (!open_proc_file (pid, pi, O_RDWR, 1)) - { - free (pi); - perror_with_name (pi->pathname); - /* NOTREACHED */ - } - - pid = pi -> pid; - - /* Add new process to process info list */ - - pi->next = procinfo_list; - procinfo_list = pi; + pi = init_procinfo (pid, 0); - add_fd (pi); /* Add to list for poll/select */ +#ifdef PIOCLWPIDS + nlwp = pi->prstatus.pr_nlwp; + lwps = alloca ((2 * nlwp + 2) * sizeof (id_t)); - /* Get current status of process and if it is not already stopped, - then stop it. Remember whether or not it was stopped when we first - examined it. */ - if (!procfs_read_status (pi)) + if (ioctl (pi->ctl_fd, PIOCLWPIDS, lwps)) { - print_sys_errmsg (pi->pathname, errno); - close_proc_file (pi); - error ("procfs_read_status failed"); + print_sys_errmsg (pi -> pathname, errno); + error ("PIOCLWPIDS failed"); } +#else /* PIOCLWPIDS */ + nlwp = 1; + lwps = alloca ((2 * nlwp + 2) * sizeof *lwps); + lwps[0] = 0; +#endif + for (; nlwp > 0; nlwp--, lwps++) + { + /* First one has already been created above. */ + if ((pi = find_procinfo ((*lwps << 16) | pid, 1)) == 0) + pi = init_procinfo ((*lwps << 16) | pid, 0); + #ifdef UNIXWARE - if (pi->prstatus.pr_lwp.pr_flags & (PR_STOPPED | PR_ISTOP)) + if (pi->prstatus.pr_lwp.pr_flags & (PR_STOPPED | PR_ISTOP)) #else - if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)) + if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)) #endif - { - pi->was_stopped = 1; - } - else - { - pi->was_stopped = 0; - if (1 || query ("Process is currently running, stop it? ")) { - long cmd; - /* Make it run again when we close it. */ - - modify_run_on_last_close_flag (pi->ctl_fd, 1); - + pi->was_stopped = 1; + } + else + { + pi->was_stopped = 0; + if (1 || query ("Process is currently running, stop it? ")) + { + long cmd; + /* Make it run again when we close it. */ + modify_run_on_last_close_flag (pi->ctl_fd, 1); #ifdef PROCFS_USE_READ_WRITE - cmd = PCSTOP; - if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0) + cmd = PCSTOP; + if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0) #else - if (ioctl (pi->ctl_fd, PIOCSTOP, &pi->prstatus) < 0) + if (ioctl (pi->ctl_fd, PIOCSTOP, &pi->prstatus) < 0) #endif - { - print_sys_errmsg (pi->pathname, errno); - close_proc_file (pi); - error ("PIOCSTOP failed"); - } + { + print_sys_errmsg (pi->pathname, errno); + close_proc_file (pi); + error ("PIOCSTOP failed"); + } #ifdef UNIXWARE - if (!procfs_read_status (pi)) - { - print_sys_errmsg (pi->pathname, errno); - close_proc_file (pi); - error ("procfs_read_status failed"); - } + if (!procfs_read_status (pi)) + { + print_sys_errmsg (pi->pathname, errno); + close_proc_file (pi); + error ("procfs_read_status failed"); + } #endif - pi->nopass_next_sigstop = 1; - } - else - { - printf_unfiltered ("Ok, gdb will wait for %s to stop.\n", target_pid_to_str (pid)); + pi->nopass_next_sigstop = 1; + } + else + { + printf_unfiltered ("Ok, gdb will wait for %s to stop.\n", + target_pid_to_str (pi->pid)); + } } - } - /* Remember some things about the inferior that we will, or might, change - so that we can restore them when we detach. */ #ifdef PROCFS_USE_READ_WRITE - memcpy ((char *) &pi->saved_trace.sigset, - (char *) &pi->prstatus.pr_sigtrace, sizeof (sigset_t)); - memcpy ((char *) &pi->saved_fltset.fltset, - (char *) &pi->prstatus.pr_flttrace, sizeof (fltset_t)); - memcpy ((char *) &pi->saved_entryset.sysset, - (char *) &pi->prstatus.pr_sysentry, sizeof (sysset_t)); - memcpy ((char *) &pi->saved_exitset.sysset, - (char *) &pi->prstatus.pr_sysexit, sizeof (sysset_t)); - - /* Set up trace and fault sets, as gdb expects them. */ - - prfillset (&sctl.sigset); - notice_signals (pi, &sctl); - prfillset (&fctl.fltset); - prdelset (&fctl.fltset, FLTPAGE); - - fctl.cmd = PCSFAULT; - if (write (pi->ctl_fd, (char *) &fctl, sizeof (struct flt_ctl)) < 0) - print_sys_errmsg ("PCSFAULT failed", errno); + fctl.cmd = PCSFAULT; + if (write (pi->ctl_fd, (char *) &fctl, sizeof (struct flt_ctl)) < 0) + print_sys_errmsg ("PCSFAULT failed", errno); #else /* PROCFS_USE_READ_WRITE */ - ioctl (pi->ctl_fd, PIOCGTRACE, &pi->saved_trace.sigset); - ioctl (pi->ctl_fd, PIOCGHOLD, &pi->saved_sighold.sigset); - ioctl (pi->ctl_fd, PIOCGFAULT, &pi->saved_fltset.fltset); - ioctl (pi->ctl_fd, PIOCGENTRY, &pi->saved_entryset.sysset); - ioctl (pi->ctl_fd, PIOCGEXIT, &pi->saved_exitset.sysset); - - /* Set up trace and fault sets, as gdb expects them. */ - - memset (&pi->prrun, 0, sizeof (pi->prrun)); - prfillset (&pi->prrun.pr_trace); - procfs_notice_signals (pid); - prfillset (&pi->prrun.pr_fault); - prdelset (&pi->prrun.pr_fault, FLTPAGE); - -#ifdef PROCFS_DONT_TRACE_FAULTS - premptyset (&pi->prrun.pr_fault); -#endif - - if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->prrun.pr_fault)) - { - print_sys_errmsg ("PIOCSFAULT failed", errno); - } - if (ioctl (pi->ctl_fd, PIOCSTRACE, &pi->prrun.pr_trace)) - { - print_sys_errmsg ("PIOCSTRACE failed", errno); + if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->prrun.pr_fault)) + { + print_sys_errmsg ("PIOCSFAULT failed", errno); + } + if (ioctl (pi->ctl_fd, PIOCSTRACE, &pi->prrun.pr_trace)) + { + print_sys_errmsg ("PIOCSTRACE failed", errno); + } + add_thread (pi->pid); + procfs_set_inferior_syscall_traps (pi); } #endif /* PROCFS_USE_READ_WRITE */ attach_flag = 1; - return (pid); + return (pi->pid); } /* @@ -3025,106 +3121,107 @@ do_detach (signal) { struct procinfo *pi; - pi = current_procinfo; - - if (signal) + for (pi = procinfo_list; pi; pi = pi->next) { - set_proc_siginfo (pi, signal); - } + if (signal) + { + set_proc_siginfo (pi, signal); + } #ifdef PROCFS_USE_READ_WRITE - pi->saved_exitset.cmd = PCSEXIT; - if (write (pi->ctl_fd, (char *) &pi->saved_exitset, - sizeof (struct sys_ctl)) < 0) + pi->saved_exitset.cmd = PCSEXIT; + if (write (pi->ctl_fd, (char *) &pi->saved_exitset, + sizeof (struct sys_ctl)) < 0) #else - if (ioctl (pi->ctl_fd, PIOCSEXIT, &pi->saved_exitset.sysset) < 0) + if (ioctl (pi->ctl_fd, PIOCSEXIT, &pi->saved_exitset.sysset) < 0) #endif - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSEXIT failed.\n"); - } + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSEXIT failed.\n"); + } #ifdef PROCFS_USE_READ_WRITE - pi->saved_entryset.cmd = PCSENTRY; - if (write (pi->ctl_fd, (char *) &pi->saved_entryset, - sizeof (struct sys_ctl)) < 0) + pi->saved_entryset.cmd = PCSENTRY; + if (write (pi->ctl_fd, (char *) &pi->saved_entryset, + sizeof (struct sys_ctl)) < 0) #else - if (ioctl (pi->ctl_fd, PIOCSENTRY, &pi->saved_entryset.sysset) < 0) + if (ioctl (pi->ctl_fd, PIOCSENTRY, &pi->saved_entryset.sysset) < 0) #endif - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSENTRY failed.\n"); - } + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSENTRY failed.\n"); + } #ifdef PROCFS_USE_READ_WRITE - pi->saved_trace.cmd = PCSTRACE; - if (write (pi->ctl_fd, (char *) &pi->saved_trace, - sizeof (struct sig_ctl)) < 0) + pi->saved_trace.cmd = PCSTRACE; + if (write (pi->ctl_fd, (char *) &pi->saved_trace, + sizeof (struct sig_ctl)) < 0) #else - if (ioctl (pi->ctl_fd, PIOCSTRACE, &pi->saved_trace.sigset) < 0) + if (ioctl (pi->ctl_fd, PIOCSTRACE, &pi->saved_trace.sigset) < 0) #endif - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSTRACE failed.\n"); - } + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSTRACE failed.\n"); + } #ifndef UNIXWARE - if (ioctl (pi->ctl_fd, PIOCSHOLD, &pi->saved_sighold.sigset) < 0) - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOSCHOLD failed.\n"); - } + if (ioctl (pi->ctl_fd, PIOCSHOLD, &pi->saved_sighold.sigset) < 0) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOSCHOLD failed.\n"); + } #endif #ifdef PROCFS_USE_READ_WRITE - pi->saved_fltset.cmd = PCSFAULT; - if (write (pi->ctl_fd, (char *) &pi->saved_fltset, - sizeof (struct flt_ctl)) < 0) + pi->saved_fltset.cmd = PCSFAULT; + if (write (pi->ctl_fd, (char *) &pi->saved_fltset, + sizeof (struct flt_ctl)) < 0) #else - if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->saved_fltset.fltset) < 0) + if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->saved_fltset.fltset) < 0) #endif - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSFAULT failed.\n"); - } - if (!procfs_read_status (pi)) - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("procfs_read_status failed.\n"); - } - else - { + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSFAULT failed.\n"); + } + if (!procfs_read_status (pi)) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("procfs_read_status failed.\n"); + } + else + { #ifdef UNIXWARE - if (signal || (pi->prstatus.pr_lwp.pr_flags & (PR_STOPPED | PR_ISTOP))) + if (signal || (pi->prstatus.pr_lwp.pr_flags & (PR_STOPPED | PR_ISTOP))) #else - if (signal || (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))) + if (signal || (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))) #endif - { - long cmd; - struct proc_ctl pctl; - - if (signal || !pi->was_stopped || - query ("Was stopped when attached, make it runnable again? ")) { - /* Clear any pending signal if we want to detach without - a signal. */ - if (signal == 0) - set_proc_siginfo (pi, signal); + long cmd; + struct proc_ctl pctl; - /* Clear any fault that might have stopped it. */ + if (signal || !pi->was_stopped || + query ("Was stopped when attached, make it runnable again? ")) + { + /* Clear any pending signal if we want to detach without + a signal. */ + if (signal == 0) + set_proc_siginfo (pi, signal); + + /* Clear any fault that might have stopped it. */ #ifdef PROCFS_USE_READ_WRITE - cmd = PCCFAULT; - if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0) + cmd = PCCFAULT; + if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0) #else - if (ioctl (pi->ctl_fd, PIOCCFAULT, 0)) + if (ioctl (pi->ctl_fd, PIOCCFAULT, 0)) #endif - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCCFAULT failed.\n"); - } + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCCFAULT failed.\n"); + } - /* Make it run again when we close it. */ + /* Make it run again when we close it. */ - modify_run_on_last_close_flag (pi->ctl_fd, 1); + modify_run_on_last_close_flag (pi->ctl_fd, 1); + } } } + close_proc_file (pi); } - close_proc_file (pi); attach_flag = 0; } @@ -3152,7 +3249,6 @@ do_detach (signal) FIXME: Investigate why wait() seems to have problems with programs being control by /proc routines. */ - static int procfs_wait (pid, ourstatus) int pid; @@ -3203,16 +3299,17 @@ procfs_wait (pid, ourstatus) { checkerr++; } - } + } if (checkerr) { if (errno == ENOENT) { + /* XXX Fixme -- what to do if attached? Can't call wait... */ rtnval = wait (&statval); - if (rtnval != inferior_pid) + if ((rtnval) != (inferior_pid)) { print_sys_errmsg (pi->pathname, errno); - error ("procfs_write_pcwstop, wait failed, returned %d", rtnval); + error ("procfs_wait: wait failed, returned %d", rtnval); /* NOTREACHED */ } } @@ -3319,7 +3416,7 @@ procfs_wait (pid, ourstatus) case FLTBPT: case FLTTRACE: statval = (SIGTRAP << 8) | 0177; - break; + break; case FLTSTACK: case FLTACCESS: case FLTBOUNDS: @@ -3350,10 +3447,11 @@ procfs_wait (pid, ourstatus) /* Stop all the other threads when any of them stops. */ { - struct procinfo *procinfo; + struct procinfo *procinfo, *next_pi; - for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next) + for (procinfo = procinfo_list; procinfo; procinfo = next_pi) { + next_pi = procinfo->next; if (!procinfo->had_event) { #ifdef PROCFS_USE_READ_WRITE @@ -3369,15 +3467,20 @@ procfs_wait (pid, ourstatus) order to avoid the hang. */ if (!procfs_read_status (procinfo)) { - print_sys_errmsg (procinfo->pathname, errno); - error ("procfs_read_status failed"); + /* The LWP has apparently terminated. */ + if (info_verbose) + printf_filtered ("LWP %d doesn't respond.\n", + (procinfo->pid >> 16) & 0xffff); + close_proc_file (procinfo); + continue; } if (!(procinfo->prstatus.pr_flags & PR_STOPPED)) - if (ioctl (procinfo->ctl_fd, PIOCSTOP, &procinfo->prstatus) < 0) + if (ioctl (procinfo->ctl_fd, PIOCSTOP, &procinfo->prstatus) + < 0) { print_sys_errmsg (procinfo->pathname, errno); - error ("PIOCSTOP failed"); + warning ("PIOCSTOP failed"); } #endif } @@ -3394,7 +3497,7 @@ procfs_wait (pid, ourstatus) if (rtnval == -1) /* No more children to wait for */ { - fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing.\n"); + warning ("Child process unexpectedly missing"); /* Claim it exited with unknown signal. */ ourstatus->kind = TARGET_WAITKIND_SIGNALLED; ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; @@ -3514,7 +3617,7 @@ procfs_resume (pid, step, signo) enum target_signal signo; { int signal_to_pass; - struct procinfo *pi, *procinfo; + struct procinfo *pi, *procinfo, *next_pi; struct proc_ctl pctl; pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0); @@ -3562,11 +3665,12 @@ procfs_resume (pid, step, signo) else if (signo == TARGET_SIGNAL_TSTP #ifdef UNIXWARE && pi->prstatus.pr_lwp.pr_cursig == SIGTSTP - && pi->prstatus.pr_lwp.pr_action.sa_handler == SIG_DFL) + && pi->prstatus.pr_lwp.pr_action.sa_handler == SIG_DFL #else && pi->prstatus.pr_cursig == SIGTSTP - && pi->prstatus.pr_action.sa_handler == SIG_DFL) + && pi->prstatus.pr_action.sa_handler == SIG_DFL #endif + ) /* We are about to pass the inferior a SIGTSTP whose action is SIG_DFL. The SIG_DFL action for a SIGTSTP is to stop @@ -3607,65 +3711,91 @@ procfs_resume (pid, step, signo) pi->prrun.pr_flags |= PRSTEP; #endif } - + pi->had_event = 0; /* Don't try to start a process unless it's stopped on an `event of interest'. Doing so will cause errors. */ + if (!procfs_read_status (pi)) + { + /* The LWP has apparently terminated. */ + if (info_verbose) + printf_filtered ("LWP %d doesn't respond.\n", + (pi->pid >> 16) & 0xffff); + close_proc_file (pi); + } + else + { #ifdef PROCFS_USE_READ_WRITE - if (write (pi->ctl_fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0) + if (write (pi->ctl_fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0) #else - if ((pi->prstatus.pr_flags & PR_ISTOP) - && ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0) + if ((pi->prstatus.pr_flags & PR_ISTOP) + && ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0) #endif - { - perror_with_name (pi->pathname); - /* NOTREACHED */ + { + /* The LWP has apparently terminated. */ + if (info_verbose) + printf_filtered ("LWP %d doesn't respond.\n", + (pi->pid >> 16) & 0xffff); + close_proc_file (pi); + } } - pi->had_event = 0; - - /* Continue all the other threads that haven't had an event of - interest. */ + /* Continue all the other threads that haven't had an event of interest. + Also continue them if they have NOPASS_NEXT_SIGSTOP set; this is only + set by do_attach, and means this is the first resume after an attach. + All threads were CSTOP'd by do_attach, and should be resumed now. */ if (pid == -1) - for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next) + for (procinfo = procinfo_list; procinfo; procinfo = next_pi) { - if (pi != procinfo && !procinfo->had_event) - { + next_pi = procinfo->next; + if (pi != procinfo) + if (!procinfo->had_event || + (procinfo->nopass_next_sigstop && signo == TARGET_SIGNAL_STOP)) + { + procinfo->had_event = procinfo->nopass_next_sigstop = 0; #ifdef PROCFS_USE_READ_WRITE - pctl.data = PRCFAULT | PRCSIG; - if (write (procinfo->ctl_fd, (char *) &pctl, - sizeof (struct proc_ctl)) < 0) - { - if (!procfs_read_status (procinfo)) - { - fprintf_unfiltered(gdb_stderr, "procfs_read_status failed, errno=%d\n", errno); - } - print_sys_errmsg (procinfo->pathname, errno); - error ("PCRUN failed"); - } - procfs_read_status (procinfo); + pctl.data = PRCFAULT | PRCSIG; + if (write (procinfo->ctl_fd, (char *) &pctl, + sizeof (struct proc_ctl)) < 0) + { + if (!procfs_read_status (procinfo)) + fprintf_unfiltered(gdb_stderr, + "procfs_read_status failed, errno=%d\n", + errno); + print_sys_errmsg (procinfo->pathname, errno); + error ("PCRUN failed"); + } + procfs_read_status (procinfo); #else - procinfo->prrun.pr_flags &= PRSTEP; - procinfo->prrun.pr_flags |= PRCFAULT | PRCSIG; - procfs_read_status (procinfo); + procinfo->prrun.pr_flags &= PRSTEP; + procinfo->prrun.pr_flags |= PRCFAULT | PRCSIG; + if (!procfs_read_status (procinfo)) + { + /* The LWP has apparently terminated. */ + if (info_verbose) + printf_filtered ("LWP %d doesn't respond.\n", + (procinfo->pid >> 16) & 0xffff); + close_proc_file (procinfo); + continue; + } - /* Don't try to start a process unless it's stopped on an - `event of interest'. Doing so will cause errors. */ + /* Don't try to start a process unless it's stopped on an + `event of interest'. Doing so will cause errors. */ - if ((procinfo->prstatus.pr_flags & PR_ISTOP) - && ioctl (procinfo->ctl_fd, PIOCRUN, &procinfo->prrun) < 0) - { - if (!procfs_read_status (procinfo)) - { - fprintf_unfiltered(gdb_stderr, "procfs_read_status failed, errno=%d\n", errno); - } - print_sys_errmsg (procinfo->pathname, errno); - error ("PIOCRUN failed"); - } - procfs_read_status (procinfo); + if ((procinfo->prstatus.pr_flags & PR_ISTOP) + && ioctl (procinfo->ctl_fd, PIOCRUN, &procinfo->prrun) < 0) + { + if (!procfs_read_status (procinfo)) + fprintf_unfiltered(gdb_stderr, + "procfs_read_status failed, errno=%d\n", + errno); + print_sys_errmsg (procinfo->pathname, errno); + warning ("PIOCRUN failed"); + } + } + procfs_read_status (procinfo); #endif - } } } @@ -3721,28 +3851,31 @@ procfs_fetch_registers (regno) LOCAL FUNCTION - proc_init_failed - called whenever /proc access initialization + proc_init_failed - called when /proc access initialization fails fails SYNOPSIS - static void proc_init_failed (struct procinfo *pi, char *why) + static void proc_init_failed (struct procinfo *pi, + char *why, int kill_p) DESCRIPTION This function is called whenever initialization of access to a /proc entry fails. It prints a suitable error message, does some cleanup, and then invokes the standard error processing routine which dumps - us back into the command loop. + us back into the command loop. If KILL_P is true, sends SIGKILL. */ static void -proc_init_failed (pi, why) +proc_init_failed (pi, why, kill_p) struct procinfo *pi; char *why; + int kill_p; { print_sys_errmsg (pi->pathname, errno); - kill (pi->pid, SIGKILL); + if (kill_p) + kill (pi->pid, SIGKILL); close_proc_file (pi); error (why); /* NOTREACHED */ @@ -3773,6 +3906,7 @@ close_proc_file (pip) { struct procinfo *procinfo; + delete_thread (pip->pid); /* remove thread from GDB's thread list */ remove_fd (pip); /* Remove fd from poll/select list */ close (pip->ctl_fd); @@ -3890,7 +4024,7 @@ open_proc_file (pid, pip, mode, control) close (pip->as_fd); close (pip->map_fd); return 0; - } + } } #else /* HAVE_MULTIPLE_PROC_FDS */ @@ -4531,7 +4665,7 @@ info_proc (args, from_tty) char *args; int from_tty; { - int pid = inferior_pid; + int pid; struct procinfo *pip; struct cleanup *old_chain; char **argv; @@ -4554,7 +4688,10 @@ info_proc (args, from_tty) /* Default to using the current inferior if no pid specified. Note that inferior_pid may be 0, hence we set okerr. */ - pip = find_procinfo (inferior_pid, 1); + pid = inferior_pid & 0x7fffffff; /* strip off sol-thread bit */ + if (!(pip = find_procinfo (pid, 1))) /* inferior_pid no good? */ + pip = procinfo_list; /* take first available */ + pid = pid & 0xffff; /* extract "real" pid */ if (args != NULL) { @@ -4652,12 +4789,12 @@ No process. Start debugging a program or specify an explicit process ID."); #ifndef PROCFS_USE_READ_WRITE #ifdef PIOCLWPIDS nlwp = pip->prstatus.pr_nlwp; - lwps = alloca ((2 * nlwp + 2) * sizeof (id_t)); + lwps = alloca ((2 * nlwp + 2) * sizeof (*lwps)); if (ioctl (pip->ctl_fd, PIOCLWPIDS, lwps)) { print_sys_errmsg (pip -> pathname, errno); - error ("PIOCLWPIDS failed"); + error ("PIOCLWPIDS failed"); } #else /* PIOCLWPIDS */ nlwp = 1; @@ -4698,6 +4835,10 @@ No process. Start debugging a program or specify an explicit process ID."); if (summary || all) { info_proc_stop (pip, summary); + supply_gregset (&pip->prstatus.pr_reg); + printf_filtered ("PC: "); + print_address (read_pc (), gdb_stdout); + printf_filtered ("\n"); } if (summary || all || signals || faults) { @@ -5005,7 +5146,7 @@ procfs_set_syscall_trap (pi, syscall_num, flags, func) syscall_func_t *func; { sysset_t sysset; - + if (flags & PROCFS_SYSCALL_ENTRY) { if (ioctl (pi->ctl_fd, PIOCGENTRY, &sysset) < 0) @@ -5148,7 +5289,7 @@ procfs_lwp_creation_handler (pi, syscall_num, why, rtnvalp, statvalp) /* We're the proud parent of a new thread. Setup an exit trap for lwp_create in the child and continue the parent. */ - + /* Third arg is pointer to new thread id. */ lwp_id = read_memory_integer (pi->prstatus.pr_sysarg[2], sizeof (int)); @@ -5157,18 +5298,36 @@ procfs_lwp_creation_handler (pi, syscall_num, why, rtnvalp, statvalp) childpi = create_procinfo (lwp_id); /* The new process has actually inherited the lwp_create syscall trap from - it's parent, but we still have to call this to register a handler for + it's parent, but we still have to call this to register handlers for that child. */ - procfs_set_syscall_trap (childpi, SYS_lwp_create, PROCFS_SYSCALL_EXIT, - procfs_lwp_creation_handler); + procfs_set_inferior_syscall_traps (childpi); + add_thread (lwp_id); + printf_filtered ("[New %s]\n", target_pid_to_str (lwp_id)); - childpi->new_child = 1; /* Flag this as an unseen child process */ + /* Continue the parent */ - *rtnvalp = lwp_id; /* the new arrival. */ - *statvalp = (SIGTRAP << 8) | 0177; + pi->prrun.pr_flags &= PRSTEP; + pi->prrun.pr_flags |= PRCFAULT; + if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0) + perror_with_name (pi->pathname); - return 1; + /* The new child may have been created in one of two states: + SUSPENDED or RUNNABLE. If runnable, we will simply signal it to run. + If suspended, we flag it to be continued later, when it has an event. */ + + if (childpi->prstatus.pr_why == PR_SUSPENDED) + childpi->new_child = 1; /* Flag this as an unseen child process */ + else + { + /* Continue the child */ + childpi->prrun.pr_flags &= PRSTEP; + childpi->prrun.pr_flags |= PRCFAULT; + + if (ioctl (childpi->ctl_fd, PIOCRUN, &childpi->prrun) != 0) + perror_with_name (childpi->pathname); + } + return 0; } #endif /* SYS_lwp_create */ @@ -5356,7 +5515,34 @@ static int procfs_thread_alive (pid) int pid; { - return 1; + struct procinfo *pi, *next_pi; + + for (pi = procinfo_list; pi; pi = next_pi) + { + next_pi = pi->next; + if (pi -> pid == pid) + if (procfs_read_status (pi)) /* alive */ + return 1; + else /* defunct (exited) */ + { + close_proc_file (pi); + return 0; + } + } + return 0; +} + +int +procfs_first_available () +{ + struct procinfo *pi; + + for (pi = procinfo_list; pi; pi = pi->next) + { + if (procfs_read_status (pi)) + return pi->pid; + } + return -1; } /* Send a SIGINT to the process group. This acts just like the user typed a @@ -5449,7 +5635,7 @@ _initialize_procfs () add_target (&procfs_ops); - add_info ("proc", info_proc, + add_info ("processes", info_proc, "Show process status information using /proc entry.\n\ Specify process id or use current inferior by default.\n\ Specify keywords for detailed information; default is summary.\n\ diff --git a/gdb/sol-thread.c b/gdb/sol-thread.c index 00bdc60..4b73c19 100644 --- a/gdb/sol-thread.c +++ b/gdb/sol-thread.c @@ -72,6 +72,7 @@ extern struct target_ops sol_thread_ops; /* Forward declaration */ extern int procfs_suppress_run; extern struct target_ops procfs_ops; /* target vector for procfs.c */ +extern char *procfs_pid_to_str PARAMS ((int pid)); /* Note that these prototypes differ slightly from those used in procfs.c for of two reasons. One, we can't use gregset_t, as that's got a whole @@ -110,10 +111,11 @@ static struct cleanup * save_inferior_pid PARAMS ((void)); static void restore_inferior_pid PARAMS ((int pid)); static char *td_err_string PARAMS ((td_err_e errcode)); static char *td_state_string PARAMS ((td_thr_state_e statecode)); -static int thread_to_lwp PARAMS ((int thread_id, int default_lwp)); +static int thread_to_lwp PARAMS ((int thread_id, int default_lwp)); static void sol_thread_resume PARAMS ((int pid, int step, enum target_signal signo)); static int lwp_to_thread PARAMS ((int lwp)); +static int sol_thread_alive PARAMS ((int pid)); #define THREAD_FLAG 0x80000000 #define is_thread(ARG) (((ARG) & THREAD_FLAG) != 0) @@ -306,24 +308,22 @@ thread_to_lwp (thread_id, default_lwp) td_thrinfo_t ti; td_thrhandle_t th; td_err_e val; - int pid; - int lwp; if (is_lwp (thread_id)) return thread_id; /* It's already an LWP id */ /* It's a thread. Convert to lwp */ - pid = PIDGET (thread_id); - thread_id = GET_THREAD(thread_id); - - val = p_td_ta_map_id2thr (main_ta, thread_id, &th); - if (val != TD_OK) + val = p_td_ta_map_id2thr (main_ta, GET_THREAD (thread_id), &th); + if (val == TD_NOTHR) + return -1; /* thread must have terminated */ + else if (val != TD_OK) error ("thread_to_lwp: td_ta_map_id2thr %s", td_err_string (val)); val = p_td_thr_get_info (&th, &ti); - - if (val != TD_OK) + if (val == TD_NOTHR) + return -1; /* thread must have terminated */ + else if (val != TD_OK) error ("thread_to_lwp: td_thr_get_info: %s", td_err_string (val)); if (ti.ti_state != TD_THR_ACTIVE) @@ -333,10 +333,8 @@ thread_to_lwp (thread_id, default_lwp) error ("thread_to_lwp: thread state not active: %s", td_state_string (ti.ti_state)); } - - lwp = BUILD_LWP (ti.ti_lid, pid); - return lwp; + return BUILD_LWP (ti.ti_lid, PIDGET (thread_id)); } /* @@ -367,29 +365,34 @@ lwp_to_thread (lwp) td_thrinfo_t ti; td_thrhandle_t th; td_err_e val; - int pid; - int thread_id; if (is_thread (lwp)) return lwp; /* It's already a thread id */ /* It's an lwp. Convert it to a thread id. */ - pid = PIDGET (lwp); - lwp = GET_LWP (lwp); + if (!sol_thread_alive (lwp)) + return -1; /* defunct lwp */ - val = p_td_ta_map_lwp2thr (main_ta, lwp, &th); - if (val != TD_OK) + val = p_td_ta_map_lwp2thr (main_ta, GET_LWP (lwp), &th); + if (val == TD_NOTHR) + return -1; /* thread must have terminated */ + else if (val != TD_OK) error ("lwp_to_thread: td_thr_get_info: %s.", td_err_string (val)); - val = p_td_thr_get_info (&th, &ti); + val = p_td_thr_validate (&th); + if (val == TD_NOTHR) + return lwp; /* libthread doesn't know about it, just return lwp */ + else if (val != TD_OK) + error ("lwp_to_thread: td_thr_validate: %s.", td_err_string (val)); - if (val != TD_OK) + val = p_td_thr_get_info (&th, &ti); + if (val == TD_NOTHR) + return -1; /* thread must have terminated */ + else if (val != TD_OK) error ("lwp_to_thread: td_thr_get_info: %s.", td_err_string (val)); - thread_id = BUILD_THREAD (ti.ti_tid, pid); - - return thread_id; + return BUILD_THREAD (ti.ti_tid, PIDGET (lwp)); } /* @@ -456,7 +459,19 @@ sol_thread_attach (args, from_tty) int from_tty; { procfs_ops.to_attach (args, from_tty); - + /* Must get symbols from solibs before libthread_db can run! */ + SOLIB_ADD ((char *)0, from_tty, (struct target_ops *)0); + if (sol_thread_active) + { + printf_filtered ("sol-thread active.\n"); + main_ph.pid = inferior_pid; /* Save for xfer_memory */ + push_target (&sol_thread_ops); + inferior_pid = lwp_to_thread (inferior_pid); + if (inferior_pid == -1) + inferior_pid = main_ph.pid; + else + add_thread (inferior_pid); + } /* XXX - might want to iterate over all the threads and register them. */ } @@ -473,6 +488,7 @@ sol_thread_detach (args, from_tty) char *args; int from_tty; { + unpush_target (&sol_thread_ops); procfs_ops.to_detach (args, from_tty); } @@ -492,12 +508,19 @@ sol_thread_resume (pid, step, signo) old_chain = save_inferior_pid (); inferior_pid = thread_to_lwp (inferior_pid, main_ph.pid); + if (inferior_pid == -1) + inferior_pid = procfs_first_available (); if (pid != -1) { + int save_pid = pid; + pid = thread_to_lwp (pid, -2); if (pid == -2) /* Inactive thread */ error ("This version of Solaris can't start inactive threads."); + if (info_verbose && pid == -1) + warning ("Specified thread %d seems to have terminated", + GET_THREAD (save_pid)); } procfs_ops.to_resume (pid, step, signo); @@ -521,28 +544,44 @@ sol_thread_wait (pid, ourstatus) old_chain = save_inferior_pid (); inferior_pid = thread_to_lwp (inferior_pid, main_ph.pid); + if (inferior_pid == -1) + inferior_pid = procfs_first_available (); if (pid != -1) - pid = thread_to_lwp (pid, -1); + { + int save_pid = pid; + + pid = thread_to_lwp (pid, -2); + if (pid == -2) /* Inactive thread */ + error ("This version of Solaris can't start inactive threads."); + if (info_verbose && pid == -1) + warning ("Specified thread %d seems to have terminated", + GET_THREAD (save_pid)); + } rtnval = procfs_ops.to_wait (pid, ourstatus); - if (rtnval != save_pid - && !in_thread_list (rtnval)) + if (ourstatus->kind != TARGET_WAITKIND_EXITED) { - fprintf_unfiltered (gdb_stderr, "[New %s]\n", - target_pid_to_str (rtnval)); - add_thread (rtnval); + /* Map the LWP of interest back to the appropriate thread ID */ + rtnval = lwp_to_thread (rtnval); + if (rtnval == -1) + rtnval = save_pid; + + /* See if we have a new thread */ + if (is_thread (rtnval) + && rtnval != save_pid + && !in_thread_list (rtnval)) + { + printf_filtered ("[New %s]\n", target_pid_to_str (rtnval)); + add_thread (rtnval); + } } /* During process initialization, we may get here without the thread package being initialized, since that can only happen after we've found the shared libs. */ - /* Map the LWP of interest back to the appropriate thread ID */ - - rtnval = lwp_to_thread (rtnval); - do_cleanups (old_chain); return rtnval; @@ -751,8 +790,6 @@ sol_thread_notice_signals (pid) procfs_ops.to_notice_signals (pid); } -void target_new_objfile PARAMS ((struct objfile *objfile)); - /* Fork an inferior process, and start debugging it with /proc. */ static void @@ -763,13 +800,15 @@ sol_thread_create_inferior (exec_file, allargs, env) { procfs_ops.to_create_inferior (exec_file, allargs, env); - if (sol_thread_active) + if (sol_thread_active && inferior_pid != 0) { main_ph.pid = inferior_pid; /* Save for xfer_memory */ push_target (&sol_thread_ops); inferior_pid = lwp_to_thread (inferior_pid); + if (inferior_pid == -1) + inferior_pid = main_ph.pid; add_thread (inferior_pid); } @@ -794,6 +833,10 @@ sol_thread_new_objfile (objfile) return; } + /* don't do anything if init failed to resolve the libthread_db library */ + if (!procfs_suppress_run) + return; + /* Now, initialize the thread debugging library. This needs to be done after the shared libraries are located because it needs information from the user's thread library. */ @@ -816,6 +859,7 @@ sol_thread_new_objfile (objfile) static void sol_thread_mourn_inferior () { + unpush_target (&sol_thread_ops); procfs_ops.to_mourn_inferior (); } @@ -827,11 +871,40 @@ sol_thread_can_run () return procfs_suppress_run; } +/* + +LOCAL FUNCTION + + sol_thread_alive - test thread for "aliveness" + +SYNOPSIS + + static bool sol_thread_alive (int pid); + +DESCRIPTION + + returns true if thread still active in inferior. + + */ + static int sol_thread_alive (pid) int pid; { - return 1; + if (is_thread (pid)) /* non-kernel thread */ + { + td_err_e val; + td_thrhandle_t th; + + pid = GET_THREAD (pid); + if ((val = p_td_ta_map_id2thr (main_ta, pid, &th)) != TD_OK) + return 0; /* thread not found */ + if ((val = p_td_thr_validate (&th)) != TD_OK) + return 0; /* thread not valid */ + return 1; /* known thread: return true */ + } + else /* kernel thread (LWP): let procfs test it */ + return procfs_ops.to_thread_alive (pid); } static void @@ -910,9 +983,9 @@ rw_common (int dowrite, const struct ps_prochandle *ph, paddr_t addr, if (cc < 0) { if (dowrite == 0) - print_sys_errmsg ("ps_pdread (): read", errno); + print_sys_errmsg ("rw_common (): read", errno); else - print_sys_errmsg ("ps_pdread (): write", errno); + print_sys_errmsg ("rw_common (): write", errno); do_cleanups (old_chain); @@ -1123,19 +1196,27 @@ solaris_pid_to_str (pid) { static char buf[100]; + /* in case init failed to resolve the libthread_db library */ + if (!procfs_suppress_run) + return procfs_pid_to_str (pid); + if (is_thread (pid)) { int lwp; lwp = thread_to_lwp (pid, -2); - if (lwp != -2) + if (lwp == -1) + sprintf (buf, "Thread %d (defunct)", GET_THREAD (pid)); + else if (lwp != -2) sprintf (buf, "Thread %d (LWP %d)", GET_THREAD (pid), GET_LWP (lwp)); else sprintf (buf, "Thread %d ", GET_THREAD (pid)); } - else + else if (GET_LWP (pid) != 0) sprintf (buf, "LWP %d ", GET_LWP (pid)); + else + sprintf (buf, "process %d ", PIDGET (pid)); return buf; } diff --git a/gdb/thread.c b/gdb/thread.c index 7ffc65a..b8bf9e1 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -125,6 +125,31 @@ add_thread (pid) thread_list = tp; } +void +delete_thread (pid) + int pid; +{ + struct thread_info *tp, *tpprev; + + tpprev = NULL; + + for (tp = thread_list; tp; tpprev = tp, tp = tp->next) + if (tp->pid == pid) + break; + + if (!tp) + return; + + if (tpprev) + tpprev->next = tp->next; + else + thread_list = tp->next; + + free (tp); + + return; +} + static struct thread_info * find_thread_id (num) int num; @@ -332,7 +357,10 @@ info_threads_command (arg, from_tty) printf_filtered ("%d %s ", tp->num, target_pid_to_str (tp->pid)); switch_to_thread (tp->pid); - print_stack_frame (selected_frame, -1, 0); + if (selected_frame) + print_stack_frame (selected_frame, -1, 0); + else + printf_filtered ("[No stack.]\n"); } switch_to_thread (current_pid); -- 2.7.4