1bbeaf6c0SSean Eric Fagan /* 2bbeaf6c0SSean Eric Fagan * Various setup functions for truss. Not the cleanest-written code, 3bbeaf6c0SSean Eric Fagan * I'm afraid. 4bbeaf6c0SSean Eric Fagan */ 5bbeaf6c0SSean Eric Fagan /* 6bbeaf6c0SSean Eric Fagan * $Id$ 7bbeaf6c0SSean Eric Fagan */ 8bbeaf6c0SSean Eric Fagan 9bbeaf6c0SSean Eric Fagan #include <stdio.h> 10bbeaf6c0SSean Eric Fagan #include <stdlib.h> 11bbeaf6c0SSean Eric Fagan #include <string.h> 12bbeaf6c0SSean Eric Fagan #include <unistd.h> 13bbeaf6c0SSean Eric Fagan #include <errno.h> 14bbeaf6c0SSean Eric Fagan #include <err.h> 15bbeaf6c0SSean Eric Fagan #include <fcntl.h> 16bbeaf6c0SSean Eric Fagan #include <signal.h> 17bbeaf6c0SSean Eric Fagan #include <sys/ioctl.h> 18bbeaf6c0SSean Eric Fagan #include <sys/pioctl.h> 19bbeaf6c0SSean Eric Fagan #include <sys/types.h> 20bbeaf6c0SSean Eric Fagan #include <sys/wait.h> 21bbeaf6c0SSean Eric Fagan 22bbeaf6c0SSean Eric Fagan static int evflags = 0; 23bbeaf6c0SSean Eric Fagan 24bbeaf6c0SSean Eric Fagan /* 25bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does 26bbeaf6c0SSean Eric Fagan * is vfork(), set itself up to stop on exec or exit, and then exec 27bbeaf6c0SSean Eric Fagan * the given command. At that point, the child process stops, and 28bbeaf6c0SSean Eric Fagan * the parent can wake up and deal with it. 29bbeaf6c0SSean Eric Fagan */ 30bbeaf6c0SSean Eric Fagan 31bbeaf6c0SSean Eric Fagan int 32bbeaf6c0SSean Eric Fagan setup_and_wait(char *command[]) { 33bbeaf6c0SSean Eric Fagan struct procfs_status pfs; 34bbeaf6c0SSean Eric Fagan char buf[32]; 35bbeaf6c0SSean Eric Fagan int fd; 36bbeaf6c0SSean Eric Fagan int pid; 37bbeaf6c0SSean Eric Fagan extern char *prog; 38bbeaf6c0SSean Eric Fagan int flags; 39bbeaf6c0SSean Eric Fagan 40bbeaf6c0SSean Eric Fagan pid = vfork(); 41bbeaf6c0SSean Eric Fagan if (pid == -1) { 42bbeaf6c0SSean Eric Fagan err(1, "vfork failed\n"); 43bbeaf6c0SSean Eric Fagan } 44bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 45bbeaf6c0SSean Eric Fagan int mask = S_EXEC | S_EXIT; 46bbeaf6c0SSean Eric Fagan fd = open("/proc/curproc/mem", O_WRONLY); 47bbeaf6c0SSean Eric Fagan if (fd == -1) 48bbeaf6c0SSean Eric Fagan err(2, "cannot open /proc/curproc/mem: %s\n", strerror(errno)); 49bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCBIS, &mask) == -1) 50bbeaf6c0SSean Eric Fagan err(3, "PIOCBIS: %s\n", strerror(errno)); 51bbeaf6c0SSean Eric Fagan execvp(command[0], command); 52bbeaf6c0SSean Eric Fagan mask = ~0; 53bbeaf6c0SSean Eric Fagan ioctl(fd, PIOCBIC, &mask); 54bbeaf6c0SSean Eric Fagan err(4, "execvp %s", command[0]); 55bbeaf6c0SSean Eric Fagan } 56bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 57bbeaf6c0SSean Eric Fagan 58bbeaf6c0SSean Eric Fagan if (waitpid(pid, NULL, WNOHANG) != 0) { 59bbeaf6c0SSean Eric Fagan /* 60bbeaf6c0SSean Eric Fagan * Process exited before it got to us -- meaning the exec failed 61bbeaf6c0SSean Eric Fagan * miserably -- so we just quietly exit. 62bbeaf6c0SSean Eric Fagan */ 63bbeaf6c0SSean Eric Fagan exit(1); 64bbeaf6c0SSean Eric Fagan } 65bbeaf6c0SSean Eric Fagan 66bbeaf6c0SSean Eric Fagan sprintf(buf, "/proc/%d/mem", pid); 67bbeaf6c0SSean Eric Fagan if ((fd = open(buf, O_RDWR)) == -1) 68bbeaf6c0SSean Eric Fagan err(5, "cannot open %s: %s\n", buf, strerror(errno)); 69bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCWAIT, &pfs) == -1) 70bbeaf6c0SSean Eric Fagan err(6, "PIOCWAIT: %s\n", strerror(errno)); 71bbeaf6c0SSean Eric Fagan if (pfs.why == S_EXIT) { 72bbeaf6c0SSean Eric Fagan int zero = 0; 73bbeaf6c0SSean Eric Fagan fprintf(stderr, "process exited before exec'ing\n"); 74bbeaf6c0SSean Eric Fagan ioctl(fd, PIOCCONT, &zero); 75bbeaf6c0SSean Eric Fagan wait(0); 76bbeaf6c0SSean Eric Fagan exit(7); 77bbeaf6c0SSean Eric Fagan } 78bbeaf6c0SSean Eric Fagan close(fd); 79bbeaf6c0SSean Eric Fagan return pid; 80bbeaf6c0SSean Eric Fagan } 81bbeaf6c0SSean Eric Fagan 82bbeaf6c0SSean Eric Fagan /* 83bbeaf6c0SSean Eric Fagan * start_tracing picks up where setup_and_wait() dropped off -- namely, 84bbeaf6c0SSean Eric Fagan * it sets the event mask for the given process id. Called for both 85bbeaf6c0SSean Eric Fagan * monitoring an existing process and when we create our own. 86bbeaf6c0SSean Eric Fagan */ 87bbeaf6c0SSean Eric Fagan 88bbeaf6c0SSean Eric Fagan int 89bbeaf6c0SSean Eric Fagan start_tracing(int pid, int flags) { 90bbeaf6c0SSean Eric Fagan int fd; 91bbeaf6c0SSean Eric Fagan char buf[32]; 92bbeaf6c0SSean Eric Fagan struct procfs_status tmp; 93bbeaf6c0SSean Eric Fagan sprintf(buf, "/proc/%d/mem", pid); 94bbeaf6c0SSean Eric Fagan fd = open(buf, O_RDWR); 95bbeaf6c0SSean Eric Fagan if (fd == -1) 96bbeaf6c0SSean Eric Fagan err(8, "cannot open %s", buf); 97bbeaf6c0SSean Eric Fagan 98bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { 99bbeaf6c0SSean Eric Fagan err(10, "cannot get procfs status struct"); 100bbeaf6c0SSean Eric Fagan } 101bbeaf6c0SSean Eric Fagan evflags = tmp.events; 102bbeaf6c0SSean Eric Fagan 103bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCBIS, &flags) == -1) 104bbeaf6c0SSean Eric Fagan err(9, "cannot set procfs event bit mask"); 105bbeaf6c0SSean Eric Fagan 106bbeaf6c0SSean Eric Fagan return fd; 107bbeaf6c0SSean Eric Fagan } 108bbeaf6c0SSean Eric Fagan 109bbeaf6c0SSean Eric Fagan /* 110bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 111bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 112bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 113bbeaf6c0SSean Eric Fagan * process. 114bbeaf6c0SSean Eric Fagan */ 115bbeaf6c0SSean Eric Fagan void 116bbeaf6c0SSean Eric Fagan restore_proc(int signo) { 117bbeaf6c0SSean Eric Fagan extern int Procfd; 118bbeaf6c0SSean Eric Fagan int i; 119bbeaf6c0SSean Eric Fagan 120bbeaf6c0SSean Eric Fagan i = ~0; 121bbeaf6c0SSean Eric Fagan ioctl(Procfd, PIOCBIC, &i); 122bbeaf6c0SSean Eric Fagan if (evflags) 123bbeaf6c0SSean Eric Fagan ioctl(Procfd, PIOCBIS, &evflags); 124bbeaf6c0SSean Eric Fagan exit(0); 125bbeaf6c0SSean Eric Fagan } 126