X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fprocfs.c;h=8a68a8964976f485d487ca2231cb845310989872;hb=b83266a0e1813b7f4891d5d6b0ed6b7302a3fe98;hp=3d82e230950c4fcc0d8bfc9514ddb83323104678;hpb=e6b8a17192da0b6aec983736388451a070b64319;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/procfs.c b/gdb/procfs.c index 3d82e23095..8a68a89649 100644 --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -1,6 +1,7 @@ /* Machine independent support for SVR4 /proc (process file system) for GDB. - Copyright 1991, 1992 Free Software Foundation, Inc. - Written by Fred Fish at Cygnus Support. + Copyright 1991, 1992-98, 1999 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support. Changes for sysv4.2mp procfs + compatibility by Geoffrey Noer at Cygnus Solutions. This file is part of GDB. @@ -16,7 +17,7 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* N O T E S @@ -24,8 +25,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ For information on the details of using /proc consult section proc(4) in the UNIX System V Release 4 System Administrator's Reference Manual. -The general register and floating point register sets are manipulated by -separate ioctl's. This file makes the assumption that if FP0_REGNUM is +The general register and floating point register sets are manipulated +separately. This file makes the assumption that if FP0_REGNUM is defined, then support for the floating point register set is desired, regardless of whether or not the actual target has floating point hardware. @@ -36,27 +37,124 @@ regardless of whether or not the actual target has floating point hardware. #include #include +#include +#include #include #include #include -#include +#include "gdb_string.h" #include #include #include -#include +#include "gdb_stat.h" #include "inferior.h" #include "target.h" #include "command.h" #include "gdbcore.h" +#include "gdbthread.h" + +#if !defined(SYS_lwp_create) && defined(SYS_lwpcreate) +# define SYS_lwp_create SYS_lwpcreate +#endif + +#if !defined(SYS_lwp_exit) && defined(SYS_lwpexit) +# define SYS_lwp_exit SYS_lwpexit +#endif + +#if !defined(SYS_lwp_wait) && defined(SYS_lwpwait) +# define SYS_lwp_wait SYS_lwpwait +#endif + +#if !defined(SYS_lwp_self) && defined(SYS_lwpself) +# define SYS_lwp_self SYS_lwpself +#endif + +#if !defined(SYS_lwp_info) && defined(SYS_lwpinfo) +# define SYS_lwp_info SYS_lwpinfo +#endif + +#if !defined(SYS_lwp_private) && defined(SYS_lwpprivate) +# define SYS_lwp_private SYS_lwpprivate +#endif + +#if !defined(SYS_lwp_kill) && defined(SYS_lwpkill) +# define SYS_lwp_kill SYS_lwpkill +#endif + +#if !defined(SYS_lwp_suspend) && defined(SYS_lwpsuspend) +# define SYS_lwp_suspend SYS_lwpsuspend +#endif + +#if !defined(SYS_lwp_continue) && defined(SYS_lwpcontinue) +# define SYS_lwp_continue SYS_lwpcontinue +#endif + +/* the name of the proc status struct depends on the implementation */ +/* Wrap Light Weight Process member in THE_PR_LWP macro for clearer code */ +#ifndef HAVE_PSTATUS_T + typedef prstatus_t gdb_prstatus_t; +#define THE_PR_LWP(a) a +#else /* HAVE_PSTATUS_T */ + typedef pstatus_t gdb_prstatus_t; +#define THE_PR_LWP(a) a.pr_lwp +#if !defined(HAVE_PRRUN_T) && defined(HAVE_MULTIPLE_PROC_FDS) + /* Fallback definitions - for using configure information directly */ +#ifndef UNIXWARE +#define UNIXWARE 1 +#endif +#if !defined(PROCFS_USE_READ_WRITE) && !defined(HAVE_PROCFS_PIOCSET) +#define PROCFS_USE_READ_WRITE 1 +#endif +#endif /* !HAVE_PRRUN_T && HAVE_MULTIPLE_PROC_FDS */ +#endif /* HAVE_PSTATUS_T */ #define MAX_SYSCALLS 256 /* Maximum number of syscalls for table */ -#ifndef PROC_NAME_FMT -#define PROC_NAME_FMT "/proc/%05d" +/* proc name formats may vary depending on the proc implementation */ +#ifdef HAVE_MULTIPLE_PROC_FDS +# ifndef CTL_PROC_NAME_FMT +# define CTL_PROC_NAME_FMT "/proc/%d/ctl" +# define AS_PROC_NAME_FMT "/proc/%d/as" +# define MAP_PROC_NAME_FMT "/proc/%d/map" +# define STATUS_PROC_NAME_FMT "/proc/%d/status" +# endif +#else /* HAVE_MULTIPLE_PROC_FDS */ +# ifndef CTL_PROC_NAME_FMT +# define CTL_PROC_NAME_FMT "/proc/%05d" +# define AS_PROC_NAME_FMT "/proc/%05d" +# define MAP_PROC_NAME_FMT "/proc/%05d" +# define STATUS_PROC_NAME_FMT "/proc/%05d" +# endif +#endif /* HAVE_MULTIPLE_PROC_FDS */ + + +/* These #ifdefs are for sol2.x in particular. sol2.x has + both a "gregset_t" and a "prgregset_t", which have + similar uses but different layouts. sol2.x gdb tries to + use prgregset_t (and prfpregset_t) everywhere. */ + +#ifdef GDB_GREGSET_TYPE + typedef GDB_GREGSET_TYPE gdb_gregset_t; +#else + typedef gregset_t gdb_gregset_t; +#endif + +#ifdef GDB_FPREGSET_TYPE + typedef GDB_FPREGSET_TYPE gdb_fpregset_t; +#else + typedef fpregset_t gdb_fpregset_t; #endif -extern struct target_ops procfs_ops; /* Forward declaration */ + +#define MAX_PROC_NAME_SIZE sizeof("/proc/1234567890/status") + +struct target_ops procfs_ops; + +int procfs_suppress_run = 0; /* Non-zero if procfs should pretend not to + be a runnable target. Used by targets + that can sit atop procfs, such as solaris + thread support. */ #if 1 /* FIXME: Gross and ugly hack to resolve coredep.c global */ CORE_ADDR kernel_u_addr; @@ -69,6 +167,52 @@ CORE_ADDR kernel_u_addr; #define si_uid _data._proc._pdata._kill.uid #endif /* BROKEN_SIGINFO_H */ +/* Define structures for passing commands to /proc/pid/ctl file. Note that + while we create these for the PROCFS_USE_READ_WRITE world, we use them + and ignore the extra cmd int in other proc schemes. +*/ +/* generic ctl msg */ +struct proc_ctl { + int cmd; + long data; +}; + +/* set general registers */ +struct greg_ctl { + int cmd; + gdb_gregset_t gregset; +}; + +/* set fp registers */ +struct fpreg_ctl { + int cmd; + gdb_fpregset_t fpregset; +}; + +/* set signals to be traced */ +struct sig_ctl { + int cmd; + sigset_t sigset; +}; + +/* set faults to be traced */ +struct flt_ctl { + int cmd; + fltset_t fltset; +}; + +/* set system calls to be traced */ +struct sys_ctl { + int cmd; + sysset_t sysset; +}; + +/* set current signal to be traced */ +struct sigi_ctl { + int cmd; + siginfo_t siginfo; +}; + /* All access to the inferior, either one started by gdb or one that has been attached to, is controlled by an instance of a procinfo structure, defined below. Since gdb currently only handles one inferior at a time, @@ -81,35 +225,44 @@ CORE_ADDR kernel_u_addr; struct procinfo { struct procinfo *next; int pid; /* Process ID of inferior */ - int fd; /* File descriptor for /proc entry */ + int ctl_fd; /* File descriptor for /proc ctl file */ + int status_fd; /* File descriptor for /proc status file */ + int as_fd; /* File descriptor for /proc as file */ + int map_fd; /* File descriptor for /proc map file */ char *pathname; /* Pathname to /proc entry */ int had_event; /* poll/select says something happened */ int was_stopped; /* Nonzero if was stopped prior to attach */ int nopass_next_sigstop; /* Don't pass a sigstop on next resume */ +#ifdef HAVE_PRRUN_T prrun_t prrun; /* Control state when it is run */ - prstatus_t prstatus; /* Current process status info */ - gregset_t gregset; /* General register set */ - fpregset_t fpregset; /* Floating point register set */ - fltset_t fltset; /* Current traced hardware fault set */ - sigset_t trace; /* Current traced signal set */ - sysset_t exitset; /* Current traced system call exit set */ - sysset_t entryset; /* Current traced system call entry set */ - fltset_t saved_fltset; /* Saved traced hardware fault set */ - sigset_t saved_trace; /* Saved traced signal set */ - sigset_t saved_sighold; /* Saved held signal set */ - sysset_t saved_exitset; /* Saved traced system call exit set */ - sysset_t saved_entryset; /* Saved traced system call entry set */ +#endif + gdb_prstatus_t prstatus; /* Current process status info */ + struct greg_ctl gregset; /* General register set */ + struct fpreg_ctl fpregset; /* Floating point register set */ + struct flt_ctl fltset; /* Current traced hardware fault set */ + struct sig_ctl trace; /* Current traced signal set */ + struct sys_ctl exitset; /* Current traced system call exit set */ + struct sys_ctl entryset; /* Current traced system call entry set */ + struct sig_ctl saved_sighold; /* Saved held signal set */ + struct flt_ctl saved_fltset; /* Saved traced hardware fault set */ + 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 trap handlers + currently installed */ + /* Pointer to list of syscall trap handlers */ + struct procfs_syscall_handler *syscall_handlers; + int saved_rtnval; /* return value and status for wait(), */ + int saved_statval; /* as supplied by a syscall handler. */ + 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 */ -static int last_resume_pid = -1; /* Last pid used with procfs_resume */ - /* Much of the information used in the /proc interface, particularly for printing status information, is kept as tables of structures of the following form. These tables can be used to map numeric values to @@ -127,45 +280,54 @@ struct trans { static struct trans pr_flag_table[] = { #if defined (PR_STOPPED) - PR_STOPPED, "PR_STOPPED", "Process is stopped", + { PR_STOPPED, "PR_STOPPED", "Process is stopped" }, #endif #if defined (PR_ISTOP) - PR_ISTOP, "PR_ISTOP", "Stopped on an event of interest", + { PR_ISTOP, "PR_ISTOP", "Stopped on an event of interest" }, #endif #if defined (PR_DSTOP) - PR_DSTOP, "PR_DSTOP", "A stop directive is in effect", + { PR_DSTOP, "PR_DSTOP", "A stop directive is in effect" }, #endif #if defined (PR_ASLEEP) - PR_ASLEEP, "PR_ASLEEP", "Sleeping in an interruptible system call", + { PR_ASLEEP, "PR_ASLEEP", "Sleeping in an interruptible system call" }, #endif #if defined (PR_FORK) - PR_FORK, "PR_FORK", "Inherit-on-fork is in effect", + { PR_FORK, "PR_FORK", "Inherit-on-fork is in effect" }, #endif #if defined (PR_RLC) - PR_RLC, "PR_RLC", "Run-on-last-close is in effect", + { PR_RLC, "PR_RLC", "Run-on-last-close is in effect" }, #endif #if defined (PR_PTRACE) - PR_PTRACE, "PR_PTRACE", "Process is being controlled by ptrace", + { PR_PTRACE, "PR_PTRACE", "Process is being controlled by ptrace" }, #endif #if defined (PR_PCINVAL) - PR_PCINVAL, "PR_PCINVAL", "PC refers to an invalid virtual address", + { PR_PCINVAL, "PR_PCINVAL", "PC refers to an invalid virtual address" }, #endif #if defined (PR_ISSYS) - PR_ISSYS, "PR_ISSYS", "Is a system process", + { PR_ISSYS, "PR_ISSYS", "Is a system process" }, #endif #if defined (PR_STEP) - PR_STEP, "PR_STEP", "Process has single step pending", + { PR_STEP, "PR_STEP", "Process has single step pending" }, #endif #if defined (PR_KLC) - PR_KLC, "PR_KLC", "Kill-on-last-close is in effect", + { PR_KLC, "PR_KLC", "Kill-on-last-close is in effect" }, #endif #if defined (PR_ASYNC) - PR_ASYNC, "PR_ASYNC", "Asynchronous stop is in effect", + { PR_ASYNC, "PR_ASYNC", "Asynchronous stop is in effect" }, #endif #if defined (PR_PCOMPAT) - PR_PCOMPAT, "PR_PCOMPAT", "Ptrace compatibility mode in effect", + { 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 - 0, NULL, NULL +#if defined (PR_ASLWP) + { PR_ASLWP, "PR_ASLWP", "Asynchronus signal LWP" }, +#endif + { 0, NULL, NULL } }; /* Translate values in the pr_why field of the prstatus struct. */ @@ -173,27 +335,30 @@ static struct trans pr_flag_table[] = static struct trans pr_why_table[] = { #if defined (PR_REQUESTED) - PR_REQUESTED, "PR_REQUESTED", "Directed to stop via PIOCSTOP/PIOCWSTOP", + { PR_REQUESTED, "PR_REQUESTED", "Directed to stop via PIOCSTOP/PIOCWSTOP" }, #endif #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", + { PR_SIGNALLED, "PR_SIGNALLED", "Receipt of a traced signal" }, #endif #if defined (PR_SYSENTRY) - PR_SYSENTRY, "PR_SYSENTRY", "Entry to a traced system call", + { PR_SYSENTRY, "PR_SYSENTRY", "Entry to a traced system call" }, #endif #if defined (PR_SYSEXIT) - PR_SYSEXIT, "PR_SYSEXIT", "Exit from a traced system call", + { PR_SYSEXIT, "PR_SYSEXIT", "Exit from a traced system call" }, #endif #if defined (PR_JOBCONTROL) - PR_JOBCONTROL, "PR_JOBCONTROL", "Default job control stop signal action", + { 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", + { PR_SUSPENDED, "PR_SUSPENDED", "Process suspended" }, +#endif +#if defined (PR_CHECKPOINT) + { PR_CHECKPOINT, "PR_CHECKPOINT", "(???)" }, #endif - 0, NULL, NULL + { 0, NULL, NULL } }; /* Hardware fault translation table. */ @@ -201,39 +366,39 @@ static struct trans pr_why_table[] = static struct trans faults_table[] = { #if defined (FLTILL) - FLTILL, "FLTILL", "Illegal instruction", + { FLTILL, "FLTILL", "Illegal instruction" }, #endif #if defined (FLTPRIV) - FLTPRIV, "FLTPRIV", "Privileged instruction", + { FLTPRIV, "FLTPRIV", "Privileged instruction" }, #endif #if defined (FLTBPT) - FLTBPT, "FLTBPT", "Breakpoint trap", + { FLTBPT, "FLTBPT", "Breakpoint trap" }, #endif #if defined (FLTTRACE) - FLTTRACE, "FLTTRACE", "Trace trap", + { FLTTRACE, "FLTTRACE", "Trace trap" }, #endif #if defined (FLTACCESS) - FLTACCESS, "FLTACCESS", "Memory access fault", + { FLTACCESS, "FLTACCESS", "Memory access fault" }, #endif #if defined (FLTBOUNDS) - FLTBOUNDS, "FLTBOUNDS", "Memory bounds violation", + { FLTBOUNDS, "FLTBOUNDS", "Memory bounds violation" }, #endif #if defined (FLTIOVF) - FLTIOVF, "FLTIOVF", "Integer overflow", + { FLTIOVF, "FLTIOVF", "Integer overflow" }, #endif #if defined (FLTIZDIV) - FLTIZDIV, "FLTIZDIV", "Integer zero divide", + { FLTIZDIV, "FLTIZDIV", "Integer zero divide" }, #endif #if defined (FLTFPE) - FLTFPE, "FLTFPE", "Floating-point exception", + { FLTFPE, "FLTFPE", "Floating-point exception" }, #endif #if defined (FLTSTACK) - FLTSTACK, "FLTSTACK", "Unrecoverable stack fault", + { FLTSTACK, "FLTSTACK", "Unrecoverable stack fault" }, #endif #if defined (FLTPAGE) - FLTPAGE, "FLTPAGE", "Recoverable page fault", + { FLTPAGE, "FLTPAGE", "Recoverable page fault" }, #endif - 0, NULL, NULL + { 0, NULL, NULL } }; /* Translation table for signal generation information. See UNIX System @@ -246,209 +411,278 @@ static struct sigcode { char *desc; } siginfo_table[] = { #if defined (SIGILL) && defined (ILL_ILLOPC) - SIGILL, ILL_ILLOPC, "ILL_ILLOPC", "Illegal opcode", + { SIGILL, ILL_ILLOPC, "ILL_ILLOPC", "Illegal opcode" }, #endif #if defined (SIGILL) && defined (ILL_ILLOPN) - SIGILL, ILL_ILLOPN, "ILL_ILLOPN", "Illegal operand", + { SIGILL, ILL_ILLOPN, "ILL_ILLOPN", "Illegal operand", }, #endif #if defined (SIGILL) && defined (ILL_ILLADR) - SIGILL, ILL_ILLADR, "ILL_ILLADR", "Illegal addressing mode", + { SIGILL, ILL_ILLADR, "ILL_ILLADR", "Illegal addressing mode" }, #endif #if defined (SIGILL) && defined (ILL_ILLTRP) - SIGILL, ILL_ILLTRP, "ILL_ILLTRP", "Illegal trap", + { SIGILL, ILL_ILLTRP, "ILL_ILLTRP", "Illegal trap" }, #endif #if defined (SIGILL) && defined (ILL_PRVOPC) - SIGILL, ILL_PRVOPC, "ILL_PRVOPC", "Privileged opcode", + { SIGILL, ILL_PRVOPC, "ILL_PRVOPC", "Privileged opcode" }, #endif #if defined (SIGILL) && defined (ILL_PRVREG) - SIGILL, ILL_PRVREG, "ILL_PRVREG", "Privileged register", + { SIGILL, ILL_PRVREG, "ILL_PRVREG", "Privileged register" }, #endif #if defined (SIGILL) && defined (ILL_COPROC) - SIGILL, ILL_COPROC, "ILL_COPROC", "Coprocessor error", + { SIGILL, ILL_COPROC, "ILL_COPROC", "Coprocessor error" }, #endif #if defined (SIGILL) && defined (ILL_BADSTK) - SIGILL, ILL_BADSTK, "ILL_BADSTK", "Internal stack error", + { SIGILL, ILL_BADSTK, "ILL_BADSTK", "Internal stack error" }, #endif #if defined (SIGFPE) && defined (FPE_INTDIV) - SIGFPE, FPE_INTDIV, "FPE_INTDIV", "Integer divide by zero", + { SIGFPE, FPE_INTDIV, "FPE_INTDIV", "Integer divide by zero" }, #endif #if defined (SIGFPE) && defined (FPE_INTOVF) - SIGFPE, FPE_INTOVF, "FPE_INTOVF", "Integer overflow", + { SIGFPE, FPE_INTOVF, "FPE_INTOVF", "Integer overflow" }, #endif #if defined (SIGFPE) && defined (FPE_FLTDIV) - SIGFPE, FPE_FLTDIV, "FPE_FLTDIV", "Floating point divide by zero", + { SIGFPE, FPE_FLTDIV, "FPE_FLTDIV", "Floating point divide by zero" }, #endif #if defined (SIGFPE) && defined (FPE_FLTOVF) - SIGFPE, FPE_FLTOVF, "FPE_FLTOVF", "Floating point overflow", + { SIGFPE, FPE_FLTOVF, "FPE_FLTOVF", "Floating point overflow" }, #endif #if defined (SIGFPE) && defined (FPE_FLTUND) - SIGFPE, FPE_FLTUND, "FPE_FLTUND", "Floating point underflow", + { SIGFPE, FPE_FLTUND, "FPE_FLTUND", "Floating point underflow" }, #endif #if defined (SIGFPE) && defined (FPE_FLTRES) - SIGFPE, FPE_FLTRES, "FPE_FLTRES", "Floating point inexact result", + { SIGFPE, FPE_FLTRES, "FPE_FLTRES", "Floating point inexact result" }, #endif #if defined (SIGFPE) && defined (FPE_FLTINV) - SIGFPE, FPE_FLTINV, "FPE_FLTINV", "Invalid floating point operation", + { SIGFPE, FPE_FLTINV, "FPE_FLTINV", "Invalid floating point operation" }, #endif #if defined (SIGFPE) && defined (FPE_FLTSUB) - SIGFPE, FPE_FLTSUB, "FPE_FLTSUB", "Subscript out of range", + { SIGFPE, FPE_FLTSUB, "FPE_FLTSUB", "Subscript out of range" }, #endif #if defined (SIGSEGV) && defined (SEGV_MAPERR) - SIGSEGV, SEGV_MAPERR, "SEGV_MAPERR", "Address not mapped to object", + { SIGSEGV, SEGV_MAPERR, "SEGV_MAPERR", "Address not mapped to object" }, #endif #if defined (SIGSEGV) && defined (SEGV_ACCERR) - SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for object", + { SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for object" }, #endif #if defined (SIGBUS) && defined (BUS_ADRALN) - SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment", + { SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment" }, #endif #if defined (SIGBUS) && defined (BUS_ADRERR) - SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Non-existent physical address", + { SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Non-existent physical address" }, #endif #if defined (SIGBUS) && defined (BUS_OBJERR) - SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object specific hardware error", + { SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object specific hardware error" }, #endif #if defined (SIGTRAP) && defined (TRAP_BRKPT) - SIGTRAP, TRAP_BRKPT, "TRAP_BRKPT", "Process breakpoint", + { SIGTRAP, TRAP_BRKPT, "TRAP_BRKPT", "Process breakpoint" }, #endif #if defined (SIGTRAP) && defined (TRAP_TRACE) - SIGTRAP, TRAP_TRACE, "TRAP_TRACE", "Process trace trap", + { SIGTRAP, TRAP_TRACE, "TRAP_TRACE", "Process trace trap" }, #endif #if defined (SIGCLD) && defined (CLD_EXITED) - SIGCLD, CLD_EXITED, "CLD_EXITED", "Child has exited", + { SIGCLD, CLD_EXITED, "CLD_EXITED", "Child has exited" }, #endif #if defined (SIGCLD) && defined (CLD_KILLED) - SIGCLD, CLD_KILLED, "CLD_KILLED", "Child was killed", + { SIGCLD, CLD_KILLED, "CLD_KILLED", "Child was killed" }, #endif #if defined (SIGCLD) && defined (CLD_DUMPED) - SIGCLD, CLD_DUMPED, "CLD_DUMPED", "Child has terminated abnormally", + { SIGCLD, CLD_DUMPED, "CLD_DUMPED", "Child has terminated abnormally" }, #endif #if defined (SIGCLD) && defined (CLD_TRAPPED) - SIGCLD, CLD_TRAPPED, "CLD_TRAPPED", "Traced child has trapped", + { SIGCLD, CLD_TRAPPED, "CLD_TRAPPED", "Traced child has trapped" }, #endif #if defined (SIGCLD) && defined (CLD_STOPPED) - SIGCLD, CLD_STOPPED, "CLD_STOPPED", "Child has stopped", + { SIGCLD, CLD_STOPPED, "CLD_STOPPED", "Child has stopped" }, #endif #if defined (SIGCLD) && defined (CLD_CONTINUED) - SIGCLD, CLD_CONTINUED, "CLD_CONTINUED", "Stopped child had continued", + { SIGCLD, CLD_CONTINUED, "CLD_CONTINUED", "Stopped child had continued" }, #endif #if defined (SIGPOLL) && defined (POLL_IN) - SIGPOLL, POLL_IN, "POLL_IN", "Input input available", + { SIGPOLL, POLL_IN, "POLL_IN", "Input input available" }, #endif #if defined (SIGPOLL) && defined (POLL_OUT) - SIGPOLL, POLL_OUT, "POLL_OUT", "Output buffers available", + { SIGPOLL, POLL_OUT, "POLL_OUT", "Output buffers available" }, #endif #if defined (SIGPOLL) && defined (POLL_MSG) - SIGPOLL, POLL_MSG, "POLL_MSG", "Input message available", + { SIGPOLL, POLL_MSG, "POLL_MSG", "Input message available" }, #endif #if defined (SIGPOLL) && defined (POLL_ERR) - SIGPOLL, POLL_ERR, "POLL_ERR", "I/O error", + { SIGPOLL, POLL_ERR, "POLL_ERR", "I/O error" }, #endif #if defined (SIGPOLL) && defined (POLL_PRI) - SIGPOLL, POLL_PRI, "POLL_PRI", "High priority input available", + { SIGPOLL, POLL_PRI, "POLL_PRI", "High priority input available" }, #endif #if defined (SIGPOLL) && defined (POLL_HUP) - SIGPOLL, POLL_HUP, "POLL_HUP", "Device disconnected", + { SIGPOLL, POLL_HUP, "POLL_HUP", "Device disconnected" }, #endif - 0, 0, NULL, NULL + { 0, 0, NULL, NULL } }; static char *syscall_table[MAX_SYSCALLS]; /* Prototypes for local functions */ -static void -set_proc_siginfo PARAMS ((struct procinfo *, int)); +static void procfs_stop PARAMS ((void)); -static void -init_syscall_table PARAMS ((void)); +static int procfs_thread_alive PARAMS ((int)); -static char * -syscallname PARAMS ((int)); +static int procfs_can_run PARAMS ((void)); -static char * -signalname PARAMS ((int)); +static void procfs_mourn_inferior PARAMS ((void)); -static char * -errnoname PARAMS ((int)); +static void procfs_fetch_registers PARAMS ((int)); -static int -proc_address_to_fd PARAMS ((struct procinfo *, CORE_ADDR, int)); +static int procfs_wait PARAMS ((int, struct target_waitstatus *)); -static int -open_proc_file PARAMS ((int, struct procinfo *, int)); +static void procfs_open PARAMS ((char *, int)); -static void -close_proc_file PARAMS ((struct procinfo *)); +static void procfs_files_info PARAMS ((struct target_ops *)); -static void -unconditionally_kill_inferior PARAMS ((struct procinfo *)); +static void procfs_prepare_to_store PARAMS ((void)); -static NORETURN void -proc_init_failed PARAMS ((struct procinfo *, char *)); +static void procfs_detach PARAMS ((char *, int)); -static void -info_proc PARAMS ((char *, int)); +static void procfs_attach PARAMS ((char *, int)); -static void -info_proc_flags PARAMS ((struct procinfo *, int)); +static void proc_set_exec_trap PARAMS ((void)); -static void -info_proc_stop PARAMS ((struct procinfo *, int)); +static void procfs_init_inferior PARAMS ((int)); -static void -info_proc_siginfo PARAMS ((struct procinfo *, int)); +static struct procinfo *create_procinfo PARAMS ((int)); -static void -info_proc_syscalls PARAMS ((struct procinfo *, int)); +static void procfs_store_registers PARAMS ((int)); -static void -info_proc_mappings PARAMS ((struct procinfo *, int)); +static int procfs_xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *)); -static void -info_proc_signals PARAMS ((struct procinfo *, int)); +static void procfs_kill_inferior PARAMS ((void)); -static void -info_proc_faults PARAMS ((struct procinfo *, int)); +static char *sigcodedesc PARAMS ((siginfo_t *)); -static char * -mappingflags PARAMS ((long)); +static char *sigcodename PARAMS ((siginfo_t *)); -static char * -lookupname PARAMS ((struct trans *, unsigned int, char *)); +static struct procinfo *wait_fd PARAMS ((void)); -static char * -lookupdesc PARAMS ((struct trans *, unsigned int)); +static void remove_fd PARAMS ((struct procinfo *)); -static int -do_attach PARAMS ((int pid)); +static void add_fd PARAMS ((struct procinfo *)); -static void -do_detach PARAMS ((int siggnal)); +static void set_proc_siginfo PARAMS ((struct procinfo *, int)); -static void -procfs_create_inferior PARAMS ((char *, char *, char **)); +static void init_syscall_table PARAMS ((void)); -static void -procfs_notice_signals PARAMS ((int pid)); +static char *syscallname PARAMS ((int)); -static struct procinfo * -find_procinfo PARAMS ((pid_t pid, int okfail)); +static char *signalname PARAMS ((int)); + +static char *errnoname PARAMS ((int)); + +static int proc_address_to_fd PARAMS ((struct procinfo *, CORE_ADDR, int)); + +static int open_proc_file PARAMS ((int, struct procinfo *, int, int)); + +static void close_proc_file PARAMS ((struct procinfo *)); + +static void close_proc_file_cleanup PARAMS ((void*)); + +static struct cleanup *make_cleanup_close_proc_file PARAMS ((struct procinfo *)); + +static void unconditionally_kill_inferior PARAMS ((struct procinfo *)); + +static NORETURN void proc_init_failed PARAMS ((struct procinfo *, char *, int)) ATTR_NORETURN; + +static void info_proc PARAMS ((char *, int)); + +static void info_proc_flags PARAMS ((struct procinfo *, int)); + +static void info_proc_stop PARAMS ((struct procinfo *, int)); + +static void info_proc_siginfo PARAMS ((struct procinfo *, int)); + +static void info_proc_syscalls PARAMS ((struct procinfo *, int)); + +static void info_proc_mappings PARAMS ((struct procinfo *, int)); + +static void info_proc_signals PARAMS ((struct procinfo *, int)); + +static void info_proc_faults PARAMS ((struct procinfo *, int)); + +static char *mappingflags PARAMS ((long)); + +static char *lookupname PARAMS ((struct trans *, unsigned int, char *)); + +static char *lookupdesc PARAMS ((struct trans *, unsigned int)); + +static int do_attach PARAMS ((int pid)); + +static void do_detach PARAMS ((int siggnal)); + +static void procfs_create_inferior PARAMS ((char *, char *, char **)); + +static void procfs_notice_signals PARAMS ((int pid)); + +static void notice_signals PARAMS ((struct procinfo *, struct sig_ctl *)); + +static struct procinfo *find_procinfo PARAMS ((pid_t pid, int okfail)); + +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, + int why, int *rtnval, int *statval)); + +static void procfs_set_syscall_trap PARAMS ((struct procinfo *pi, + int syscall_num, int flags, + syscall_func_t *func)); + +static void procfs_clear_syscall_trap PARAMS ((struct procinfo *pi, + int syscall_num, int errok)); + +#define PROCFS_SYSCALL_ENTRY 0x1 /* Trap on entry to sys call */ +#define PROCFS_SYSCALL_EXIT 0x2 /* Trap on exit from sys call */ + +static syscall_func_t procfs_exit_handler; + +static syscall_func_t procfs_exec_handler; + +#ifdef SYS_sproc +static syscall_func_t procfs_sproc_handler; +static syscall_func_t procfs_fork_handler; +#endif + +#ifdef SYS_lwp_create +static syscall_func_t procfs_lwp_creation_handler; +#endif + +static void modify_inherit_on_fork_flag PARAMS ((int fd, int flag)); +static void modify_run_on_last_close_flag PARAMS ((int fd, int flag)); + +/* */ + +struct procfs_syscall_handler +{ + int syscall_num; /* The number of the system call being handled */ + /* The function to be called */ + syscall_func_t *func; +}; + +static void procfs_resume PARAMS ((int pid, int step, + enum target_signal signo)); + +static void init_procfs_ops PARAMS ((void)); /* External function prototypes that can't be easily included in any header file because the args are typedefs in system include files. */ -extern void -supply_gregset PARAMS ((gregset_t *)); +extern void supply_gregset PARAMS ((gdb_gregset_t *)); -extern void -fill_gregset PARAMS ((gregset_t *, int)); +extern void fill_gregset PARAMS ((gdb_gregset_t *, int)); -extern void -supply_fpregset PARAMS ((fpregset_t *)); +#ifdef FP0_REGNUM +extern void supply_fpregset PARAMS ((gdb_fpregset_t *)); -extern void -fill_fpregset PARAMS ((fpregset_t *, int)); +extern void fill_fpregset PARAMS ((gdb_fpregset_t *, int)); +#endif /* @@ -528,12 +762,32 @@ add_fd (pi) poll_list = (struct pollfd *) xrealloc (poll_list, (num_poll_list + 1) * sizeof (struct pollfd)); - poll_list[num_poll_list].fd = pi->fd; + poll_list[num_poll_list].fd = pi->ctl_fd; +#ifdef UNIXWARE + poll_list[num_poll_list].events = POLLWRNORM; +#else poll_list[num_poll_list].events = POLLPRI; +#endif 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; @@ -542,10 +796,10 @@ remove_fd (pi) for (i = 0; i < num_poll_list; i++) { - if (poll_list[i].fd == pi->fd) + if (poll_list[i].fd == pi->ctl_fd) { if (i != num_poll_list - 1) - memcpy (poll_list, poll_list + i + 1, + memcpy (poll_list + i, poll_list + i + 1, (num_poll_list - i - 1) * sizeof (struct pollfd)); num_poll_list--; @@ -561,66 +815,189 @@ remove_fd (pi) } } -#define LOSING_POLL unixware_sux +/* + +LOCAL FUNCTION + + procfs_read_status - get procfs fd status + +SYNOPSIS + + static int procfs_read_status (pi) struct procinfo *pi; + +DESCRIPTION + + Given a pointer to a procinfo struct, get the status of + the status_fd in the appropriate way. Returns 0 on failure, + 1 on success. + */ + +static int +procfs_read_status (pi) + struct procinfo *pi; +{ +#ifdef PROCFS_USE_READ_WRITE + if ((lseek (pi->status_fd, 0, SEEK_SET) < 0) || + (read (pi->status_fd, (char *) &pi->prstatus, + sizeof (gdb_prstatus_t)) != sizeof (gdb_prstatus_t))) +#else + if (ioctl (pi->status_fd, PIOCSTATUS, &pi->prstatus) < 0) +#endif + return 0; + else + return 1; +} + +/* + +LOCAL FUNCTION + + procfs_write_pcwstop - send a PCWSTOP to procfs fd + +SYNOPSIS + + static int procfs_write_pcwstop (pi) struct procinfo *pi; + +DESCRIPTION + + Given a pointer to a procinfo struct, send a PCWSTOP to + the ctl_fd in the appropriate way. Returns 0 on failure, + 1 on success. + */ + +static int +procfs_write_pcwstop (pi) + struct procinfo *pi; +{ +#ifdef PROCFS_USE_READ_WRITE + long cmd = PCWSTOP; + if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0) +#else + if (ioctl (pi->ctl_fd, PIOCWSTOP, &pi->prstatus) < 0) +#endif + return 0; + else + return 1; +} + +/* + +LOCAL FUNCTION + + procfs_write_pckill - send a kill to procfs fd + +SYNOPSIS + + static void procfs_write_pckill (pi) struct procinfo *pi; + +DESCRIPTION + + Given a pointer to a procinfo struct, send a kill to + the ctl_fd in the appropriate way. Returns 0 on failure, + 1 on success. + */ + +static void +procfs_write_pckill (pi) + struct procinfo *pi; +{ +#ifdef PROCFS_USE_READ_WRITE + struct proc_ctl pctl; + pctl.cmd = PCKILL; + pctl.data = SIGKILL; + write (pi->ctl_fd, &pctl, sizeof (struct proc_ctl)); +#else + int signo = SIGKILL; + ioctl (pi->ctl_fd, PIOCKILL, &signo); +#endif +} static struct procinfo * wait_fd () { - struct procinfo *pi; + struct procinfo *pi, *next_pi; +#ifndef LOSING_POLL int num_fds; int i; +#endif - if (attach_flag) - set_sigint_trap (); /* Causes SIGINT to be passed on to the + set_sigint_trap (); /* Causes SIGINT to be passed on to the attached process. */ + set_sigio_trap (); + wait_again: #ifndef LOSING_POLL - num_fds = poll (poll_list, num_poll_list, -1); -#else + while (1) + { + num_fds = poll (poll_list, num_poll_list, -1); + if (num_fds > 0) + break; + if (num_fds < 0 && errno == EINTR) + continue; + print_sys_errmsg ("poll failed", errno); + error ("Poll failed, returned %d", num_fds); + } +#else /* LOSING_POLL */ pi = current_procinfo; - while (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0) + while (!procfs_write_pcwstop (pi)) { - if (errno != EINTR) + if (errno == ENOENT) + { + /* Process exited. */ + pi->prstatus.pr_flags = 0; + break; + } + else if (errno != EINTR) { print_sys_errmsg (pi->pathname, errno); - error ("PIOCWSTOP failed"); + error ("procfs_write_pcwstop failed"); } } pi->had_event = 1; -#endif +#endif /* LOSING_POLL */ - if (attach_flag) - clear_sigint_trap(); + clear_sigint_trap (); + clear_sigio_trap (); #ifndef LOSING_POLL - if (num_fds <= 0) - { - print_sys_errmsg ("poll failed\n", errno); - error ("Poll failed, returned %d", num_fds); - } - for (i = 0; i < num_poll_list && num_fds > 0; i++) { - if ((poll_list[i].revents & (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) + for (pi = procinfo_list; pi; pi = next_pi) { - if (poll_list[i].fd == pi->fd) + next_pi = pi->next; + if (poll_list[i].fd == pi->ctl_fd) { - if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0) - { - print_sys_errmsg (pi->pathname, errno); - error ("PIOCSTATUS failed"); - } num_fds--; + if ((poll_list[i].revents & POLLHUP) != 0 || + !procfs_read_status(pi)) + { /* The LWP has apparently terminated. */ + if (num_poll_list <= 1) + { + pi->prstatus.pr_flags = 0; + pi->had_event = 1; + break; + } + if (info_verbose) + printf_filtered ("LWP %d exited.\n", + (pi->pid >> 16) & 0xffff); + close_proc_file (pi); + i--; /* don't skip deleted entry */ + if (num_fds != 0) + break; /* already another event to process */ + else + goto wait_again; /* wait for another event */ + } pi->had_event = 1; break; } } if (!pi) - error ("procfs_wait: Couldn't find procinfo for fd %d\n", + error ("wait_fd: Couldn't find procinfo for fd %d\n", poll_list[i].fd); } #endif /* LOSING_POLL */ @@ -797,18 +1174,15 @@ syscallname (syscallnum) int syscallnum; { static char locbuf[32]; - char *rtnval; - if (syscallnum >= 0 && syscallnum < MAX_SYSCALLS) - { - rtnval = syscall_table[syscallnum]; - } + if (syscallnum >= 0 && syscallnum < MAX_SYSCALLS + && syscall_table[syscallnum] != NULL) + return syscall_table[syscallnum]; else { sprintf (locbuf, "syscall %u", syscallnum); - rtnval = locbuf; + return locbuf; } - return (rtnval); } /* @@ -992,6 +1366,9 @@ init_syscall_table () #if defined (SYS_sys3b) syscall_table[SYS_sys3b] = "sys3b"; #endif +#if defined (SYS_sysi86) + syscall_table[SYS_sysi86] = "sysi86"; +#endif #if defined (SYS_acct) syscall_table[SYS_acct] = "acct"; #endif @@ -1208,37 +1585,277 @@ init_syscall_table () #if defined (SYS_sproc) syscall_table[SYS_sproc] = "sproc"; #endif -} - -/* - -LOCAL FUNCTION - - procfs_kill_inferior - kill any currently inferior - -SYNOPSIS - - void procfs_kill_inferior (void) - -DESCRIPTION - - Kill any current inferior. - -NOTES - - Kills even attached inferiors. Presumably the user has already - been prompted that the inferior is an attached one rather than - one started by gdb. (FIXME?) - -*/ - -static void -procfs_kill_inferior () -{ - target_mourn_inferior (); -} - -/* +#if defined (SYS_keyctl) + syscall_table[SYS_keyctl] = "keyctl"; +#endif +#if defined (SYS_secsys) + syscall_table[SYS_secsys] = "secsys"; +#endif +#if defined (SYS_filepriv) + syscall_table[SYS_filepriv] = "filepriv"; +#endif +#if defined (SYS_procpriv) + syscall_table[SYS_procpriv] = "procpriv"; +#endif +#if defined (SYS_devstat) + syscall_table[SYS_devstat] = "devstat"; +#endif +#if defined (SYS_aclipc) + syscall_table[SYS_aclipc] = "aclipc"; +#endif +#if defined (SYS_fdevstat) + syscall_table[SYS_fdevstat] = "fdevstat"; +#endif +#if defined (SYS_flvlfile) + syscall_table[SYS_flvlfile] = "flvlfile"; +#endif +#if defined (SYS_lvlfile) + syscall_table[SYS_lvlfile] = "lvlfile"; +#endif +#if defined (SYS_lvlequal) + syscall_table[SYS_lvlequal] = "lvlequal"; +#endif +#if defined (SYS_lvlproc) + syscall_table[SYS_lvlproc] = "lvlproc"; +#endif +#if defined (SYS_lvlipc) + syscall_table[SYS_lvlipc] = "lvlipc"; +#endif +#if defined (SYS_acl) + syscall_table[SYS_acl] = "acl"; +#endif +#if defined (SYS_auditevt) + syscall_table[SYS_auditevt] = "auditevt"; +#endif +#if defined (SYS_auditctl) + syscall_table[SYS_auditctl] = "auditctl"; +#endif +#if defined (SYS_auditdmp) + syscall_table[SYS_auditdmp] = "auditdmp"; +#endif +#if defined (SYS_auditlog) + syscall_table[SYS_auditlog] = "auditlog"; +#endif +#if defined (SYS_auditbuf) + syscall_table[SYS_auditbuf] = "auditbuf"; +#endif +#if defined (SYS_lvldom) + syscall_table[SYS_lvldom] = "lvldom"; +#endif +#if defined (SYS_lvlvfs) + syscall_table[SYS_lvlvfs] = "lvlvfs"; +#endif +#if defined (SYS_mkmld) + syscall_table[SYS_mkmld] = "mkmld"; +#endif +#if defined (SYS_mldmode) + syscall_table[SYS_mldmode] = "mldmode"; +#endif +#if defined (SYS_secadvise) + syscall_table[SYS_secadvise] = "secadvise"; +#endif +#if defined (SYS_online) + syscall_table[SYS_online] = "online"; +#endif +#if defined (SYS_setitimer) + syscall_table[SYS_setitimer] = "setitimer"; +#endif +#if defined (SYS_getitimer) + syscall_table[SYS_getitimer] = "getitimer"; +#endif +#if defined (SYS_gettimeofday) + syscall_table[SYS_gettimeofday] = "gettimeofday"; +#endif +#if defined (SYS_settimeofday) + syscall_table[SYS_settimeofday] = "settimeofday"; +#endif +#if defined (SYS_lwp_create) + syscall_table[SYS_lwp_create] = "_lwp_create"; +#endif +#if defined (SYS_lwp_exit) + syscall_table[SYS_lwp_exit] = "_lwp_exit"; +#endif +#if defined (SYS_lwp_wait) + syscall_table[SYS_lwp_wait] = "_lwp_wait"; +#endif +#if defined (SYS_lwp_self) + syscall_table[SYS_lwp_self] = "_lwp_self"; +#endif +#if defined (SYS_lwp_info) + syscall_table[SYS_lwp_info] = "_lwp_info"; +#endif +#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"; +#endif +#if defined (SYS_processor_exbind) + syscall_table[SYS_processor_exbind] = "processor_exbind"; +#endif +#if defined (SYS_prepblock) + syscall_table[SYS_prepblock] = "prepblock"; +#endif +#if defined (SYS_block) + syscall_table[SYS_block] = "block"; +#endif +#if defined (SYS_rdblock) + syscall_table[SYS_rdblock] = "rdblock"; +#endif +#if defined (SYS_unblock) + syscall_table[SYS_unblock] = "unblock"; +#endif +#if defined (SYS_cancelblock) + syscall_table[SYS_cancelblock] = "cancelblock"; +#endif +#if defined (SYS_pread) + syscall_table[SYS_pread] = "pread"; +#endif +#if defined (SYS_pwrite) + syscall_table[SYS_pwrite] = "pwrite"; +#endif +#if defined (SYS_truncate) + syscall_table[SYS_truncate] = "truncate"; +#endif +#if defined (SYS_ftruncate) + syscall_table[SYS_ftruncate] = "ftruncate"; +#endif +#if defined (SYS_lwp_kill) + syscall_table[SYS_lwp_kill] = "_lwp_kill"; +#endif +#if defined (SYS_sigwait) + syscall_table[SYS_sigwait] = "sigwait"; +#endif +#if defined (SYS_fork1) + syscall_table[SYS_fork1] = "fork1"; +#endif +#if defined (SYS_forkall) + syscall_table[SYS_forkall] = "forkall"; +#endif +#if defined (SYS_modload) + syscall_table[SYS_modload] = "modload"; +#endif +#if defined (SYS_moduload) + syscall_table[SYS_moduload] = "moduload"; +#endif +#if defined (SYS_modpath) + syscall_table[SYS_modpath] = "modpath"; +#endif +#if defined (SYS_modstat) + syscall_table[SYS_modstat] = "modstat"; +#endif +#if defined (SYS_modadm) + syscall_table[SYS_modadm] = "modadm"; +#endif +#if defined (SYS_getksym) + syscall_table[SYS_getksym] = "getksym"; +#endif +#if defined (SYS_lwp_suspend) + syscall_table[SYS_lwp_suspend] = "_lwp_suspend"; +#endif +#if defined (SYS_lwp_continue) + syscall_table[SYS_lwp_continue] = "_lwp_continue"; +#endif +#if defined (SYS_priocntllst) + syscall_table[SYS_priocntllst] = "priocntllst"; +#endif +#if defined (SYS_sleep) + syscall_table[SYS_sleep] = "sleep"; +#endif +#if defined (SYS_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"; +#endif +#if defined (SYS_lwp_sema_trywait) + syscall_table[SYS_lwp_sema_trywait] = "lwp_sema_trywait"; +#endif +#if defined(SYS_fstatvfs64) + syscall_table[SYS_fstatvfs64] = "fstatvfs64"; +#endif +#if defined(SYS_statvfs64) + syscall_table[SYS_statvfs64] = "statvfs64"; +#endif +#if defined(SYS_ftruncate64) + syscall_table[SYS_ftruncate64] = "ftruncate64"; +#endif +#if defined(SYS_truncate64) + syscall_table[SYS_truncate64] = "truncate64"; +#endif +#if defined(SYS_getrlimit64) + syscall_table[SYS_getrlimit64] = "getrlimit64"; +#endif +#if defined(SYS_setrlimit64) + syscall_table[SYS_setrlimit64] = "setrlimit64"; +#endif +#if defined(SYS_lseek64) + syscall_table[SYS_lseek64] = "lseek64"; +#endif +#if defined(SYS_mmap64) + syscall_table[SYS_mmap64] = "mmap64"; +#endif +#if defined(SYS_pread64) + syscall_table[SYS_pread64] = "pread64"; +#endif +#if defined(SYS_creat64) + syscall_table[SYS_creat64] = "creat64"; +#endif +#if defined(SYS_dshmsys) + syscall_table[SYS_dshmsys] = "dshmsys"; +#endif +#if defined(SYS_invlpg) + syscall_table[SYS_invlpg] = "invlpg"; +#endif +#if defined(SYS_cg_ids) + syscall_table[SYS_cg_ids] = "cg_ids"; +#endif +#if defined(SYS_cg_processors) + syscall_table[SYS_cg_processors] = "cg_processors"; +#endif +#if defined(SYS_cg_info) + syscall_table[SYS_cg_info] = "cg_info"; +#endif +#if defined(SYS_cg_bind) + syscall_table[SYS_cg_bind] = "cg_bind"; +#endif +#if defined(SYS_cg_current) + syscall_table[SYS_cg_current] = "cg_current"; +#endif +#if defined(SYS_cg_memloc) + syscall_table[SYS_cg_memloc] = "cg_memloc"; +#endif +} + +/* + +LOCAL FUNCTION + + procfs_kill_inferior - kill any current inferior + +SYNOPSIS + + void procfs_kill_inferior (void) + +DESCRIPTION + + Kill any current inferior. + +NOTES + + Kills even attached inferiors. Presumably the user has already + been prompted that the inferior is an attached one rather than + one started by gdb. (FIXME?) + +*/ + +static void +procfs_kill_inferior () +{ + target_mourn_inferior (); +} + +/* LOCAL FUNCTION @@ -1265,13 +1882,38 @@ static void unconditionally_kill_inferior (pi) struct procinfo *pi; { - int signo; int ppid; + struct proc_ctl pctl; ppid = pi->prstatus.pr_ppid; - signo = SIGKILL; - ioctl (pi->fd, PIOCKILL, &signo); +#ifdef PROCFS_NEED_CLEAR_CURSIG_FOR_KILL + /* Alpha OSF/1-3.x procfs needs a clear of the current signal + before the PIOCKILL, otherwise it might generate a corrupted core + file for the inferior. */ + ioctl (pi->ctl_fd, PIOCSSIG, NULL); +#endif +#ifdef PROCFS_NEED_PIOCSSIG_FOR_KILL + /* Alpha OSF/1-2.x procfs needs a PIOCSSIG call with a SIGKILL signal + to kill the inferior, otherwise it might remain stopped with a + pending SIGKILL. + We do not check the result of the PIOCSSIG, the inferior might have + died already. */ + { + struct siginfo newsiginfo; + + memset ((char *) &newsiginfo, 0, sizeof (newsiginfo)); + newsiginfo.si_signo = SIGKILL; + newsiginfo.si_code = 0; + newsiginfo.si_errno = 0; + newsiginfo.si_pid = getpid (); + newsiginfo.si_uid = getuid (); + ioctl (pi->ctl_fd, PIOCSSIG, &newsiginfo); + } +#else /* PROCFS_NEED_PIOCSSIG_FOR_KILL */ + procfs_write_pckill (pi); +#endif /* PROCFS_NEED_PIOCSSIG_FOR_KILL */ + close_proc_file (pi); /* Only wait() for our direct children. Our grandchildren zombies are killed @@ -1321,15 +1963,15 @@ procfs_xfer_memory (memaddr, myaddr, len, dowrite, target) pi = current_procinfo; - if (lseek(pi->fd, (off_t) memaddr, 0) == (off_t) memaddr) + if (lseek(pi->as_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr) { if (dowrite) { - nbytes = write (pi->fd, myaddr, len); + nbytes = write (pi->as_fd, myaddr, len); } else { - nbytes = read (pi->fd, myaddr, len); + nbytes = read (pi->as_fd, myaddr, len); } if (nbytes < 0) { @@ -1382,15 +2024,32 @@ procfs_store_registers (regno) int regno; { struct procinfo *pi; +#ifdef PROCFS_USE_READ_WRITE + struct greg_ctl greg; + struct fpreg_ctl fpreg; +#endif pi = current_procinfo; +#ifdef PROCFS_USE_READ_WRITE + if (regno != -1) + { + procfs_read_status (pi); + memcpy ((char *) &greg.gregset, + (char *) &pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs, + sizeof (gdb_gregset_t)); + } + fill_gregset (&greg.gregset, regno); + greg.cmd = PCSREG; + write (pi->ctl_fd, &greg, sizeof (greg)); +#else /* PROCFS_USE_READ_WRITE */ if (regno != -1) { - ioctl (pi->fd, PIOCGREG, &pi->gregset); + ioctl (pi->ctl_fd, PIOCGREG, &pi->gregset.gregset); } - fill_gregset (&pi->gregset, regno); - ioctl (pi->fd, PIOCSREG, &pi->gregset); + fill_gregset (&pi->gregset.gregset, regno); + ioctl (pi->ctl_fd, PIOCSREG, &pi->gregset.gregset); +#endif /* PROCFS_USE_READ_WRITE */ #if defined (FP0_REGNUM) @@ -1398,12 +2057,25 @@ procfs_store_registers (regno) target has floating point hardware. Since we ignore the returned value, we'll never know whether it worked or not anyway. */ +#ifdef PROCFS_USE_READ_WRITE + if (regno != -1) + { + procfs_read_status (pi); + memcpy ((char *) &fpreg.fpregset, + (char *) &pi->prstatus.pr_lwp.pr_context.uc_mcontext.fpregs, + sizeof (gdb_fpregset_t)); + } + fill_fpregset (&fpreg.fpregset, regno); + fpreg.cmd = PCSFPREG; + write (pi->ctl_fd, &fpreg, sizeof (fpreg)); +#else /* PROCFS_USE_READ_WRITE */ if (regno != -1) { - ioctl (pi->fd, PIOCGFPREG, &pi->fpregset); + ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset.fpregset); } - fill_fpregset (&pi->fpregset, regno); - ioctl (pi->fd, PIOCSFPREG, &pi->fpregset); + fill_fpregset (&pi->fpregset.fpregset, regno); + ioctl (pi->ctl_fd, PIOCSFPREG, &pi->fpregset.fpregset); +#endif /* PROCFS_USE_READ_WRITE */ #endif /* FP0_REGNUM */ @@ -1413,16 +2085,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 - void create_procinfo (int pid) + struct procinfo * init_procinfo (int pid) DESCRIPTION - Allocate a procinfo structure, open the /proc file and then sets up - the set of signals and faults that are to be traced. + 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 @@ -1431,19 +2104,23 @@ NOTES */ -static void -create_procinfo (pid) +static struct procinfo * +init_procinfo (pid, kill) int pid; + int kill; { - struct procinfo *pi; + struct procinfo *pi = (struct procinfo *) + xmalloc (sizeof (struct procinfo)); + struct sig_ctl sctl; + struct flt_ctl fctl; - if (find_procinfo (pid, 1)) - return; /* All done! It already exists */ + memset ((char *) pi, 0, sizeof (*pi)); + if (!open_proc_file (pid, pi, O_RDWR, 1)) + proc_init_failed (pi, "can't open process file", kill); - pi = (struct procinfo *) xmalloc (sizeof (struct procinfo)); + /* open_proc_file may modify pid. */ - if (!open_proc_file (pid, pi, O_RDWR)) - proc_init_failed (pi, "can't open process file"); + pid = pi -> pid; /* Add new process to process info list */ @@ -1452,37 +2129,65 @@ create_procinfo (pid) add_fd (pi); /* Add to list for poll/select */ + /* 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); + prfillset (&fctl.fltset); + prdelset (&fctl.fltset, FLTPAGE); + +#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); prfillset (&pi->prrun.pr_fault); prdelset (&pi->prrun.pr_fault, FLTPAGE); +#ifdef PROCFS_DONT_TRACE_FAULTS + premptyset (&pi->prrun.pr_fault); +#endif +#endif /* UNIXWARE */ - if (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0) - proc_init_failed (pi, "PIOCWSTOP failed"); + if (!procfs_read_status (pi)) + proc_init_failed (pi, "procfs_read_status failed", kill); - if (ioctl (pi->fd, PIOCSFAULT, &pi->prrun.pr_fault) < 0) - proc_init_failed (pi, "PIOCSFAULT failed"); + return pi; } /* LOCAL FUNCTION - procfs_init_inferior - initialize target vector and access to a - /proc entry + create_procinfo - initialize access to a /proc entry SYNOPSIS - void procfs_init_inferior (int pid) + struct procinfo * create_procinfo (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. + 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 @@ -1491,181 +2196,620 @@ NOTES */ -static void -procfs_init_inferior (pid) +static struct procinfo * +create_procinfo (pid) int pid; { - push_target (&procfs_ops); + struct procinfo *pi; + struct sig_ctl sctl; + struct flt_ctl fctl; - create_procinfo (pid); - add_thread (pid); /* Setup initial thread */ + pi = find_procinfo (pid, 1); + if (pi != NULL) + return pi; /* All done! It already exists */ - /* One trap to exec the shell, one to exec the program being debugged. */ - startup_inferior (2); + 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", 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", 1); +#else + if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->prrun.pr_fault) < 0) + proc_init_failed (pi, "PIOCSFAULT failed", 1); +#endif + + return pi; } /* -GLOBAL FUNCTION +LOCAL FUNCTION - procfs_notice_signals + procfs_exit_handler - handle entry into the _exit syscall SYNOPSIS - static void procfs_notice_signals (int pid); + int procfs_exit_handler (pi, syscall_num, why, rtnvalp, statvalp) DESCRIPTION - When the user changes the state of gdb's signal handling via the - "handle" command, this function gets called to see if any change - in the /proc interface is required. It is also called internally - by other /proc interface functions to initialize the state of - the traced signal set. + This routine is called when an inferior process enters the _exit() + system call. It continues the process, and then collects the exit + status and pid which are returned in *statvalp and *rtnvalp. After + that it returns non-zero to indicate that procfs_wait should wake up. + +NOTES + There is probably a better way to do this. - One thing it does is that signals for which the state is "nostop", - "noprint", and "pass", have their trace bits reset in the pr_trace - field, so that they are no longer traced. This allows them to be - delivered directly to the inferior without the debugger ever being - involved. */ -static void -procfs_notice_signals (pid) - int pid; +static int +procfs_exit_handler (pi, syscall_num, why, rtnvalp, statvalp) + struct procinfo *pi; + int syscall_num; + int why; + int *rtnvalp; + int *statvalp; { - int signo; - struct procinfo *pi; + struct procinfo *temp_pi, *next_pi; + struct proc_ctl pctl; - pi = find_procinfo (pid, 0); +#ifdef UNIXWARE + pctl.cmd = PCRUN; + pctl.data = PRCFAULT; +#else + pi->prrun.pr_flags = PRCFAULT; +#endif - for (signo = 0; signo < NSIG; signo++) +#ifdef PROCFS_USE_READ_WRITE + if (write (pi->ctl_fd, (char *)&pctl, sizeof (struct proc_ctl)) < 0) +#else + if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0) +#endif + perror_with_name (pi->pathname); + + if (attach_flag) { - if (signal_stop_state (target_signal_from_host (signo)) == 0 && - signal_print_state (target_signal_from_host (signo)) == 0 && - signal_pass_state (target_signal_from_host (signo)) == 1) - { - prdelset (&pi->prrun.pr_trace, signo); - } - else - { - praddset (&pi->prrun.pr_trace, signo); - } + /* Claim it exited (don't call wait). */ + if (info_verbose) + printf_filtered ("(attached process has exited)\n"); + *statvalp = 0; + *rtnvalp = inferior_pid; } - if (ioctl (pi->fd, PIOCSTRACE, &pi->prrun.pr_trace)) + else { - print_sys_errmsg ("PIOCSTRACE failed", errno); + *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; } /* LOCAL FUNCTION - proc_set_exec_trap -- arrange for exec'd child to halt at startup + procfs_exec_handler - handle exit from the exec family of syscalls SYNOPSIS - void proc_set_exec_trap (void) + int procfs_exec_handler (pi, syscall_num, why, rtnvalp, statvalp) DESCRIPTION - This function is called in the child process when starting up - an inferior, prior to doing the exec of the actual inferior. - It sets the child process's exitset to make exit from the exec - system call an event of interest to stop on, and then simply - returns. The child does the exec, the system call returns, and - the child stops at the first instruction, ready for the gdb - parent process to take control of it. - -NOTE + This routine is called when an inferior process is about to finish any + of the exec() family of system calls. It pretends that we got a + SIGTRAP (for compatibility with ptrace behavior), and returns non-zero + to tell procfs_wait to wake up. - We need to use all local variables since the child may be sharing - it's data space with the parent, if vfork was used rather than - fork. +NOTES + This need for compatibility with ptrace is questionable. In the + future, it shouldn't be necessary. - Also note that we want to turn off the inherit-on-fork flag in - the child process so that any grand-children start with all - tracing flags cleared. */ -static void -proc_set_exec_trap () +static int +procfs_exec_handler (pi, syscall_num, why, rtnvalp, statvalp) + struct procinfo *pi; + int syscall_num; + int why; + int *rtnvalp; + int *statvalp; { - sysset_t exitset; - sysset_t entryset; - auto char procname[32]; - int fd; - - sprintf (procname, PROC_NAME_FMT, getpid ()); - if ((fd = open (procname, O_RDWR)) < 0) - { - perror (procname); - gdb_flush (gdb_stderr); - _exit (127); - } - premptyset (&exitset); - premptyset (&entryset); + *statvalp = (SIGTRAP << 8) | 0177; - /* GW: Rationale... - Not all systems with /proc have all the exec* syscalls with the same - names. On the SGI, for example, there is no SYS_exec, but there - *is* a SYS_execv. So, we try to account for that. */ + return 1; +} -#ifdef SYS_exec - praddset (&exitset, SYS_exec); -#endif -#ifdef SYS_execve - praddset (&exitset, SYS_execve); -#endif -#ifdef SYS_execv - praddset (&exitset, SYS_execv); -#endif +#if defined(SYS_sproc) && !defined(UNIXWARE) +/* IRIX lwp creation system call */ - if (ioctl (fd, PIOCSEXIT, &exitset) < 0) - { - perror (procname); - gdb_flush (gdb_stderr); - _exit (127); - } +/* - praddset (&entryset, SYS_exit); +LOCAL FUNCTION - if (ioctl (fd, PIOCSENTRY, &entryset) < 0) - { - perror (procname); - gdb_flush (gdb_stderr); - _exit (126); + procfs_sproc_handler - handle exit from the sproc syscall + +SYNOPSIS + + int procfs_sproc_handler (pi, syscall_num, why, rtnvalp, statvalp) + +DESCRIPTION + + This routine is called when an inferior process is about to finish an + sproc() system call. This is the system call that IRIX uses to create + a lightweight process. When the target process gets this event, we can + look at rval1 to find the new child processes ID, and create a new + procinfo struct from that. + + After that, it pretends that we got a SIGTRAP, and returns non-zero + to tell procfs_wait to wake up. Subsequently, wait_for_inferior gets + woken up, sees the new process and continues it. + +NOTES + We actually never see the child exiting from sproc because we will + shortly stop the child with PIOCSTOP, which is then registered as the + event of interest. + */ + +static int +procfs_sproc_handler (pi, syscall_num, why, rtnvalp, statvalp) + struct procinfo *pi; + int syscall_num; + int why; + int *rtnvalp; + int *statvalp; +{ +/* We've just detected the completion of an sproc system call. Now we need to + setup a procinfo struct for this thread, and notify the thread system of the + new arrival. */ + +/* If sproc failed, then nothing interesting happened. Continue the process + and go back to sleep. */ + + if (pi->prstatus.pr_errno != 0) + { + 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 0; } - /* Turn off inherit-on-fork flag so that all grand-children of gdb - start with tracing flags cleared. */ + /* At this point, the new thread is stopped at it's first instruction, and + the parent is stopped at the exit from sproc. */ + + /* Notify the caller of the arrival of a new thread. */ + create_procinfo (pi->prstatus.pr_rval1); + + *rtnvalp = pi->prstatus.pr_rval1; + *statvalp = (SIGTRAP << 8) | 0177; + + return 1; +} + +/* + +LOCAL FUNCTION + + procfs_fork_handler - handle exit from the fork syscall + +SYNOPSIS + + int procfs_fork_handler (pi, syscall_num, why, rtnvalp, statvalp) + +DESCRIPTION + + This routine is called when an inferior process is about to finish a + fork() system call. We will open up the new process, and then close + it, which releases it from the clutches of the debugger. + + After that, we continue the target process as though nothing had + happened. + +NOTES + This is necessary for IRIX because we have to set PR_FORK in order + to catch the creation of lwps (via sproc()). When an actual fork + occurs, it becomes necessary to reset the forks debugger flags and + continue it because we can't hack multiple processes yet. + */ + +static int +procfs_fork_handler (pi, syscall_num, why, rtnvalp, statvalp) + struct procinfo *pi; + int syscall_num; + int why; + int *rtnvalp; + int *statvalp; +{ + struct procinfo *pitemp; + +/* At this point, we've detected the completion of a fork (or vfork) call in + our child. The grandchild is also stopped because we set inherit-on-fork + earlier. (Note that nobody has the grandchilds' /proc file open at this + point.) We will release the grandchild from the debugger by opening it's + /proc file and then closing it. Since run-on-last-close is set, the + grandchild continues on its' merry way. */ + + + pitemp = create_procinfo (pi->prstatus.pr_rval1); + if (pitemp) + close_proc_file (pitemp); + + if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0) + perror_with_name (pi->pathname); + + return 0; +} +#endif /* SYS_sproc && !UNIXWARE */ + +/* + +LOCAL FUNCTION + + procfs_set_inferior_syscall_traps - setup the syscall traps + +SYNOPSIS + + void procfs_set_inferior_syscall_traps (struct procinfo *pip) + +DESCRIPTION + + 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 void +procfs_set_inferior_syscall_traps (pip) + struct procinfo *pip; +{ + procfs_set_syscall_trap (pip, SYS_exit, PROCFS_SYSCALL_ENTRY, + procfs_exit_handler); + +#ifndef PRFS_STOPEXEC +#ifdef SYS_exec + procfs_set_syscall_trap (pip, SYS_exec, PROCFS_SYSCALL_EXIT, + procfs_exec_handler); +#endif +#ifdef SYS_execv + procfs_set_syscall_trap (pip, SYS_execv, PROCFS_SYSCALL_EXIT, + procfs_exec_handler); +#endif +#ifdef SYS_execve + procfs_set_syscall_trap (pip, SYS_execve, PROCFS_SYSCALL_EXIT, + procfs_exec_handler); +#endif +#endif /* PRFS_STOPEXEC */ + + /* Setup traps on exit from sproc() */ + +#ifdef SYS_sproc + procfs_set_syscall_trap (pip, SYS_sproc, PROCFS_SYSCALL_EXIT, + procfs_sproc_handler); + procfs_set_syscall_trap (pip, SYS_fork, PROCFS_SYSCALL_EXIT, + procfs_fork_handler); +#ifdef SYS_vfork + procfs_set_syscall_trap (pip, SYS_vfork, PROCFS_SYSCALL_EXIT, + procfs_fork_handler); +#endif +/* Turn on inherit-on-fork flag so that all children of the target process + start with tracing flags set. This allows us to trap lwp creation. Note + that we also have to trap on fork and vfork in order to disable all tracing + in the targets child processes. */ + + modify_inherit_on_fork_flag (pip->ctl_fd, 1); +#endif + +#ifdef SYS_lwp_create + 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 + + void 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 void +procfs_init_inferior (pid) + int pid; +{ + struct procinfo *pip; + + push_target (&procfs_ops); + + pip = create_procinfo (pid); -#if defined (PIOCRESET) /* New method */ + 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. */ + + pid = pip -> pid; + inferior_pid = pid; + + add_thread (pip -> pid); /* Setup initial thread */ + +#ifdef START_INFERIOR_TRAPS_EXPECTED + startup_inferior (START_INFERIOR_TRAPS_EXPECTED); +#else + /* One trap to exec the shell, one to exec the program being debugged. */ + startup_inferior (2); +#endif +} + +/* + +GLOBAL FUNCTION + + procfs_notice_signals + +SYNOPSIS + + static void procfs_notice_signals (int pid); + +DESCRIPTION + + When the user changes the state of gdb's signal handling via the + "handle" command, this function gets called to see if any change + in the /proc interface is required. It is also called internally + by other /proc interface functions to initialize the state of + the traced signal set. + + One thing it does is that signals for which the state is "nostop", + "noprint", and "pass", have their trace bits reset in the pr_trace + field, so that they are no longer traced. This allows them to be + delivered directly to the inferior without the debugger ever being + involved. + */ + +static void +procfs_notice_signals (pid) + int pid; +{ + struct procinfo *pi; + struct sig_ctl sctl; + + pi = find_procinfo (pid, 0); + +#ifndef HAVE_PRRUN_T + premptyset (&sctl.sigset); +#else + sctl.sigset = pi->prrun.pr_trace; +#endif + + notice_signals (pi, &sctl); + +#ifdef HAVE_PRRUN_T + pi->prrun.pr_trace = sctl.sigset; +#endif +} + +static void +notice_signals (pi, sctl) + struct procinfo *pi; + struct sig_ctl *sctl; +{ + int signo; + + for (signo = 0; signo < NSIG; signo++) + { + if (signal_stop_state (target_signal_from_host (signo)) == 0 && + signal_print_state (target_signal_from_host (signo)) == 0 && + signal_pass_state (target_signal_from_host (signo)) == 1) + { + prdelset (&sctl->sigset, signo); + } + else + { + praddset (&sctl->sigset, signo); + } + } +#ifdef PROCFS_USE_READ_WRITE + sctl->cmd = PCSTRACE; + if (write (pi->ctl_fd, (char *) sctl, sizeof (struct sig_ctl)) < 0) +#else + if (ioctl (pi->ctl_fd, PIOCSTRACE, &sctl->sigset)) +#endif + { + print_sys_errmsg ("PIOCSTRACE failed", errno); + } +} + +/* + +LOCAL FUNCTION + + proc_set_exec_trap -- arrange for exec'd child to halt at startup + +SYNOPSIS + + void proc_set_exec_trap (void) + +DESCRIPTION + + This function is called in the child process when starting up + an inferior, prior to doing the exec of the actual inferior. + It sets the child process's exitset to make exit from the exec + system call an event of interest to stop on, and then simply + returns. The child does the exec, the system call returns, and + the child stops at the first instruction, ready for the gdb + parent process to take control of it. + +NOTE + + We need to use all local variables since the child may be sharing + it's data space with the parent, if vfork was used rather than + fork. + + Also note that we want to turn off the inherit-on-fork flag in + the child process so that any grand-children start with all + tracing flags cleared. + */ + +static void +proc_set_exec_trap () +{ + struct sys_ctl exitset; + struct sys_ctl entryset; + char procname[MAX_PROC_NAME_SIZE]; + int fd; + + sprintf (procname, CTL_PROC_NAME_FMT, getpid ()); +#ifdef UNIXWARE + if ((fd = open (procname, O_WRONLY)) < 0) +#else + if ((fd = open (procname, O_RDWR)) < 0) +#endif + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (127); + } + premptyset (&exitset.sysset); + premptyset (&entryset.sysset); + +#ifdef PRFS_STOPEXEC + /* Under Alpha OSF/1 we have to use a PIOCSSPCACT ioctl to trace + exits from exec system calls because of the user level loader. */ { - long pr_flags; - pr_flags = PR_FORK; - ioctl (fd, PIOCRESET, &pr_flags); + int prfs_flags; + + if (ioctl (fd, PIOCGSPCACT, &prfs_flags) < 0) + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (127); + } + prfs_flags |= PRFS_STOPEXEC; + if (ioctl (fd, PIOCSSPCACT, &prfs_flags) < 0) + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (127); + } } +#else /* PRFS_STOPEXEC */ + /* GW: Rationale... + Not all systems with /proc have all the exec* syscalls with the same + names. On the SGI, for example, there is no SYS_exec, but there + *is* a SYS_execv. So, we try to account for that. */ + +#ifdef SYS_exec + praddset (&exitset.sysset, SYS_exec); +#endif +#ifdef SYS_execve + praddset (&exitset.sysset, SYS_execve); +#endif +#ifdef SYS_execv + praddset (&exitset.sysset, SYS_execv); +#endif + +#ifdef PROCFS_USE_READ_WRITE + exitset.cmd = PCSEXIT; + if (write (fd, (char *) &exitset, sizeof (struct sys_ctl)) < 0) #else -#if defined (PIOCRFORK) /* Original method */ - ioctl (fd, PIOCRFORK, NULL); + if (ioctl (fd, PIOCSEXIT, &exitset.sysset) < 0) #endif + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (127); + } +#endif /* PRFS_STOPEXEC */ + + praddset (&entryset.sysset, SYS_exit); + +#ifdef PROCFS_USE_READ_WRITE + entryset.cmd = PCSENTRY; + if (write (fd, (char *) &entryset, sizeof (struct sys_ctl)) < 0) +#else + if (ioctl (fd, PIOCSENTRY, &entryset.sysset) < 0) #endif + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (126); + } + + /* Turn off inherit-on-fork flag so that all grand-children of gdb + start with tracing flags cleared. */ + + modify_inherit_on_fork_flag (fd, 0); /* Turn on run-on-last-close flag so that this process will not hang if GDB goes away for some reason. */ -#if defined (PIOCSET) /* New method */ + modify_run_on_last_close_flag (fd, 1); + +#ifndef UNIXWARE /* since this is a solaris-ism, we don't want it */ + /* NOTE: revisit when doing thread support for UW */ +#ifdef PR_ASYNC { - long pr_flags; - pr_flags = PR_RLC; - (void) ioctl (fd, PIOCSET, &pr_flags); - } + long pr_flags; + struct proc_ctl pctl; + +/* Solaris needs this to make procfs treat all threads seperately. Without + this, all threads halt whenever something happens to any thread. Since + GDB wants to control all this itself, it needs to set PR_ASYNC. */ + + pr_flags = PR_ASYNC; +#ifdef PROCFS_USE_READ_WRITE + pctl.cmd = PCSET; + pctl.data = PR_FORK|PR_ASYNC; + write (fd, (char *) &pctl, sizeof (struct proc_ctl)); #else -#if defined (PIOCSRLC) /* Original method */ - (void) ioctl (fd, PIOCSRLC, 0); -#endif + ioctl (fd, PIOCSET, &pr_flags); #endif + } +#endif /* PR_ASYNC */ +#endif /* !UNIXWARE */ } /* @@ -1687,6 +2831,48 @@ DESCRIPTION the end of the mappings or the function returns nonzero. */ +#ifdef UNIXWARE +int +proc_iterate_over_mappings (func) + int (*func) PARAMS ((int, CORE_ADDR)); +{ + int nmap; + int fd; + int funcstat = 0; + prmap_t *prmaps; + prmap_t *prmap; + struct procinfo *pi; + struct stat sbuf; + + pi = current_procinfo; + + if (fstat (pi->map_fd, &sbuf) < 0) + return 0; + + nmap = sbuf.st_size / sizeof (prmap_t); + prmaps = (prmap_t *) alloca (nmap * sizeof(prmap_t)); + if ((lseek (pi->map_fd, 0, SEEK_SET) == 0) && + (read (pi->map_fd, (char *) prmaps, nmap * sizeof (prmap_t)) == + (nmap * sizeof (prmap_t)))) + { + int i = 0; + for (prmap = prmaps; i < nmap && funcstat == 0; ++prmap, ++i) + { + char name[sizeof ("/proc/1234567890/object") + + sizeof (prmap->pr_mapname)]; + sprintf (name, "/proc/%d/object/%s", pi->pid, prmap->pr_mapname); + if ((fd = open (name, O_RDONLY)) == -1) + { + funcstat = 1; + break; + } + funcstat = (*func) (fd, (CORE_ADDR) prmap->pr_vaddr); + close (fd); + } + } + return (funcstat); +} +#else /* UNIXWARE */ int proc_iterate_over_mappings (func) int (*func) PARAMS ((int, CORE_ADDR)); @@ -1700,10 +2886,10 @@ proc_iterate_over_mappings (func) pi = current_procinfo; - if (ioctl (pi->fd, PIOCNMAP, &nmap) == 0) + if (ioctl (pi->map_fd, PIOCNMAP, &nmap) == 0) { prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps)); - if (ioctl (pi->fd, PIOCMAP, prmaps) == 0) + if (ioctl (pi->map_fd, PIOCMAP, prmaps) == 0) { for (prmap = prmaps; prmap -> pr_size && funcstat == 0; ++prmap) { @@ -1715,6 +2901,7 @@ proc_iterate_over_mappings (func) } return (funcstat); } +#endif /* UNIXWARE */ #if 0 /* Currently unused */ /* @@ -1750,10 +2937,10 @@ proc_base_address (addr) pi = current_procinfo; - if (ioctl (pi->fd, PIOCNMAP, &nmap) == 0) + if (ioctl (pi->map_fd, PIOCNMAP, &nmap) == 0) { prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps)); - if (ioctl (pi->fd, PIOCMAP, prmaps) == 0) + if (ioctl (pi->map_fd, PIOCMAP, prmaps) == 0) { for (prmap = prmaps; prmap -> pr_size; ++prmap) { @@ -1771,6 +2958,7 @@ proc_base_address (addr) #endif /* 0 */ +#ifndef UNIXWARE /* LOCAL FUNCTION @@ -1799,7 +2987,7 @@ proc_address_to_fd (pi, addr, complain) { int fd = -1; - if ((fd = ioctl (pi->fd, PIOCOPENM, (caddr_t *) &addr)) < 0) + if ((fd = ioctl (pi->ctl_fd, PIOCOPENM, (caddr_t *) &addr)) < 0) { if (complain) { @@ -1809,7 +2997,7 @@ proc_address_to_fd (pi, addr, complain) } return (fd); } - +#endif /* !UNIXWARE */ /* Attach to process PID, then initialize for debugging it and wait for the trace-trap that results from attaching. */ @@ -1842,8 +3030,7 @@ procfs_attach (args, from_tty) gdb_flush (gdb_stdout); } - do_attach (pid); - inferior_pid = pid; + inferior_pid = pid = do_attach (pid); push_target (&procfs_ops); } @@ -1942,102 +3129,92 @@ static int do_attach (pid) int pid; { - int result; 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)) - { - free (pi); - perror_with_name (pi->pathname); - /* NOTREACHED */ - } - - /* 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 (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0) - { - print_sys_errmsg (pi->pathname, errno); - close_proc_file (pi); - error ("PIOCSTATUS failed"); - } - if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)) + if (ioctl (pi->ctl_fd, PIOCLWPIDS, lwps)) { - pi->was_stopped = 1; + print_sys_errmsg (pi -> pathname, errno); + error ("PIOCLWPIDS failed"); } - else +#else /* PIOCLWPIDS */ + nlwp = 1; + lwps = alloca ((2 * nlwp + 2) * sizeof *lwps); + lwps[0] = 0; +#endif + for (; nlwp > 0; nlwp--, lwps++) { - pi->was_stopped = 0; - if (1 || query ("Process is currently running, stop it? ")) + /* First one has already been created above. */ + if ((pi = find_procinfo ((*lwps << 16) | pid, 1)) == 0) + pi = init_procinfo ((*lwps << 16) | pid, 0); + + if (THE_PR_LWP(pi->prstatus).pr_flags & (PR_STOPPED | PR_ISTOP)) { - /* Make it run again when we close it. */ -#if defined (PIOCSET) /* New method */ - { - long pr_flags; - pr_flags = PR_RLC; - result = ioctl (pi->fd, PIOCSET, &pr_flags); - } + 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) #else -#if defined (PIOCSRLC) /* Original method */ - result = ioctl (pi->fd, PIOCSRLC, 0); + if (ioctl (pi->ctl_fd, PIOCSTOP, &pi->prstatus) < 0) #endif + { + 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"); + } #endif - if (result < 0) - { - print_sys_errmsg (pi->pathname, errno); - close_proc_file (pi); - error ("PIOCSRLC or PIOCSET failed"); + pi->nopass_next_sigstop = 1; } - if (ioctl (pi->fd, PIOCSTOP, &pi->prstatus) < 0) + else { - print_sys_errmsg (pi->pathname, errno); - close_proc_file (pi); - error ("PIOCSTOP failed"); + printf_unfiltered ("Ok, gdb will wait for %s to stop.\n", + target_pid_to_str (pi->pid)); } - pi->nopass_next_sigstop = 1; } - else + +#ifdef PROCFS_USE_READ_WRITE + 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 */ + if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->prrun.pr_fault)) { - printf_unfiltered ("Ok, gdb will wait for %s to stop.\n", target_pid_to_str (pid)); + print_sys_errmsg ("PIOCSFAULT failed", errno); } - } - - /* Remember some things about the inferior that we will, or might, change - so that we can restore them when we detach. */ - - ioctl (pi->fd, PIOCGTRACE, &pi->saved_trace); - ioctl (pi->fd, PIOCGHOLD, &pi->saved_sighold); - ioctl (pi->fd, PIOCGFAULT, &pi->saved_fltset); - ioctl (pi->fd, PIOCGENTRY, &pi->saved_entryset); - ioctl (pi->fd, PIOCGEXIT, &pi->saved_exitset); - - /* 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); - if (ioctl (pi->fd, PIOCSFAULT, &pi->prrun.pr_fault)) - { - print_sys_errmsg ("PIOCSFAULT failed", errno); - } - if (ioctl (pi->fd, PIOCSTRACE, &pi->prrun.pr_trace)) - { - print_sys_errmsg ("PIOCSTRACE 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); } /* @@ -2073,80 +3250,106 @@ static void do_detach (signal) int signal; { - int result; struct procinfo *pi; - pi = current_procinfo; - - if (signal) - { - set_proc_siginfo (pi, signal); - } - if (ioctl (pi->fd, PIOCSEXIT, &pi->saved_exitset) < 0) - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSEXIT failed.\n"); - } - if (ioctl (pi->fd, PIOCSENTRY, &pi->saved_entryset) < 0) - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSENTRY failed.\n"); - } - if (ioctl (pi->fd, PIOCSTRACE, &pi->saved_trace) < 0) - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSTRACE failed.\n"); - } - if (ioctl (pi->fd, PIOCSHOLD, &pi->saved_sighold) < 0) - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOSCHOLD failed.\n"); - } - if (ioctl (pi->fd, PIOCSFAULT, &pi->saved_fltset) < 0) - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSFAULT failed.\n"); - } - if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0) - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSTATUS failed.\n"); - } - else + for (pi = procinfo_list; pi; pi = pi->next) { - if (signal || (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))) + if (signal) { - if (signal || !pi->was_stopped || - query ("Was stopped when attached, make it runnable again? ")) - { - /* Clear any fault that might have stopped it. */ - if (ioctl (pi->fd, PIOCCFAULT, 0)) - { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCCFAULT failed.\n"); - } - - /* Make it run again when we close it. */ -#if defined (PIOCSET) /* New method */ - { - long pr_flags; - pr_flags = PR_RLC; - result = ioctl (pi->fd, PIOCSET, &pr_flags); - } + 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) +#else + if (ioctl (pi->ctl_fd, PIOCSEXIT, &pi->saved_exitset.sysset) < 0) +#endif + { + 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) #else -#if defined (PIOCSRLC) /* Original method */ - result = ioctl (pi->fd, PIOCSRLC, 0); + if (ioctl (pi->ctl_fd, PIOCSENTRY, &pi->saved_entryset.sysset) < 0) #endif + { + 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) +#else + if (ioctl (pi->ctl_fd, PIOCSTRACE, &pi->saved_trace.sigset) < 0) +#endif + { + 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"); + } #endif - if (result) +#ifdef PROCFS_USE_READ_WRITE + 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) +#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 + { + if (signal + || (THE_PR_LWP(pi->prstatus).pr_flags & (PR_STOPPED | PR_ISTOP))) + { + long cmd; + struct proc_ctl pctl; + + if (signal || !pi->was_stopped || + query ("Was stopped when attached, make it runnable again? ")) { - print_sys_errmsg (pi->pathname, errno); - printf_unfiltered ("PIOCSRLC or PIOCSET failed.\n"); + /* 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) +#else + if (ioctl (pi->ctl_fd, PIOCCFAULT, 0)) +#endif + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCCFAULT failed.\n"); + } + + /* Make it run again when we close it. */ + + modify_run_on_last_close_flag (pi->ctl_fd, 1); } } } + close_proc_file (pi); } - close_proc_file (pi); attach_flag = 0; } @@ -2174,7 +3377,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; @@ -2186,43 +3388,80 @@ procfs_wait (pid, ourstatus) int checkerr = 0; int rtnval = -1; struct procinfo *pi; + struct proc_ctl pctl; - if (pid != -1) /* Non-specific process? */ - pi = NULL; - else - for (pi = procinfo_list; pi; pi = pi->next) - if (pi->had_event) - break; +scan_again: -wait_again: + /* handle all syscall events first, otherwise we might not + notice a thread was created until too late. */ - if (!pi) - pi = wait_fd (); + for (pi = procinfo_list; pi; pi = pi->next) + { + if (!pi->had_event) + continue; - if (pid != -1) - for (pi = procinfo_list; pi; pi = pi->next) - if (pi->pid == pid && pi->had_event) - break; + if (! (THE_PR_LWP(pi->prstatus).pr_flags & (PR_STOPPED | PR_ISTOP)) ) + continue; + + why = THE_PR_LWP(pi->prstatus).pr_why; + what = THE_PR_LWP(pi->prstatus).pr_what; + if (why == PR_SYSENTRY || why == PR_SYSEXIT) + { + int i; + int found_handler = 0; - if (!pi && !checkerr) - goto wait_again; + for (i = 0; i < pi->num_syscall_handlers; i++) + if (pi->syscall_handlers[i].syscall_num == what) + { + found_handler = 1; + pi->saved_rtnval = pi->pid; + pi->saved_statval = 0; + if (!pi->syscall_handlers[i].func + (pi, what, why, &pi->saved_rtnval, &pi->saved_statval)) + pi->had_event = 0; + break; + } + + if (!found_handler) + { + if (why == PR_SYSENTRY) + error ("PR_SYSENTRY, unhandled system call %d", what); + else + error ("PR_SYSEXIT, unhandled system call %d", what); + } + } + } - if (!checkerr && !(pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))) + /* find a relevant process with an event */ + + for (pi = procinfo_list; pi; pi = pi->next) + if (pi->had_event && (pid == -1 || pi->pid == pid)) + break; + + if (!pi) { - if (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0) + wait_fd (); + goto scan_again; + } + + if (!checkerr + && !(THE_PR_LWP(pi->prstatus).pr_flags & (PR_STOPPED | PR_ISTOP))) + { + if (!procfs_write_pcwstop (pi)) { 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) != (PIDGET (inferior_pid))) { print_sys_errmsg (pi->pathname, errno); - error ("PIOCWSTOP, wait failed, returned %d", rtnval); + error ("procfs_wait: wait failed, returned %d", rtnval); /* NOTREACHED */ } } @@ -2233,78 +3472,25 @@ wait_again: /* NOTREACHED */ } } - else if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)) + else if (THE_PR_LWP(pi->prstatus).pr_flags & (PR_STOPPED | PR_ISTOP)) { +#ifdef UNIXWARE rtnval = pi->prstatus.pr_pid; - why = pi->prstatus.pr_why; - what = pi->prstatus.pr_what; - - switch (why) - { - case PR_SIGNALLED: - statval = (what << 8) | 0177; - break; - case PR_SYSENTRY: - if (what != SYS_exit) - error ("PR_SYSENTRY, unknown system call %d", what); - - pi->prrun.pr_flags = PRCFAULT; - - if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0) - perror_with_name (pi->pathname); - - rtnval = wait (&statval); - - break; - case PR_SYSEXIT: - switch (what) - { -#ifdef SYS_exec - case SYS_exec: -#endif -#ifdef SYS_execve - case SYS_execve: -#endif -#ifdef SYS_execv - case SYS_execv: +#else + rtnval = pi->pid; #endif - statval = (SIGTRAP << 8) | 0177; - break; -#ifdef SYS_sproc - case SYS_sproc: -/* We've just detected the completion of an sproc system call. Now we need to - setup a procinfo struct for this thread, and notify the thread system of the - new arrival. */ + why = THE_PR_LWP(pi->prstatus).pr_why; + what = THE_PR_LWP(pi->prstatus).pr_what; -/* If sproc failed, then nothing interesting happened. Continue the process and - go back to sleep. */ - - if (pi->prstatus.pr_errno != 0) - { - pi->prrun.pr_flags &= PRSTEP; - pi->prrun.pr_flags |= PRCFAULT; - - if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0) - perror_with_name (pi->pathname); - - goto wait_again; - } - -/* At this point, the new thread is stopped at it's first instruction, and - the parent is stopped at the exit from sproc. */ - -/* Notify the caller of the arrival of a new thread. */ - create_procinfo (pi->prstatus.pr_rval1); - - rtnval = pi->prstatus.pr_rval1; - statval = (SIGTRAP << 8) | 0177; - - break; -#endif /* SYS_sproc */ - - default: - error ("PIOCSTATUS (PR_SYSEXIT): Unknown system call %d", what); - } + switch (why) + { + case PR_SIGNALLED: + statval = (what << 8) | 0177; + break; + case PR_SYSENTRY: + case PR_SYSEXIT: + rtnval = pi->saved_rtnval; + statval = pi->saved_statval; break; case PR_REQUESTED: statval = (SIGSTOP << 8) | 0177; @@ -2315,14 +3501,6 @@ wait_again: case PR_FAULTED: switch (what) { - case FLTPRIV: - case FLTILL: - statval = (SIGILL << 8) | 0177; - break; - case FLTBPT: - case FLTTRACE: - statval = (SIGTRAP << 8) | 0177; - break; #ifdef FLTWATCH case FLTWATCH: statval = (SIGTRAP << 8) | 0177; @@ -2333,6 +3511,17 @@ wait_again: statval = (SIGTRAP << 8) | 0177; break; #endif +#ifndef FAULTED_USE_SIGINFO + /* Irix, contrary to the documentation, fills in 0 for si_signo. + Solaris fills in si_signo. I'm not sure about others. */ + case FLTPRIV: + case FLTILL: + statval = (SIGILL << 8) | 0177; + break; + case FLTBPT: + case FLTTRACE: + statval = (SIGTRAP << 8) | 0177; + break; case FLTSTACK: case FLTACCESS: case FLTBOUNDS: @@ -2344,40 +3533,73 @@ wait_again: statval = (SIGFPE << 8) | 0177; break; case FLTPAGE: /* Recoverable page fault */ +#endif /* not FAULTED_USE_SIGINFO */ default: - error ("PIOCWSTOP, unknown why %d, what %d", why, what); + /* Use the signal which the kernel assigns. This is better than + trying to second-guess it from the fault. In fact, I suspect + that FLTACCESS can be either SIGSEGV or SIGBUS. */ + statval = + ((THE_PR_LWP(pi->prstatus).pr_info.si_signo) << 8) | 0177; + break; } break; default: error ("PIOCWSTOP, unknown why %d, what %d", why, what); } -/* Stop all the other threads when any of them stops. */ + /* 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) - if (ioctl (procinfo->fd, PIOCSTOP, &procinfo->prstatus) < 0) - { - print_sys_errmsg (procinfo->pathname, errno); - error ("PIOCSTOP failed"); - } + { +#ifdef PROCFS_USE_READ_WRITE + long cmd = PCSTOP; + if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0) + { + print_sys_errmsg (procinfo->pathname, errno); + error ("PCSTOP failed"); + } +#else + /* A bug in Solaris (2.5) causes us to hang when trying to + stop a stopped process. So, we have to check first in + order to avoid the hang. */ + 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; + } + + if (!(procinfo->prstatus.pr_flags & PR_STOPPED)) + if (ioctl (procinfo->ctl_fd, PIOCSTOP, &procinfo->prstatus) + < 0) + { + print_sys_errmsg (procinfo->pathname, errno); + warning ("PIOCSTOP failed"); + } +#endif + } } } } else { - error ("PIOCWSTOP, stopped for unknown/unhandled reason, flags %#x", - pi->prstatus.pr_flags); + error ("PIOCWSTOP, stopped for unknown/unhandled reason, flags %#x", + THE_PR_LWP(pi->prstatus).pr_flags); } store_waitstatus (ourstatus, statval); 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; @@ -2409,7 +3631,7 @@ DESCRIPTION If we are not delivering the same signal that the prstatus siginfo struct contains information about, then synthesize a siginfo struct - to match the signal we are doing to deliver, make it of the type + to match the signal we are going to deliver, make it of the type "generated by a user process", and send this synthesized copy. When used to set the inferior's signal state, this will be required if we are not currently stopped because of a traced signal, or if we decide @@ -2433,22 +3655,49 @@ set_proc_siginfo (pip, signo) { struct siginfo newsiginfo; struct siginfo *sip; + struct sigi_ctl sictl; + +#ifdef PROCFS_DONT_PIOCSSIG_CURSIG + /* With Alpha OSF/1 procfs, the kernel gets really confused if it + receives a PIOCSSIG with a signal identical to the current signal, + it messes up the current signal. Work around the kernel bug. */ + if (signo == THE_PR_LWP(pip->prstatus).pr_cursig) + return; +#endif - if (signo == pip -> prstatus.pr_info.si_signo) +#ifdef UNIXWARE + if (signo == THE_PR_LWP(pip->prstatus).pr_info.si_signo) + { + memcpy ((char *) &sictl.siginfo, (char *) &pip->prstatus.pr_lwp.pr_info, + sizeof (siginfo_t)); + } +#else + if (signo == THE_PR_LWP(pip->prstatus).pr_info.si_signo) { sip = &pip -> prstatus.pr_info; } +#endif else { +#ifdef UNIXWARE + siginfo_t *sip = &sictl.siginfo; + memset ((char *) sip, 0, sizeof (siginfo_t)); +#else memset ((char *) &newsiginfo, 0, sizeof (newsiginfo)); sip = &newsiginfo; +#endif sip -> si_signo = signo; sip -> si_code = 0; sip -> si_errno = 0; sip -> si_pid = getpid (); sip -> si_uid = getuid (); } - if (ioctl (pip -> fd, PIOCSSIG, sip) < 0) +#ifdef PROCFS_USE_READ_WRITE + sictl.cmd = PCSSIG; + if (write (pip->ctl_fd, (char *) &sictl, sizeof (struct sigi_ctl)) < 0) +#else + if (ioctl (pip->ctl_fd, PIOCSSIG, sip) < 0) +#endif { print_sys_errmsg (pip -> pathname, errno); warning ("PIOCSSIG failed"); @@ -2466,12 +3715,18 @@ 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); errno = 0; +#ifdef UNIXWARE + pctl.cmd = PCRUN; + pctl.data = PRCFAULT; +#else pi->prrun.pr_flags = PRSTRACE | PRSFAULT | PRCFAULT; +#endif #if 0 /* It should not be necessary. If the user explicitly changes the value, @@ -2506,8 +3761,9 @@ procfs_resume (pid, step, signo) an inferior to continue running at the same time as gdb. (FIXME?) */ signal_to_pass = 0; else if (signo == TARGET_SIGNAL_TSTP - && pi->prstatus.pr_cursig == SIGTSTP - && pi->prstatus.pr_action.sa_handler == SIG_DFL) + && THE_PR_LWP(pi->prstatus).pr_cursig == SIGTSTP + && THE_PR_LWP(pi->prstatus).pr_action.sa_handler == SIG_DFL + ) /* We are about to pass the inferior a SIGTSTP whose action is SIG_DFL. The SIG_DFL action for a SIGTSTP is to stop @@ -2533,43 +3789,105 @@ procfs_resume (pid, step, signo) } else { +#ifdef UNIXWARE + pctl.data |= PRCSIG; +#else pi->prrun.pr_flags |= PRCSIG; +#endif } pi->nopass_next_sigstop = 0; if (step) { +#ifdef UNIXWARE + pctl.data |= PRSTEP; +#else pi->prrun.pr_flags |= PRSTEP; +#endif } - if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0) + 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)) { - 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); + } + else + { +#ifdef PROCFS_USE_READ_WRITE + 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) +#endif + { + /* 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) - { - procinfo->prrun.pr_flags &= PRSTEP; - procinfo->prrun.pr_flags |= PRCFAULT | PRCSIG; - ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus); - if (ioctl (procinfo->fd, PIOCRUN, &procinfo->prrun) < 0) - { - if (ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus) < 0) - { - fprintf_unfiltered(gdb_stderr, "PIOCSTATUS failed, errno=%d\n", errno); - } - print_sys_errmsg (procinfo->pathname, errno); - error ("PIOCRUN failed"); - } - ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus); - } + 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"); + } +#else + 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. */ + + 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"); + } +#endif + } + procfs_read_status (procinfo); } } @@ -2599,44 +3917,57 @@ procfs_fetch_registers (regno) pi = current_procinfo; - if (ioctl (pi->fd, PIOCGREG, &pi->gregset) != -1) +#ifdef UNIXWARE + if (procfs_read_status (pi)) + { + supply_gregset (&pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs); +#if defined (FP0_REGNUM) + supply_fpregset (&pi->prstatus.pr_lwp.pr_context.uc_mcontext.fpregs); +#endif + } +#else /* UNIXWARE */ + if (ioctl (pi->ctl_fd, PIOCGREG, &pi->gregset.gregset) != -1) { - supply_gregset (&pi->gregset); + supply_gregset (&pi->gregset.gregset); } #if defined (FP0_REGNUM) - if (ioctl (pi->fd, PIOCGFPREG, &pi->fpregset) != -1) + if (ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset.fpregset) != -1) { - supply_fpregset (&pi->fpregset); + supply_fpregset (&pi->fpregset.fpregset); } #endif +#endif /* UNIXWARE */ } /* 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 */ @@ -2667,9 +3998,15 @@ 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 -> fd); + close (pip->ctl_fd); +#ifdef HAVE_MULTIPLE_PROC_FDS + close (pip->as_fd); + close (pip->status_fd); + close (pip->map_fd); +#endif free (pip -> pathname); @@ -2678,11 +4015,31 @@ close_proc_file (pip) if (procinfo_list == pip) procinfo_list = pip->next; else - for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next) - if (procinfo->next == pip) - procinfo->next = pip->next; + { + for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next) + { + if (procinfo->next == pip) + { + procinfo->next = pip->next; + break; + } + } + free (pip); + } +} + +static void +close_proc_file_cleanup (pip) + void *pip; +{ + close_proc_file ((struct procinfo *) pip); +} - free (pip); +static struct cleanup * +make_cleanup_close_proc_file (pip) + struct procinfo *pip; +{ + return make_cleanup (close_proc_file_cleanup, pip); } /* @@ -2707,23 +4064,118 @@ DESCRIPTION Note that the pathname is left intact, even when the open fails, so that callers can use it to construct meaningful error messages rather than just "file open failed". + + Note that for Solaris, the process-id also includes an LWP-id, so we + actually attempt to open that. If we are handed a pid with a 0 LWP-id, + then we will ask the kernel what it is and add it to the pid. Hence, + the pid can be changed by us. */ static int -open_proc_file (pid, pip, mode) +open_proc_file (pid, pip, mode, control) int pid; struct procinfo *pip; int mode; + int control; { + int tmp, tmpfd; + pip -> next = NULL; pip -> had_event = 0; - pip -> pathname = xmalloc (32); + pip -> pathname = xmalloc (MAX_PROC_NAME_SIZE); pip -> pid = pid; - sprintf (pip -> pathname, PROC_NAME_FMT, pid); - if ((pip -> fd = open (pip -> pathname, mode)) < 0) +#ifndef PIOCOPENLWP + tmp = pid; +#else + tmp = pid & 0xffff; +#endif + +#ifdef HAVE_MULTIPLE_PROC_FDS + sprintf (pip->pathname, STATUS_PROC_NAME_FMT, tmp); + if ((pip->status_fd = open (pip->pathname, O_RDONLY)) < 0) + { + return 0; + } + + sprintf (pip->pathname, AS_PROC_NAME_FMT, tmp); + if ((pip->as_fd = open (pip->pathname, O_RDWR)) < 0) + { + close (pip->status_fd); + return 0; + } + + sprintf (pip->pathname, MAP_PROC_NAME_FMT, tmp); + if ((pip->map_fd = open (pip->pathname, O_RDONLY)) < 0) + { + close (pip->status_fd); + close (pip->as_fd); + return 0; + } + + if (control) + { + sprintf (pip->pathname, CTL_PROC_NAME_FMT, tmp); + if ((pip->ctl_fd = open (pip->pathname, O_WRONLY)) < 0) + { + close (pip->status_fd); + close (pip->as_fd); + close (pip->map_fd); + return 0; + } + } + +#else /* HAVE_MULTIPLE_PROC_FDS */ + sprintf (pip -> pathname, CTL_PROC_NAME_FMT, tmp); + + if ((tmpfd = open (pip -> pathname, mode)) < 0) return 0; +#ifndef PIOCOPENLWP + pip -> ctl_fd = tmpfd; + pip -> as_fd = tmpfd; + pip -> map_fd = tmpfd; + pip -> status_fd = tmpfd; +#else + tmp = (pid >> 16) & 0xffff; /* Extract thread id */ + + if (tmp == 0) + { /* Don't know thread id yet */ + if (ioctl (tmpfd, PIOCSTATUS, &pip -> prstatus) < 0) + { + print_sys_errmsg (pip -> pathname, errno); + close (tmpfd); + error ("open_proc_file: PIOCSTATUS failed"); + } + + tmp = pip -> prstatus.pr_who; /* Get thread id from prstatus_t */ + pip -> pid = (tmp << 16) | pid; /* Update pip */ + } + + if ((pip -> ctl_fd = ioctl (tmpfd, PIOCOPENLWP, &tmp)) < 0) + { + close (tmpfd); + return 0; + } + +#ifdef PIOCSET /* New method */ + { + long pr_flags; + pr_flags = PR_ASYNC; + ioctl (pip -> ctl_fd, PIOCSET, &pr_flags); + } +#endif + + /* keep extra fds in sync */ + pip->as_fd = pip->ctl_fd; + pip->map_fd = pip->ctl_fd; + pip->status_fd = pip->ctl_fd; + + close (tmpfd); /* All done with main pid */ +#endif /* PIOCOPENLWP */ + +#endif /* HAVE_MULTIPLE_PROC_FDS */ + return 1; } @@ -2752,6 +4204,11 @@ info_proc_flags (pip, summary) int summary; { struct trans *transp; +#ifdef UNIXWARE + long flags = pip->prstatus.pr_flags | pip->prstatus.pr_lwp.pr_flags; +#else + long flags = pip->prstatus.pr_flags; +#endif printf_filtered ("%-32s", "Process status flags:"); if (!summary) @@ -2760,7 +4217,7 @@ info_proc_flags (pip, summary) } for (transp = pr_flag_table; transp -> name != NULL; transp++) { - if (pip -> prstatus.pr_flags & transp -> value) + if (flags & transp -> value) { if (summary) { @@ -2784,10 +4241,10 @@ info_proc_stop (pip, summary) int why; int what; - why = pip -> prstatus.pr_why; - what = pip -> prstatus.pr_what; + why = THE_PR_LWP(pip->prstatus).pr_why; + what = THE_PR_LWP(pip->prstatus).pr_what; - if (pip -> prstatus.pr_flags & PR_STOPPED) + if (THE_PR_LWP(pip->prstatus).pr_flags & PR_STOPPED) { printf_filtered ("%-32s", "Reason for stopping:"); if (!summary) @@ -2878,12 +4335,12 @@ info_proc_siginfo (pip, summary) { struct siginfo *sip; - if ((pip -> prstatus.pr_flags & PR_STOPPED) && - (pip -> prstatus.pr_why == PR_SIGNALLED || - pip -> prstatus.pr_why == PR_FAULTED)) + if ((THE_PR_LWP(pip->prstatus).pr_flags & PR_STOPPED) && + (THE_PR_LWP(pip->prstatus).pr_why == PR_SIGNALLED || + THE_PR_LWP(pip->prstatus).pr_why == PR_FAULTED)) { printf_filtered ("%-32s", "Additional signal/fault info:"); - sip = &pip -> prstatus.pr_info; + sip = &(THE_PR_LWP(pip->prstatus).pr_info); if (summary) { printf_filtered ("%s ", signalname (sip -> si_signo)); @@ -2905,7 +4362,8 @@ info_proc_siginfo (pip, summary) (sip -> si_signo == SIGSEGV) || (sip -> si_signo == SIGBUS)) { - printf_filtered ("addr=%#x ", sip -> si_addr); + printf_filtered ("addr=%#lx ", + (unsigned long) sip -> si_addr); } else if ((sip -> si_signo == SIGCHLD)) { @@ -2944,13 +4402,15 @@ info_proc_siginfo (pip, summary) if ((sip -> si_signo == SIGILL) || (sip -> si_signo == SIGFPE)) { - printf_filtered ("\t%-16#x %s.\n", sip -> si_addr, + printf_filtered ("\t%#-16lx %s.\n", + (unsigned long) sip -> si_addr, "Address of faulting instruction"); } else if ((sip -> si_signo == SIGSEGV) || (sip -> si_signo == SIGBUS)) { - printf_filtered ("\t%-16#x %s.\n", sip -> si_addr, + printf_filtered ("\t%#-16lx %s.\n", + (unsigned long) sip -> si_addr, "Address of faulting memory reference"); } else if ((sip -> si_signo == SIGCHLD)) @@ -2998,17 +4458,19 @@ info_proc_syscalls (pip, summary) } #endif - if (ioctl (pip -> fd, PIOCGENTRY, &pip -> entryset) < 0) +#ifndef UNIXWARE + if (ioctl (pip -> ctl_fd, PIOCGENTRY, &pip -> entryset) < 0) { print_sys_errmsg (pip -> pathname, errno); error ("PIOCGENTRY failed"); } - if (ioctl (pip -> fd, PIOCGEXIT, &pip -> exitset) < 0) + if (ioctl (pip -> ctl_fd, PIOCGEXIT, &pip -> exitset) < 0) { print_sys_errmsg (pip -> pathname, errno); error ("PIOCGEXIT failed"); } +#endif printf_filtered ("System call tracing information:\n\n"); @@ -3020,17 +4482,27 @@ info_proc_syscalls (pip, summary) { QUIT; if (syscall_table[syscallnum] != NULL) - { - printf_filtered ("\t%-12s ", syscall_table[syscallnum]); - printf_filtered ("%-8s ", - prismember (&pip -> entryset, syscallnum) - ? "on" : "off"); - printf_filtered ("%-8s ", - prismember (&pip -> exitset, syscallnum) - ? "on" : "off"); - printf_filtered ("\n"); - } - } + printf_filtered ("\t%-12s ", syscall_table[syscallnum]); + else + printf_filtered ("\t%-12d ", syscallnum); + +#ifdef UNIXWARE + printf_filtered ("%-8s ", + prismember (&pip->prstatus.pr_sysentry, syscallnum) + ? "on" : "off"); + printf_filtered ("%-8s ", + prismember (&pip->prstatus.pr_sysexit, syscallnum) + ? "on" : "off"); +#else + printf_filtered ("%-8s ", + prismember (&pip -> entryset, syscallnum) + ? "on" : "off"); + printf_filtered ("%-8s ", + prismember (&pip -> exitset, syscallnum) + ? "on" : "off"); +#endif + printf_filtered ("\n"); + } printf_filtered ("\n"); } } @@ -3039,7 +4511,7 @@ static char * signalname (signo) int signo; { - char *name; + const char *name; static char locbuf[32]; name = strsigno (signo); @@ -3058,7 +4530,7 @@ static char * errnoname (errnum) int errnum; { - char *name; + const char *name; static char locbuf[32]; name = strerrno (errnum); @@ -3082,11 +4554,13 @@ info_proc_signals (pip, summary) if (!summary) { - if (ioctl (pip -> fd, PIOCGTRACE, &pip -> trace) < 0) +#ifndef PROCFS_USE_READ_WRITE + if (ioctl (pip -> ctl_fd, PIOCGTRACE, &pip -> trace) < 0) { print_sys_errmsg (pip -> pathname, errno); error ("PIOCGTRACE failed"); } +#endif printf_filtered ("Disposition of signals:\n\n"); printf_filtered ("\t%-15s %-8s %-8s %-8s %s\n\n", @@ -3095,15 +4569,42 @@ info_proc_signals (pip, summary) { QUIT; printf_filtered ("\t%-15s ", signalname (signo)); +#ifdef UNIXWARE + printf_filtered ("%-8s ", + prismember (&pip -> prstatus.pr_sigtrace, signo) + ? "on" : "off"); + printf_filtered ("%-8s ", + prismember (&pip -> prstatus.pr_lwp.pr_context.uc_sigmask, signo) + ? "on" : "off"); +#else printf_filtered ("%-8s ", prismember (&pip -> trace, signo) ? "on" : "off"); printf_filtered ("%-8s ", prismember (&pip -> prstatus.pr_sighold, signo) ? "on" : "off"); +#endif + +#ifdef UNIXWARE + if (prismember (&pip->prstatus.pr_sigpend, signo) || + prismember (&pip->prstatus.pr_lwp.pr_lwppend, signo)) + printf_filtered("%-8s ", "yes"); + else + printf_filtered("%-8s ", "no"); +#else /* UNIXWARE */ +#ifdef PROCFS_SIGPEND_OFFSET + /* Alpha OSF/1 numbers the pending signals from 1. */ + printf_filtered ("%-8s ", + (signo ? prismember (&pip -> prstatus.pr_sigpend, + signo - 1) + : 0) + ? "yes" : "no"); +#else printf_filtered ("%-8s ", prismember (&pip -> prstatus.pr_sigpend, signo) ? "yes" : "no"); +#endif +#endif /* UNIXWARE */ printf_filtered (" %s\n", safe_strsignal (signo)); } printf_filtered ("\n"); @@ -3119,11 +4620,13 @@ info_proc_faults (pip, summary) if (!summary) { - if (ioctl (pip -> fd, PIOCGFAULT, &pip -> fltset) < 0) +#ifndef UNIXWARE + if (ioctl (pip -> ctl_fd, PIOCGFAULT, &pip->fltset.fltset) < 0) { print_sys_errmsg (pip -> pathname, errno); error ("PIOCGFAULT failed"); } +#endif printf_filtered ("Current traced hardware fault set:\n\n"); printf_filtered ("\t%-12s %-8s\n", "Fault", "Trace"); @@ -3132,8 +4635,13 @@ info_proc_faults (pip, summary) { QUIT; printf_filtered ("\t%-12s ", transp -> name); - printf_filtered ("%-8s", prismember (&pip -> fltset, transp -> value) +#ifdef UNIXWARE + printf_filtered ("%-8s", prismember (&pip->prstatus.pr_flttrace, transp -> value) ? "on" : "off"); +#else + printf_filtered ("%-8s", prismember (&pip->fltset.fltset, transp -> value) + ? "on" : "off"); +#endif printf_filtered ("\n"); } printf_filtered ("\n"); @@ -3148,26 +4656,49 @@ info_proc_mappings (pip, summary) int nmap; struct prmap *prmaps; struct prmap *prmap; + struct stat sbuf; if (!summary) { printf_filtered ("Mapped address spaces:\n\n"); +#ifdef BFD_HOST_64_BIT + printf_filtered (" %18s %18s %10s %10s %7s\n", +#else printf_filtered ("\t%10s %10s %10s %10s %7s\n", +#endif "Start Addr", " End Addr", " Size", " Offset", "Flags"); - if (ioctl (pip -> fd, PIOCNMAP, &nmap) == 0) +#ifdef PROCFS_USE_READ_WRITE + if (fstat (pip->map_fd, &sbuf) == 0) + { + nmap = sbuf.st_size / sizeof (prmap_t); + prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps)); + if ((lseek (pip->map_fd, 0, SEEK_SET) == 0) && + (read (pip->map_fd, (char *) prmaps, + nmap * sizeof (*prmaps)) == (nmap * sizeof (*prmaps)))) + { + int i = 0; + for (prmap = prmaps; i < nmap; ++prmap, ++i) +#else + if (ioctl (pip -> ctl_fd, PIOCNMAP, &nmap) == 0) { prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps)); - if (ioctl (pip -> fd, PIOCMAP, prmaps) == 0) + if (ioctl (pip -> ctl_fd, PIOCMAP, prmaps) == 0) { for (prmap = prmaps; prmap -> pr_size; ++prmap) +#endif /* PROCFS_USE_READ_WRITE */ { - printf_filtered ("\t%#10x %#10x %#10x %#10x %7s\n", - prmap -> pr_vaddr, - prmap -> pr_vaddr + prmap -> pr_size - 1, +#ifdef BFD_HOST_64_BIT + printf_filtered (" %#18lx %#18lx %#10x %#10x %7s\n", +#else + printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n", +#endif + (unsigned long)prmap -> pr_vaddr, + (unsigned long)prmap -> pr_vaddr + + prmap -> pr_size - 1, prmap -> pr_size, prmap -> pr_off, mappingflags (prmap -> pr_mflags)); @@ -3228,13 +4759,18 @@ info_proc (args, from_tty) int id = 0; int status = 0; int all = 0; + int nlwp; + int *lwps; old_chain = make_cleanup (null_cleanup, 0); /* 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) { @@ -3242,7 +4778,7 @@ info_proc (args, from_tty) { nomem (0); } - make_cleanup (freeargv, (char *) argv); + make_cleanup_freeargv (argv); while (*argv != NULL) { @@ -3298,12 +4834,13 @@ info_proc (args, from_tty) memset (pip, 0, sizeof (*pip)); pip->pid = pid; - if (!open_proc_file (pid, pip, O_RDONLY)) + if (!open_proc_file (pid, pip, O_RDONLY, 0)) { perror_with_name (pip -> pathname); /* NOTREACHED */ } - make_cleanup (close_proc_file, pip); + pid = pip->pid; + make_cleanup_close_proc_file (pip); } else if (**argv != '\000') { @@ -3313,118 +4850,609 @@ info_proc (args, from_tty) } } - /* If we don't have a valid open process at this point, then we have no - inferior or didn't specify a specific pid. */ + /* If we don't have a valid open process at this point, then we have no + inferior or didn't specify a specific pid. */ + + if (!pip) + { + error ("\ +No process. Start debugging a program or specify an explicit process ID."); + } + + if (!procfs_read_status (pip)) + { + print_sys_errmsg (pip -> pathname, errno); + error ("procfs_read_status failed"); + } + +#ifndef PROCFS_USE_READ_WRITE +#ifdef PIOCLWPIDS + nlwp = pip->prstatus.pr_nlwp; + lwps = alloca ((2 * nlwp + 2) * sizeof (*lwps)); + + if (ioctl (pip->ctl_fd, PIOCLWPIDS, lwps)) + { + print_sys_errmsg (pip -> pathname, errno); + error ("PIOCLWPIDS failed"); + } +#else /* PIOCLWPIDS */ + nlwp = 1; + lwps = alloca ((2 * nlwp + 2) * sizeof *lwps); + lwps[0] = 0; +#endif /* PIOCLWPIDS */ + + for (; nlwp > 0; nlwp--, lwps++) + { + pip = find_procinfo ((*lwps << 16) | pid, 1); + + if (!pip) + { + pip = (struct procinfo *) xmalloc (sizeof (struct procinfo)); + memset (pip, 0, sizeof (*pip)); + if (!open_proc_file ((*lwps << 16) | pid, pip, O_RDONLY, 0)) + continue; + + make_cleanup_close_proc_file (pip); + + if (!procfs_read_status (pip)) + { + print_sys_errmsg (pip -> pathname, errno); + error ("procfs_read_status failed"); + } + } + +#endif /* PROCFS_USE_READ_WRITE */ + + /* Print verbose information of the requested type(s), or just a summary + of the information for all types. */ + + printf_filtered ("\nInformation for %s.%d:\n\n", pip -> pathname, *lwps); + if (summary || all || flags) + { + info_proc_flags (pip, summary); + } + if (summary || all) + { + info_proc_stop (pip, summary); +#ifdef UNIXWARE + supply_gregset (&pip->prstatus.pr_lwp.pr_context.uc_mcontext.gregs); +#else + supply_gregset (&pip->prstatus.pr_reg); +#endif + printf_filtered ("PC: "); + print_address (read_pc (), gdb_stdout); + printf_filtered ("\n"); + } + if (summary || all || signals || faults) + { + info_proc_siginfo (pip, summary); + } + if (summary || all || syscalls) + { + info_proc_syscalls (pip, summary); + } + if (summary || all || mappings) + { + info_proc_mappings (pip, summary); + } + if (summary || all || signals) + { + info_proc_signals (pip, summary); + } + if (summary || all || faults) + { + info_proc_faults (pip, summary); + } + printf_filtered ("\n"); + + /* All done, deal with closing any temporary process info structure, + freeing temporary memory , etc. */ + + do_cleanups (old_chain); +#ifndef PROCFS_USE_READ_WRITE + } +#endif +} + +/* + +LOCAL FUNCTION + + modify_inherit_on_fork_flag - Change the inherit-on-fork flag + +SYNOPSIS + + void modify_inherit_on_fork_flag (fd, flag) + +DESCRIPTION + + Call this routine to modify the inherit-on-fork flag. This routine is + just a nice wrapper to hide the #ifdefs needed by various systems to + control this flag. + + */ + +static void +modify_inherit_on_fork_flag (fd, flag) + int fd; + int flag; +{ +#if defined (PIOCSET) || defined (PCSET) + long pr_flags; +#endif + int retval = 0; + struct proc_ctl pctl; + +#if defined (PIOCSET) || defined (PCSET) /* New method */ + pr_flags = PR_FORK; + if (flag) + { +#ifdef PROCFS_USE_READ_WRITE + pctl.cmd = PCSET; + pctl.data = PR_FORK; + if (write (fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0) + retval = -1; +#else + retval = ioctl (fd, PIOCSET, &pr_flags); +#endif + } + else + { +#ifdef PROCFS_USE_READ_WRITE + pctl.cmd = PCRESET; + pctl.data = PR_FORK; + if (write (fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0) + retval = -1; +#else + retval = ioctl (fd, PIOCRESET, &pr_flags); +#endif + } - if (!pip) +#else +#ifdef PIOCSFORK /* Original method */ + if (flag) { - error ("\ -No process. Start debugging a program or specify an explicit process ID."); + retval = ioctl (fd, PIOCSFORK, NULL); } - if (ioctl (pip -> fd, PIOCSTATUS, &(pip -> prstatus)) < 0) + else { - print_sys_errmsg (pip -> pathname, errno); - error ("PIOCSTATUS failed"); + retval = ioctl (fd, PIOCRFORK, NULL); } +#else + Neither PR_FORK nor PIOCSFORK exist!!! +#endif +#endif + + if (!retval) + return; + + print_sys_errmsg ("modify_inherit_on_fork_flag", errno); + error ("PIOCSFORK or PR_FORK modification failed"); +} + +/* + +LOCAL FUNCTION + + modify_run_on_last_close_flag - Change the run-on-last-close flag + +SYNOPSIS - /* Print verbose information of the requested type(s), or just a summary - of the information for all types. */ + void modify_run_on_last_close_flag (fd, flag) - printf_filtered ("\nInformation for %s:\n\n", pip -> pathname); - if (summary || all || flags) +DESCRIPTION + + Call this routine to modify the run-on-last-close flag. This routine + is just a nice wrapper to hide the #ifdefs needed by various systems to + control this flag. + + */ + +static void +modify_run_on_last_close_flag (fd, flag) + int fd; + int flag; +{ +#if defined (PIOCSET) || defined (PCSET) + long pr_flags; +#endif + int retval = 0; + struct proc_ctl pctl; + +#if defined (PIOCSET) || defined (PCSET) /* New method */ + pr_flags = PR_RLC; + if (flag) { - info_proc_flags (pip, summary); +#ifdef PROCFS_USE_READ_WRITE + pctl.cmd = PCSET; + pctl.data = PR_RLC; + if (write (fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0) + retval = -1; +#else + retval = ioctl (fd, PIOCSET, &pr_flags); +#endif } - if (summary || all) + else { - info_proc_stop (pip, summary); +#ifdef PROCFS_USE_READ_WRITE + pctl.cmd = PCRESET; + pctl.data = PR_RLC; + if (write (fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0) + retval = -1; +#else + retval = ioctl (fd, PIOCRESET, &pr_flags); +#endif } - if (summary || all || signals || faults) + +#else +#ifdef PIOCSRLC /* Original method */ + if (flag) + retval = ioctl (fd, PIOCSRLC, NULL); + else + retval = ioctl (fd, PIOCRRLC, NULL); +#else + Neither PR_RLC nor PIOCSRLC exist!!! +#endif +#endif + + if (!retval) + return; + + print_sys_errmsg ("modify_run_on_last_close_flag", errno); + error ("PIOCSRLC or PR_RLC modification failed"); +} + +/* + +LOCAL FUNCTION + + procfs_clear_syscall_trap -- Deletes the trap for the specified system call. + +SYNOPSIS + + void procfs_clear_syscall_trap (struct procinfo *, int syscall_num, int errok) + +DESCRIPTION + + This function function disables traps for the specified system call. + errok is non-zero if errors should be ignored. + */ + +static void +procfs_clear_syscall_trap (pi, syscall_num, errok) + struct procinfo *pi; + int syscall_num; + int errok; +{ + sysset_t sysset; + int goterr, i; + +#ifndef UNIXWARE + goterr = ioctl (pi->ctl_fd, PIOCGENTRY, &sysset) < 0; + + if (goterr && !errok) { - info_proc_siginfo (pip, summary); + print_sys_errmsg (pi->pathname, errno); + error ("PIOCGENTRY failed"); } - if (summary || all || syscalls) + + if (!goterr) { - info_proc_syscalls (pip, summary); + prdelset (&sysset, syscall_num); + + if ((ioctl (pi->ctl_fd, PIOCSENTRY, &sysset) < 0) && !errok) + { + print_sys_errmsg (pi->pathname, errno); + error ("PIOCSENTRY failed"); + } } - if (summary || all || mappings) + + goterr = ioctl (pi->ctl_fd, PIOCGEXIT, &sysset) < 0; + + if (goterr && !errok) { - info_proc_mappings (pip, summary); + procfs_clear_syscall_trap (pi, syscall_num, 1); + print_sys_errmsg (pi->pathname, errno); + error ("PIOCGEXIT failed"); } - if (summary || all || signals) + + if (!goterr) { - info_proc_signals (pip, summary); + praddset (&sysset, syscall_num); + + if ((ioctl (pi->ctl_fd, PIOCSEXIT, &sysset) < 0) && !errok) + { + procfs_clear_syscall_trap (pi, syscall_num, 1); + print_sys_errmsg (pi->pathname, errno); + error ("PIOCSEXIT failed"); + } } - if (summary || all || faults) +#endif + + if (!pi->syscall_handlers) { - info_proc_faults (pip, summary); + if (!errok) + error ("procfs_clear_syscall_trap: syscall_handlers is empty"); + return; } - printf_filtered ("\n"); - /* All done, deal with closing any temporary process info structure, - freeing temporary memory , etc. */ + /* Remove handler func from the handler list */ + + for (i = 0; i < pi->num_syscall_handlers; i++) + if (pi->syscall_handlers[i].syscall_num == syscall_num) + { + if (i + 1 != pi->num_syscall_handlers) + { /* Not the last entry. + Move subsequent entries fwd. */ + memcpy (&pi->syscall_handlers[i], &pi->syscall_handlers[i + 1], + (pi->num_syscall_handlers - i - 1) + * sizeof (struct procfs_syscall_handler)); + } + + pi->syscall_handlers = xrealloc (pi->syscall_handlers, + (pi->num_syscall_handlers - 1) + * sizeof (struct procfs_syscall_handler)); + pi->num_syscall_handlers--; + return; + } - do_cleanups (old_chain); + if (!errok) + error ("procfs_clear_syscall_trap: Couldn't find handler for sys call %d", + syscall_num); } /* LOCAL FUNCTION - procfs_set_sproc_trap -- arrange for exec'd child stop on sproc + procfs_set_syscall_trap -- arrange for a function to be called when the + child executes the specified system call. SYNOPSIS - void procfs_set_sproc_trap (void) + void procfs_set_syscall_trap (struct procinfo *, int syscall_num, int flags, + syscall_func_t *function) DESCRIPTION - This function sets up a trap on sproc system call exits so that we can - detect the arrival of a new thread. We are called with the child - stopped prior to it's first instruction. - - Also note that we turn on the inherit-on-fork flag in the child process - so that any grand-children start with all tracing flags set. + This function sets up an entry and/or exit trap for the specified system + call. When the child executes the specified system call, your function + will be called with the call #, a flag that indicates entry or exit, and + pointers to rtnval and statval (which are used by procfs_wait). The + function should return non-zero if something interesting happened, zero + otherwise. */ -#ifdef SYS_sproc - static void -procfs_set_sproc_trap (pi) +procfs_set_syscall_trap (pi, syscall_num, flags, func) struct procinfo *pi; + int syscall_num; + int flags; + syscall_func_t *func; { - sysset_t exitset; - - if (ioctl (pi->fd, PIOCGEXIT, &exitset) < 0) + sysset_t sysset; + +#ifndef UNIXWARE + if (flags & PROCFS_SYSCALL_ENTRY) { - print_sys_errmsg (pi->pathname, errno); - error ("PIOCGEXIT failed"); + if (ioctl (pi->ctl_fd, PIOCGENTRY, &sysset) < 0) + { + print_sys_errmsg (pi->pathname, errno); + error ("PIOCGENTRY failed"); + } + + praddset (&sysset, syscall_num); + + if (ioctl (pi->ctl_fd, PIOCSENTRY, &sysset) < 0) + { + print_sys_errmsg (pi->pathname, errno); + error ("PIOCSENTRY failed"); + } } - praddset (&exitset, SYS_sproc); + if (flags & PROCFS_SYSCALL_EXIT) + { + if (ioctl (pi->ctl_fd, PIOCGEXIT, &sysset) < 0) + { + procfs_clear_syscall_trap (pi, syscall_num, 1); + print_sys_errmsg (pi->pathname, errno); + error ("PIOCGEXIT failed"); + } + + praddset (&sysset, syscall_num); + + if (ioctl (pi->ctl_fd, PIOCSEXIT, &sysset) < 0) + { + procfs_clear_syscall_trap (pi, syscall_num, 1); + print_sys_errmsg (pi->pathname, errno); + error ("PIOCSEXIT failed"); + } + } +#endif - if (ioctl (pi->fd, PIOCSEXIT, &exitset) < 0) + if (!pi->syscall_handlers) { - print_sys_errmsg (pi->pathname, errno); - error ("PIOCSEXIT failed"); + pi->syscall_handlers = xmalloc (sizeof (struct procfs_syscall_handler)); + pi->syscall_handlers[0].syscall_num = syscall_num; + pi->syscall_handlers[0].func = func; + pi->num_syscall_handlers = 1; + } + else + { + int i; + + for (i = 0; i < pi->num_syscall_handlers; i++) + if (pi->syscall_handlers[i].syscall_num == syscall_num) + { + pi->syscall_handlers[i].func = func; + return; + } + + pi->syscall_handlers = xrealloc (pi->syscall_handlers, (i + 1) + * sizeof (struct procfs_syscall_handler)); + pi->syscall_handlers[i].syscall_num = syscall_num; + pi->syscall_handlers[i].func = func; + pi->num_syscall_handlers++; } +} - /* Turn on inherit-on-fork flag so that all grand-children of gdb start with - tracing flags set. */ +#ifdef SYS_lwp_create -#ifdef PIOCSET /* New method */ - { - long pr_flags; - pr_flags = PR_FORK; - ioctl (pi->fd, PIOCSET, &pr_flags); - } +/* + +LOCAL FUNCTION + + procfs_lwp_creation_handler - handle exit from the _lwp_create syscall + +SYNOPSIS + + int procfs_lwp_creation_handler (pi, syscall_num, why, rtnvalp, statvalp) + +DESCRIPTION + + This routine is called both when an inferior process and it's new lwp + are about to finish a _lwp_create() system call. This is the system + call that Solaris uses to create a lightweight process. When the + target process gets this event, we can look at sysarg[2] to find the + new childs lwp ID, and create a procinfo struct from that. After that, + we pretend that we got a SIGTRAP, and return non-zero to tell + procfs_wait to wake up. Subsequently, wait_for_inferior gets woken up, + sees the new process and continues it. + + When we see the child exiting from lwp_create, we just contine it, + since everything was handled when the parent trapped. + +NOTES + In effect, we are only paying attention to the parent's completion of + the lwp_create syscall. If we only paid attention to the child + instead, then we wouldn't detect the creation of a suspended thread. + */ + +static int +procfs_lwp_creation_handler (pi, syscall_num, why, rtnvalp, statvalp) + struct procinfo *pi; + int syscall_num; + int why; + int *rtnvalp; + int *statvalp; +{ + int lwp_id; + struct procinfo *childpi; + struct proc_ctl pctl; + + /* We've just detected the completion of an lwp_create system call. Now we + need to setup a procinfo struct for this thread, and notify the thread + system of the new arrival. */ + + /* If lwp_create failed, then nothing interesting happened. Continue the + process and go back to sleep. */ + +#ifdef UNIXWARE + /* Joel ... can you check this logic out please? JKJ */ + if (pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs[R_EFL] & 1) + { /* _lwp_create failed */ + pctl.cmd = PCRUN; + pctl.data = PRCFAULT; + + if (write (pi->ctl_fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0) + perror_with_name (pi->pathname); + + return 0; + } +#else /* UNIXWARE */ + if (PROCFS_GET_CARRY (pi->prstatus.pr_reg)) + { /* _lwp_create failed */ + 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 0; + } +#endif + + /* At this point, the new thread is stopped at it's first instruction, and + the parent is stopped at the exit from lwp_create. */ + + if (pi->new_child) /* Child? */ + { /* Yes, just continue it */ +#ifdef UNIXWARE + pctl.cmd = PCRUN; + pctl.data = PRCFAULT; + + if (write(pi->ctl_fd, (char *)&pctl, sizeof (struct proc_ctl)) < 0) +#else /* !UNIXWARE */ + pi->prrun.pr_flags &= PRSTEP; + pi->prrun.pr_flags |= PRCFAULT; + + if ((pi->prstatus.pr_flags & PR_ISTOP) + && ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0) +#endif /* !UNIXWARE */ + perror_with_name (pi->pathname); + + pi->new_child = 0; /* No longer new */ + + return 0; + } + + /* 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 ( + THE_PR_LWP(pi->prstatus).pr_sysarg[2], sizeof (int)); + + lwp_id = (lwp_id << 16) | PIDGET (pi->pid); + + 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 handlers for + that child. */ + + procfs_set_inferior_syscall_traps (childpi); + add_thread (lwp_id); + printf_filtered ("[New %s]\n", target_pid_to_str (lwp_id)); + + /* Continue the parent */ +#ifdef UNIXWARE + pctl.cmd = PCRUN; + pctl.data = PRCFAULT; + + if (write(pi->ctl_fd, (char *)&pctl, sizeof (struct proc_ctl)) < 0) #else -#ifdef PIOCSFORK /* Original method */ - ioctl (pi->fd, PIOCSFORK, NULL); + pi->prrun.pr_flags &= PRSTEP; + pi->prrun.pr_flags |= PRCFAULT; + if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0) #endif + perror_with_name (pi->pathname); + + /* 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 (THE_PR_LWP(childpi->prstatus).pr_why == PR_SUSPENDED) + childpi->new_child = 1; /* Flag this as an unseen child process */ + else + { + /* Continue the child */ +#ifdef UNIXWARE + pctl.cmd = PCRUN; + pctl.data = PRCFAULT; + + if (write(pi->ctl_fd, (char *)&pctl, sizeof (struct proc_ctl)) < 0) +#else + childpi->prrun.pr_flags &= PRSTEP; + childpi->prrun.pr_flags |= PRCFAULT; + + if (ioctl (childpi->ctl_fd, PIOCRUN, &childpi->prrun) != 0) #endif + perror_with_name (childpi->pathname); + } + return 0; } -#endif /* SYS_sproc */ +#endif /* SYS_lwp_create */ /* Fork an inferior process, and start debugging it with /proc. */ @@ -3504,17 +5532,11 @@ procfs_create_inferior (exec_file, allargs, env) } fork_inferior (exec_file, allargs, env, - proc_set_exec_trap, procfs_init_inferior, shell_file); + proc_set_exec_trap, procfs_init_inferior, NULL, shell_file); /* We are at the first instruction we care about. */ /* Pedal to the metal... */ - /* Setup traps on exit from sproc() */ - -#ifdef SYS_sproc - procfs_set_sproc_trap (current_procinfo); -#endif - proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0); } @@ -3524,20 +5546,31 @@ static void procfs_mourn_inferior () { struct procinfo *pi; + struct procinfo *next_pi; - for (pi = procinfo_list; pi; pi = pi->next) - unconditionally_kill_inferior (pi); + for (pi = procinfo_list; pi; pi = next_pi) + { + next_pi = pi->next; + unconditionally_kill_inferior (pi); + } unpush_target (&procfs_ops); generic_mourn_inferior (); } + /* Mark our target-struct as eligible for stray "run" and "attach" commands. */ static int procfs_can_run () { - return(1); + /* This variable is controlled by modules that sit atop procfs that may layer + their own process structure atop that provided here. sol-thread.c does + this because of the Solaris two-level thread model. */ + + return !procfs_suppress_run; } +#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS +#ifndef UNIXWARE /* Insert a watchpoint */ int @@ -3554,7 +5587,7 @@ procfs_set_watchpoint(pid, addr, len, rw) wpt.pr_vaddr = (caddr_t)addr; wpt.pr_size = len; wpt.pr_wflags = ((rw & 1) ? MA_READ : 0) | ((rw & 2) ? MA_WRITE : 0); - if (ioctl (pi->fd, PIOCSWATCH, &wpt) < 0) + if (ioctl (pi->ctl_fd, PIOCSWATCH, &wpt) < 0) { if (errno == E2BIG) return -1; @@ -3582,60 +5615,162 @@ procfs_stopped_by_watchpoint(pid) why = pi->prstatus.pr_why; what = pi->prstatus.pr_what; if (why == PR_FAULTED - && (what == FLTWATCH) || (what == FLTKWATCH)) +#if defined (FLTWATCH) && defined (FLTKWATCH) + && (what == FLTWATCH || what == FLTKWATCH) +#else +#ifdef FLTWATCH + && (what == FLTWATCH) +#endif +#ifdef FLTKWATCH + && (what == FLTKWATCH) +#endif +#endif + ) return what; } return 0; } +#endif /* !UNIXWARE */ +#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */ + +/* Why is this necessary? Shouldn't dead threads just be removed from the + thread database? */ + +static int +procfs_thread_alive (pid) + int pid; +{ + 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; +} + +int +procfs_get_pid_fd (pid) + int pid; +{ + struct procinfo *pi = find_procinfo (pid, 1); + + if (pi == NULL) + return -1; + + return pi->ctl_fd; +} + +/* Send a SIGINT to the process group. This acts just like the user typed a + ^C on the controlling terminal. + + XXX - This may not be correct for all systems. Some may want to use + killpg() instead of kill (-pgrp). */ + +static void +procfs_stop () +{ + extern pid_t inferior_process_group; + + kill (-inferior_process_group, SIGINT); +} + +/* Convert a pid to printable form. */ + +#ifdef TIDGET +char * +procfs_pid_to_str (pid) + int pid; +{ + static char buf[100]; + + sprintf (buf, "Kernel thread %d", TIDGET (pid)); + + return buf; +} +#endif /* TIDGET */ -struct target_ops procfs_ops = { - "procfs", /* to_shortname */ - "Unix /proc child process", /* to_longname */ - "Unix /proc child process (started by the \"run\" command).", /* to_doc */ - procfs_open, /* to_open */ - 0, /* to_close */ - procfs_attach, /* to_attach */ - procfs_detach, /* to_detach */ - procfs_resume, /* to_resume */ - procfs_wait, /* to_wait */ - procfs_fetch_registers, /* to_fetch_registers */ - procfs_store_registers, /* to_store_registers */ - procfs_prepare_to_store, /* to_prepare_to_store */ - procfs_xfer_memory, /* to_xfer_memory */ - procfs_files_info, /* to_files_info */ - memory_insert_breakpoint, /* to_insert_breakpoint */ - memory_remove_breakpoint, /* to_remove_breakpoint */ - terminal_init_inferior, /* to_terminal_init */ - terminal_inferior, /* to_terminal_inferior */ - terminal_ours_for_output, /* to_terminal_ours_for_output */ - terminal_ours, /* to_terminal_ours */ - child_terminal_info, /* to_terminal_info */ - procfs_kill_inferior, /* to_kill */ - 0, /* to_load */ - 0, /* to_lookup_symbol */ - procfs_create_inferior, /* to_create_inferior */ - procfs_mourn_inferior, /* to_mourn_inferior */ - procfs_can_run, /* to_can_run */ - procfs_notice_signals, /* to_notice_signals */ - process_stratum, /* to_stratum */ - 0, /* to_next */ - 1, /* to_has_all_memory */ - 1, /* to_has_memory */ - 1, /* to_has_stack */ - 1, /* to_has_registers */ - 1, /* to_has_execution */ - 0, /* sections */ - 0, /* sections_end */ - OPS_MAGIC /* to_magic */ -}; +static void +init_procfs_ops () +{ + procfs_ops.to_shortname = "procfs"; + procfs_ops.to_longname = "Unix /proc child process"; + procfs_ops.to_doc = "Unix /proc child process (started by the \"run\" command)."; + procfs_ops.to_open = procfs_open; + procfs_ops.to_attach = procfs_attach; + procfs_ops.to_detach = procfs_detach; + procfs_ops.to_resume = procfs_resume; + procfs_ops.to_wait = procfs_wait; + procfs_ops.to_fetch_registers = procfs_fetch_registers; + procfs_ops.to_store_registers = procfs_store_registers; + procfs_ops.to_prepare_to_store = procfs_prepare_to_store; + procfs_ops.to_xfer_memory = procfs_xfer_memory; + procfs_ops.to_files_info = procfs_files_info; + procfs_ops.to_insert_breakpoint = memory_insert_breakpoint; + procfs_ops.to_remove_breakpoint = memory_remove_breakpoint; + procfs_ops.to_terminal_init = terminal_init_inferior; + procfs_ops.to_terminal_inferior = terminal_inferior; + procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output; + procfs_ops.to_terminal_ours = terminal_ours; + procfs_ops.to_terminal_info = child_terminal_info; + procfs_ops.to_kill = procfs_kill_inferior; + procfs_ops.to_create_inferior = procfs_create_inferior; + procfs_ops.to_mourn_inferior = procfs_mourn_inferior; + procfs_ops.to_can_run = procfs_can_run; + procfs_ops.to_notice_signals = procfs_notice_signals; + procfs_ops.to_thread_alive = procfs_thread_alive; + procfs_ops.to_stop = procfs_stop; + procfs_ops.to_stratum = process_stratum; + procfs_ops.to_has_all_memory = 1; + procfs_ops.to_has_memory = 1; + procfs_ops.to_has_stack = 1; + procfs_ops.to_has_registers = 1; + procfs_ops.to_has_execution = 1; + procfs_ops.to_magic = OPS_MAGIC; +} void _initialize_procfs () { +#ifdef HAVE_OPTIONAL_PROC_FS + char procname[MAX_PROC_NAME_SIZE]; + int fd; + + /* If we have an optional /proc filesystem (e.g. under OSF/1), + don't add procfs support if we cannot access the running + GDB via /proc. */ + sprintf (procname, STATUS_PROC_NAME_FMT, getpid ()); + if ((fd = open (procname, O_RDONLY)) < 0) + return; + close (fd); +#endif + + init_procfs_ops (); 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\