136359Smarc /* 236359Smarc * Copyright (c) 1989 The Regents of the University of California. 336359Smarc * All rights reserved. 436359Smarc * 536359Smarc * Redistribution and use in source and binary forms are permitted 636359Smarc * provided that the above copyright notice and this paragraph are 736359Smarc * duplicated in all such forms and that any documentation, 836359Smarc * advertising materials, and other materials related to such 936359Smarc * distribution and use acknowledge that the software was developed 1036359Smarc * by the University of California, Berkeley. The name of the 1136359Smarc * University may not be used to endorse or promote products derived 1236359Smarc * from this software without specific prior written permission. 1336359Smarc * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1436359Smarc * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1536359Smarc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1636359Smarc * 17*37555Smckusick * @(#)kern_ktrace.c 1.2 (Berkeley) 04/26/89 1836359Smarc */ 1936359Smarc 2036359Smarc #ifdef KTRACE 2136359Smarc 2236359Smarc #include "param.h" 2336359Smarc #include "systm.h" 2436359Smarc #include "dir.h" 2536359Smarc #include "user.h" 2636359Smarc #include "assym.s" 2736359Smarc #include "proc.h" 2836359Smarc #include "seg.h" 2936359Smarc #include "acct.h" 3036359Smarc #include "fs.h" 3136359Smarc #include "inode.h" 3236359Smarc #include "syslog.h" 3336359Smarc #include "kernel.h" 3436359Smarc #include "ktrace.h" 3536359Smarc #include "malloc.h" 3636359Smarc 3736359Smarc #include "../sys/syscalls.c" 3836359Smarc 3936359Smarc extern int nsysent; 4036359Smarc extern char *syscallnames[]; 4136359Smarc 4236359Smarc struct ktr_header * 4336359Smarc ktrgetheader(type) 4436359Smarc { 4536359Smarc register struct ktr_header *kth; 4636359Smarc 4736359Smarc MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 4836359Smarc M_TEMP, M_WAITOK); 4936359Smarc if (kth == NULL) 5036359Smarc return (NULL); 5136359Smarc kth->ktr_type = type; 5236359Smarc kth->ktr_time = time; 5336359Smarc kth->ktr_pid = u.u_procp->p_pid; 5436359Smarc bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN); 5536359Smarc 5636359Smarc return (kth); 5736359Smarc } 5836359Smarc 5936359Smarc ktrsyscall(ip, code, narg) 6036359Smarc struct inode *ip; 6136359Smarc { 6236359Smarc struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); 6336359Smarc struct ktr_syscall *ktp; 6436359Smarc register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 6536359Smarc int *argp, i; 6636359Smarc 6736359Smarc if (kth == NULL) { 6836359Smarc printf("lost syscall trace - no header\n"); /* DEBUG */ 6936359Smarc return; 7036359Smarc } 7136359Smarc MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 7236359Smarc if (ktp == NULL) { 7336359Smarc printf("lost syscall trace - no buffer\n"); /* DEBUG */ 7436359Smarc FREE(kth, M_TEMP); 7536359Smarc return; 7636359Smarc } 7736359Smarc ktp->ktr_code = code; 7836359Smarc ktp->ktr_narg = narg; 7936359Smarc argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 8036359Smarc for (i = 0; i < narg; i++) 8136359Smarc *argp++ = u.u_arg[i]; 8236359Smarc kth->ktr_buf = (caddr_t)ktp; 8336359Smarc kth->ktr_len = len; 8436359Smarc ktrwrite(ip, kth); 8536359Smarc FREE(ktp, M_TEMP); 8636359Smarc FREE(kth, M_TEMP); 8736359Smarc } 8836359Smarc 8936359Smarc ktrsysret(ip, code) 9036359Smarc struct inode *ip; 9136359Smarc { 9236359Smarc struct ktr_header *kth = ktrgetheader(KTR_SYSRET); 9336359Smarc struct ktr_sysret *ktp; 9436359Smarc 9536359Smarc if (kth == NULL) { 9636359Smarc printf("lost syscall ret - no header\n"); /* DEBUG */ 9736359Smarc return; 9836359Smarc } 9936359Smarc MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret), 10036359Smarc M_TEMP , M_WAITOK); 10136359Smarc if (ktp == NULL) { 10236359Smarc printf("lost syscall ret - no buffer\n"); /* DEBUG */ 10336359Smarc FREE(kth, M_TEMP); 10436359Smarc return; 10536359Smarc } 10636359Smarc ktp->ktr_code = code; 10736359Smarc ktp->ktr_eosys = u.u_eosys; 10836359Smarc ktp->ktr_error = u.u_error; 10936359Smarc ktp->ktr_retval = u.u_r.r_val1; /* what about val2 ? */ 11036359Smarc 11136359Smarc kth->ktr_buf = (caddr_t)ktp; 11236359Smarc kth->ktr_len = sizeof(struct ktr_sysret); 11336359Smarc 11436359Smarc ktrwrite(ip, kth); 11536359Smarc FREE(ktp, M_TEMP); 11636359Smarc FREE(kth, M_TEMP); 11736359Smarc } 11836359Smarc 11936359Smarc ktrnamei(ip, path) 12036359Smarc struct inode *ip; 12136359Smarc char *path; 12236359Smarc { 12336359Smarc struct ktr_header *kth = ktrgetheader(KTR_NAMEI); 12436359Smarc 12536359Smarc if (kth == NULL) { 12636359Smarc printf("lost namei - no header\n"); /* DEBUG */ 12736359Smarc return; 12836359Smarc } 12936359Smarc kth->ktr_len = strlen(path); 13036359Smarc kth->ktr_buf = path; 13136359Smarc 13236359Smarc ktrwrite(ip, kth); 13336359Smarc FREE(kth, M_TEMP); 13436359Smarc } 13536359Smarc 13636359Smarc /* 13736359Smarc * ktrace system call 13836359Smarc */ 13936359Smarc ktrace() 14036359Smarc { 14136359Smarc register struct inode *ip = NULL; 14236359Smarc register struct a { 14336359Smarc char *fname; 14436359Smarc int ops; 14536359Smarc int facs; 14636359Smarc pid_t pid; 14736359Smarc } *uap = (struct a *)u.u_ap; 14836359Smarc register struct nameidata *ndp = &u.u_nd; 14936359Smarc register struct proc *p; 15036359Smarc struct pgrp *pg; 15136359Smarc register int ops = uap->ops&0x3; 15236359Smarc register int facs = uap->facs; 15336359Smarc 15436359Smarc /* 15536359Smarc * Until security implications are thought through, 15636359Smarc * limit tracing to root. 15736359Smarc */ 158*37555Smckusick if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag))) 15936359Smarc return; 16036359Smarc if (ops != KTROP_CLEAR) { 16136359Smarc /* 16236359Smarc * an operation which requires a file argument. 16336359Smarc */ 16436359Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 16536359Smarc ndp->ni_segflg = UIO_USERSPACE; 16636359Smarc ndp->ni_dirp = uap->fname; 16736359Smarc ip = namei(ndp); 16836359Smarc if (ip == NULL) 16936359Smarc return; 17036359Smarc if ((ip->i_mode&IFMT) != IFREG) { 17136359Smarc u.u_error = EACCES; 17236359Smarc iput(ip); 17336359Smarc return; 17436359Smarc } 17536359Smarc if (ip->i_fs->fs_ronly) { 17636359Smarc u.u_error = EROFS; 17736359Smarc iput(ip); 17836359Smarc return; 17936359Smarc } 18036359Smarc iunlock(ip); 18136359Smarc } 18236359Smarc /* 18336359Smarc * Clear all uses of the tracefile 18436359Smarc */ 18536359Smarc if (ops == KTROP_CLEARFILE) { 18636359Smarc for (p = allproc; p != NULL; p = p->p_nxt) { 18736359Smarc if (p->p_tracep == ip) { 18836359Smarc p->p_flag &= ~SKTR; 18936359Smarc p->p_tracep = NULL; 19036359Smarc p->p_traceflag = 0; 19136359Smarc irele(ip); 19236359Smarc } 19336359Smarc } 19436359Smarc goto done; 19536359Smarc } 19636359Smarc 19736359Smarc /* 19836359Smarc * need something to (un)trace 19936359Smarc */ 20036359Smarc if (!facs) { 20136359Smarc u.u_error = EINVAL; 20236359Smarc goto done; 20336359Smarc } 20436359Smarc 20536359Smarc if (uap->pid < 0) { 20636359Smarc pg = pgfind(-uap->pid); 20736359Smarc if (pg == NULL) { 20836359Smarc u.u_error = ESRCH; 20936359Smarc goto done; 21036359Smarc } 21136359Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 21236359Smarc if (uap->ops&KTROP_INHERITFLAG) 21336359Smarc ktrsetchildren(p, ops, facs, ip); 21436359Smarc else 21536359Smarc ktrops(p, ops, facs, ip); 21636359Smarc 21736359Smarc } else { 21836359Smarc p = pfind(uap->pid); 21936359Smarc if (p == NULL) { 22036359Smarc u.u_error = ESRCH; 22136359Smarc goto done; 22236359Smarc } 22336359Smarc if (uap->ops&KTROP_INHERITFLAG) 22436359Smarc ktrsetchildren(p, ops, facs, ip); 22536359Smarc else 22636359Smarc ktrops(p, ops, facs, ip); 22736359Smarc } 22836359Smarc done: 22936359Smarc if (ip != NULL) 23036359Smarc irele(ip); 23136359Smarc } 23236359Smarc 23336359Smarc ktrops(p, ops, facs, ip) 23436359Smarc struct proc *p; 23536359Smarc struct inode *ip; 23636359Smarc { 23736359Smarc if (ops == KTROP_SET) { 23836359Smarc if (p->p_tracep != ip) { 23936359Smarc /* 24036359Smarc * if trace file already in use, relinquish 24136359Smarc */ 24236359Smarc if (p->p_tracep != NULL) 24336359Smarc irele(p->p_tracep); 24436359Smarc igrab(ip); 24536359Smarc p->p_tracep = ip; 24636359Smarc iunlock(ip); 24736359Smarc } 24836359Smarc p->p_traceflag |= facs; 24936359Smarc } else { 25036359Smarc /* KTROP_CLEAR */ 25136359Smarc if ((p->p_traceflag &= ~facs) == 0) { 25236359Smarc if (p->p_tracep != NULL) { 25336359Smarc irele(p->p_tracep); 25436359Smarc p->p_tracep = NULL; 25536359Smarc } 25636359Smarc p->p_flag &= SKTR; 25736359Smarc } 25836359Smarc } 25936359Smarc } 26036359Smarc 26136359Smarc ktrsetchildren(top, ops, facs, ip) 26236359Smarc struct proc *top; 26336359Smarc struct inode *ip; 26436359Smarc { 26536359Smarc register struct proc *p; 26636359Smarc register int ndx; 26736359Smarc 26836359Smarc p = top; 26936359Smarc for (;;) { 27036359Smarc if (ops == KTROP_SET) 27136359Smarc p->p_flag |= SKTR; 27236359Smarc ktrops(p, ops, facs, ip); 27336359Smarc /* 27436359Smarc * If this process has children, descend to them next, 27536359Smarc * otherwise do any siblings, and if done with this level, 27636359Smarc * follow back up the tree (but not past top). 27736359Smarc */ 27836359Smarc if (p->p_cptr) 27936359Smarc p = p->p_cptr; 28036359Smarc else if (p == top) 28136359Smarc return; 28236359Smarc else if (p->p_osptr) 28336359Smarc p = p->p_osptr; 28436359Smarc else for (;;) { 28536359Smarc p = p->p_pptr; 28636359Smarc if (p == top) 28736359Smarc return; 28836359Smarc if (p->p_osptr) { 28936359Smarc p = p->p_osptr; 29036359Smarc break; 29136359Smarc } 29236359Smarc } 29336359Smarc } 29436359Smarc } 29536359Smarc 29636359Smarc ktrwrite(ip, kth) 29736359Smarc register struct inode *ip; 29836359Smarc struct ktr_header *kth; 29936359Smarc { 30036359Smarc int save = u.u_error; 30136359Smarc int osize; 30236359Smarc 30336359Smarc ilock(ip); 30436359Smarc osize = ip->i_size; 30536359Smarc u.u_error = 0; 30636359Smarc u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)kth, 30736359Smarc sizeof(struct ktr_header), ip->i_size, 1, (int *)0); 30836359Smarc if (u.u_error) { 30936359Smarc itrunc(ip, (u_long)osize); 31036359Smarc goto end; 31136359Smarc } 31236359Smarc if (kth->ktr_len > 0) { 31336359Smarc u.u_error = rdwri(UIO_WRITE, ip, kth->ktr_buf, 31436359Smarc kth->ktr_len, ip->i_size, 1, (int *)0); 31536359Smarc if (u.u_error) 31636359Smarc itrunc(ip, (u_long)osize); 31736359Smarc } 31836359Smarc end: 31936359Smarc u.u_error = save; 32036359Smarc iunlock(ip); 32136359Smarc } 32236359Smarc 32336359Smarc #endif 324