From owner-freebsd-hackers Wed Nov 26 16:42:10 1997 Return-Path: Received: (from root@localhost) by hub.freebsd.org (8.8.7/8.8.7) id QAA04338 for hackers-outgoing; Wed, 26 Nov 1997 16:42:10 -0800 (PST) (envelope-from owner-freebsd-hackers) Received: from kithrup.com (kithrup.com [205.179.156.40]) by hub.freebsd.org (8.8.7/8.8.7) with ESMTP id QAA04329 for ; Wed, 26 Nov 1997 16:42:02 -0800 (PST) (envelope-from sef@garth.kithrup.com) Received: from garth.kithrup.com (garth.kithrup.com [205.179.156.41]) by kithrup.com (8.8.8/8.8.7) with ESMTP id QAA07272 for ; Wed, 26 Nov 1997 16:42:01 -0800 (PST) (envelope-from sef@garth.kithrup.com) Received: (from sef@localhost) by garth.kithrup.com (8.8.5/8.7.3) id QAA00355 for hackers@freebsd.org; Wed, 26 Nov 1997 16:41:56 -0800 (PST) Date: Wed, 26 Nov 1997 16:41:56 -0800 (PST) From: Sean Eric Fagan Message-Id: <199711270041.QAA00355@garth.kithrup.com> To: hackers@freebsd.org Subject: procfs patches Sender: owner-freebsd-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk These are the kernel side of the truss work I've been doing for the past few years. I'm running a 2.2 system with these patches. The truss and procctl programs are at http://www.freebsd.org/~sef/truss -- it works, and even works for linux binaries. (I'm working on even better version, that will be able to print out the arguments in an intelligent fashion, but that's nowhere near ready.) Enjoy. I expect to check this stuff in "soon" (hopefully within a couple of weekends). Note that you need to rebuild libkvm, ps, gdb, and all LKM's -- I kinda paniced one of my systems when I forgot about that, and went multiuser ;). Also note the new file -- sys/pioctl.h. Index: i386/i386/trap.c =================================================================== RCS file: /kithrup/cvs/src/sys/i386/i386/trap.c,v retrieving revision 1.114 diff -u -r1.114 trap.c --- trap.c 1997/11/06 19:28:09 1.114 +++ trap.c 1997/11/15 05:05:46 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -959,6 +960,8 @@ p->p_retval[0] = 0; p->p_retval[1] = frame.tf_edx; + STOPEVENT(p, S_SCE, callp->sy_narg); + error = (*callp->sy_call)(p, args); switch (error) { @@ -1009,6 +1012,14 @@ if (KTRPOINT(p, KTR_SYSRET)) ktrsysret(p->p_tracep, code, error, p->p_retval[0]); #endif + + /* + * This works because errno is findable through the + * register set. If we ever support an emulation where this + * is not the case, this code will need to be revisited. + */ + STOPEVENT(p, S_SCX, code); + } /* Index: kern/init_main.c =================================================================== RCS file: /kithrup/cvs/src/sys/kern/init_main.c,v retrieving revision 1.74 diff -u -r1.74 init_main.c --- init_main.c 1997/11/07 08:52:53 1.74 +++ init_main.c 1997/11/15 05:05:45 @@ -417,6 +417,12 @@ * Charge root for one process. */ (void)chgproccnt(0, 1); + + /* + * Initialize the procfs flags (to 0, of course) + */ + p->p_stops = p->p_stype = p->p_step = 0; + } SYSINIT(p0init, SI_SUB_INTRINSIC, SI_ORDER_FIRST, proc0_init, NULL) Index: kern/kern_exec.c =================================================================== RCS file: /kithrup/cvs/src/sys/kern/kern_exec.c,v retrieving revision 1.68 diff -u -r1.68 kern_exec.c --- kern_exec.c 1997/11/06 19:29:08 1.68 +++ kern_exec.c 1997/11/15 05:05:45 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -338,6 +339,8 @@ * If tracing the process, trap to debugger so breakpoints * can be set before the program executes. */ + STOPEVENT(p, S_EXEC, 0); + if (p->p_flag & P_TRACED) psignal(p, SIGTRAP); Index: kern/kern_exit.c =================================================================== RCS file: /kithrup/cvs/src/sys/kern/kern_exit.c,v retrieving revision 1.60 diff -u -r1.60 kern_exit.c --- kern_exit.c 1997/11/20 19:09:43 1.60 +++ kern_exit.c 1997/11/22 06:55:04 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -113,6 +114,7 @@ register struct proc *q, *nq; register struct vmspace *vm; ele_p ep = exit_list; + extern void procfs_exit(pid_t); if (p->p_pid == 1) { printf("init died (signal %d, exit %d)\n", @@ -155,6 +157,14 @@ #ifdef PGINPROF vmsizmon(); #endif + STOPEVENT(p, S_EXIT, rv); + + /* + * Now that we're back from stopevent(), force a close + * of all open procfs files for this process. + */ + procfs_exit(p->p_pid); + /* * Check if any LKMs need anything done at process exit. * e.g. SYSV IPC stuff Index: kern/kern_sig.c =================================================================== RCS file: /kithrup/cvs/src/sys/kern/kern_sig.c,v retrieving revision 1.35 diff -u -r1.35 kern_sig.c --- kern_sig.c 1997/11/06 19:29:14 1.35 +++ kern_sig.c 1997/11/27 00:34:07 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -743,15 +744,19 @@ register sig_t action; int mask; - if ((u_int)signum >= NSIG || signum == 0) + if ((u_int)signum >= NSIG || signum == 0) { + printf("psignal: signum %d\n", signum); panic("psignal signal number"); + } mask = sigmask(signum); prop = sigprop[signum]; /* - * If proc is traced, always give parent a chance. + * If proc is traced, always give parent a chance; + * if signal event is tracked by procfs, give *that* + * a chance, as well. */ - if (p->p_flag & P_TRACED) + if ((p->p_flag & P_TRACED) || (p->p_stops & S_SIG)) action = SIG_DFL; else { /* @@ -948,6 +953,8 @@ register int signum, mask, prop; for (;;) { + int traced = (p->p_flag & P_TRACED) || (p->p_stops & S_SIG); + mask = p->p_siglist & ~p->p_sigmask; if (p->p_flag & P_PPWAIT) mask &= ~stopsigmask; @@ -956,11 +963,14 @@ signum = ffs((long)mask); mask = sigmask(signum); prop = sigprop[signum]; + + STOPEVENT(p, S_SIG, signum); + /* * We should see pending but ignored signals * only if P_TRACED was on when they were posted. */ - if (mask & p->p_sigignore && (p->p_flag & P_TRACED) == 0) { + if ((mask & p->p_sigignore) && (traced == 0)) { p->p_siglist &= ~mask; continue; } @@ -974,7 +984,8 @@ do { stop(p); mi_switch(); - } while (!trace_req(p) && p->p_flag & P_TRACED); + } while (!trace_req(p) + && p->p_flag & P_TRACED); /* * If the traced bit got turned off, go back up @@ -1118,6 +1129,8 @@ signum, action, ps->ps_flags & SAS_OLDMASK ? ps->ps_oldmask : p->p_sigmask, 0); #endif + STOPEVENT(p, S_SIG, signum); + if (action == SIG_DFL) { /* * Default action, where the default is to kill @@ -1235,6 +1248,8 @@ struct vattr vattr; int error, error1; char name[MAXCOMLEN+6]; /* progname.core */ + + STOPEVENT(p, S_CORE, 0); if (p->p_flag & P_SUGID) return (EFAULT); Index: kern/sys_process.c =================================================================== RCS file: /kithrup/cvs/src/sys/kern/sys_process.c,v retrieving revision 1.32 diff -u -r1.32 sys_process.c --- sys_process.c 1997/11/12 12:28:12 1.32 +++ sys_process.c 1997/11/15 05:05:44 @@ -503,3 +503,22 @@ { return 1; } + +/* + * stopevent() + * Stop a process because of a procfs event; + * stay stopped until p->p_step is cleared + * (cleared by PIOCCONT in procfs). + */ + +void +stopevent(struct proc *p, unsigned int event, unsigned int val) { + p->p_step = 1; + + do { + p->p_xstat = val; + p->p_stype = event; /* Which event caused the stop? */ + wakeup(&p->p_stype); /* Wake up any PIOCWAIT'ing procs */ + tsleep(&p->p_step, PWAIT, "stopevent", 0); + } while (p->p_step); +} Index: kern/vfs_vnops.c =================================================================== RCS file: /kithrup/cvs/src/sys/kern/vfs_vnops.c,v retrieving revision 1.41 diff -u -r1.41 vfs_vnops.c --- vfs_vnops.c 1997/11/07 08:53:11 1.41 +++ vfs_vnops.c 1997/11/15 05:05:43 @@ -453,8 +453,9 @@ /* fall into ... */ default: +#if 0 return (ENOTTY); - +#endif case VFIFO: case VCHR: case VBLK: Index: miscfs/procfs/procfs_subr.c =================================================================== RCS file: /kithrup/cvs/src/sys/miscfs/procfs/procfs_subr.c,v retrieving revision 1.17 diff -u -r1.17 procfs_subr.c --- procfs_subr.c 1997/08/02 14:32:18 1.17 +++ procfs_subr.c 1997/11/15 05:05:43 @@ -351,3 +351,14 @@ return (0); } + +void +procfs_exit(pid_t pid) +{ + struct pfsnode *pfs; + + for (pfs = pfshead; pfs ; pfs = pfs->pfs_next) { + if (pfs->pfs_pid == pid) + vgone(PFSTOV(pfs)); + } +} Index: miscfs/procfs/procfs_vnops.c =================================================================== RCS file: /kithrup/cvs/src/sys/miscfs/procfs/procfs_vnops.c,v retrieving revision 1.42 diff -u -r1.42 procfs_vnops.c --- procfs_vnops.c 1997/11/07 08:53:15 1.42 +++ procfs_vnops.c 1997/11/15 05:12:51 @@ -55,6 +55,7 @@ #include #include #include +#include static int procfs_abortop __P((struct vop_abortop_args *)); static int procfs_access __P((struct vop_access_args *)); @@ -63,6 +64,7 @@ static int procfs_close __P((struct vop_close_args *)); static int procfs_getattr __P((struct vop_getattr_args *)); static int procfs_inactive __P((struct vop_inactive_args *)); +static int procfs_ioctl __P((struct vop_ioctl_args *)); static int procfs_lookup __P((struct vop_lookup_args *)); static int procfs_open __P((struct vop_open_args *)); static int procfs_print __P((struct vop_print_args *)); @@ -184,6 +186,79 @@ } /* + * do an ioctl operation on a pfsnode (vp). + * (vp) is not locked on entry or exit. + */ +static int +procfs_ioctl(ap) + struct vop_ioctl_args *ap; +{ + struct pfsnode *pfs = VTOPFS(ap->a_vp); + struct proc *procp; + int error; + int signo; + struct procfs_status *psp; + + procp = pfind(pfs->pfs_pid); + if (procp == NULL) { + return ENOTTY; + } + + switch (ap->a_command) { + case PIOCBIS: + procp->p_stops |= *(unsigned int*)ap->a_data; + break; + case PIOCBIC: + procp->p_stops &= ~*(unsigned int*)ap->a_data; + break; + case PIOCSFL: + procp->p_pfsflags = (unsigned char)*(unsigned int*)ap->a_data; + *(unsigned int*)ap->a_data = procp->p_stops; + break; + case PIOCSTATUS: + psp = (struct procfs_status *)ap->a_data; + psp->state = (procp->p_step == 0); + psp->flags = procp->p_pfsflags; + psp->events = procp->p_stops; + if (procp->p_step) { + psp->why = procp->p_stype; + psp->val = procp->p_xstat; + } else { + psp->why = psp->val = 0; /* Not defined values */ + } + break; + case PIOCWAIT: + psp = (struct procfs_status *)ap->a_data; + if (procp->p_step == 0) { + error = tsleep(&procp->p_stype, PWAIT | PCATCH, "piocwait", 0); + if (error) + return error; + } + psp->state = 1; /* It stopped */ + psp->flags = procp->p_pfsflags; + psp->events = procp->p_stops; + psp->why = procp->p_stype; /* why it stopped */ + psp->val = procp->p_xstat; /* any extra info */ + break; + case PIOCCONT: /* Restart a proc */ + if (procp->p_step == 0) + return EINVAL; /* Can only start a stopped process */ + if (ap->a_data && (signo = *(int*)ap->a_data)) { + if (signo >= NSIG || signo <= 0) + return EINVAL; + if (error = psignal(procp, signo)) + return error; + } + procp->p_step = 0; + wakeup(&procp->p_step); + break; + default: + return (ENOTTY); + } + return 0; +} + +/* * do block mapping for pfsnode (vp). * since we don't use the buffer cache * for procfs this function should never @@ -908,6 +983,7 @@ { &vop_setattr_desc, (vop_t *) procfs_setattr }, { &vop_symlink_desc, (vop_t *) procfs_badop }, { &vop_write_desc, (vop_t *) procfs_rw }, + { &vop_ioctl_desc, (vop_t *) procfs_ioctl }, { NULL, NULL } }; static struct vnodeopv_desc procfs_vnodeop_opv_desc = Index: sys/proc.h =================================================================== RCS file: /kithrup/cvs/src/sys/sys/proc.h,v retrieving revision 1.46 diff -u -r1.46 proc.h --- proc.h 1997/11/06 19:29:45 1.46 +++ proc.h 1997/11/15 05:05:42 @@ -151,6 +151,11 @@ short p_locks; /* DEBUG: lockmgr count of held locks */ short p_simple_locks; /* DEBUG: count of held simple locks */ + unsigned int p_stops; /* procfs event bitmask */ + unsigned int p_stype; /* procfs stop event type */ + char p_step; /* procfs stop *once* flag */ + unsigned char p_pfsflags; /* procfs flags */ + char p_pad3[2]; /* padding for alignment */ register_t p_retval[2]; /* syscall aux returns */ /* End area that is zeroed on creation. */ @@ -270,6 +275,10 @@ if (--(s)->s_count == 0) \ FREE(s, M_SESSION); \ } + +extern void stopevent(struct proc*, unsigned int, unsigned int); +#define STOPEVENT(p,e,v) do { \ + if ((p)->p_stops & (e)) stopevent(p,e,v); } while (0) /* hold process U-area in memory, normally for ptrace/procfs work */ #define PHOLD(p) { \ Index: i386/i386/trap.c =================================================================== --- /dev/null Wed Nov 26 16:08:20 1997 +++ sys/pioctl.h Fri Nov 14 21:08:15 1997 @@ -0,0 +1,33 @@ +#include + +#if 0 +struct procfs_status { + int state; /* 0 for running, 1 for stopped */ + int why; /* what event, if any, proc stopped on */ + unsigned int val; /* Any extra data */ +}; +#else +struct procfs_status { + int state; /* Running, stopped, something else? */ + int flags; /* Any flags */ + unsigned long events; /* Events to stop on */ + int why; /* What event, if any, proc stopped on */ + unsigned long val; /* Any extra data */ +}; +#endif + +#define PIOCBIS _IOW('p', 1, unsigned int) /* Set event flag */ +#define PIOCBIC _IOW('p', 2, unsigned int) /* Clear event flag */ +#define PIOCSFL _IOR('p', 3, unsigned int) /* Set flags */ + /* wait for proc to stop */ +#define PIOCWAIT _IOR('p', 4, struct procfs_status) +#define PIOCCONT _IOW('p', 5, int) /* Continue a process */ + /* Get proc status */ +#define PIOCSTATUS _IOW('p', 6, struct procfs_status) + +#define S_EXEC 0x00000001 /* stop-on-exec */ +#define S_SIG 0x00000002 /* stop-on-signal */ +#define S_SCE 0x00000004 /* stop on syscall entry */ +#define S_SCX 0x00000008 /* stop on syscall exit */ +#define S_CORE 0x00000010 /* stop on coredump */ +#define S_EXIT 0x00000020 /* stop on exit */