1f0bcd5c3SXin LI /*- 209d64da3SSean Eric Fagan * Copryight 1997 Sean Eric Fagan 309d64da3SSean Eric Fagan * 409d64da3SSean Eric Fagan * Redistribution and use in source and binary forms, with or without 509d64da3SSean Eric Fagan * modification, are permitted provided that the following conditions 609d64da3SSean Eric Fagan * are met: 709d64da3SSean Eric Fagan * 1. Redistributions of source code must retain the above copyright 809d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer. 909d64da3SSean Eric Fagan * 2. Redistributions in binary form must reproduce the above copyright 1009d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer in the 1109d64da3SSean Eric Fagan * documentation and/or other materials provided with the distribution. 1209d64da3SSean Eric Fagan * 3. All advertising materials mentioning features or use of this software 1309d64da3SSean Eric Fagan * must display the following acknowledgement: 1409d64da3SSean Eric Fagan * This product includes software developed by Sean Eric Fagan 1509d64da3SSean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote 1609d64da3SSean Eric Fagan * products derived from this software without specific prior written 1709d64da3SSean Eric Fagan * permission. 1809d64da3SSean Eric Fagan * 1909d64da3SSean Eric Fagan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2009d64da3SSean Eric Fagan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2109d64da3SSean Eric Fagan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2209d64da3SSean Eric Fagan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2309d64da3SSean Eric Fagan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2409d64da3SSean Eric Fagan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2509d64da3SSean Eric Fagan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2609d64da3SSean Eric Fagan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2709d64da3SSean Eric Fagan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2809d64da3SSean Eric Fagan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2909d64da3SSean Eric Fagan * SUCH DAMAGE. 3009d64da3SSean Eric Fagan */ 3109d64da3SSean Eric Fagan 32b956c13cSPhilippe Charnier #include <sys/cdefs.h> 33b956c13cSPhilippe Charnier __FBSDID("$FreeBSD$"); 343cf51049SPhilippe Charnier 3509d64da3SSean Eric Fagan /* 36bbeaf6c0SSean Eric Fagan * Various setup functions for truss. Not the cleanest-written code, 37bbeaf6c0SSean Eric Fagan * I'm afraid. 38bbeaf6c0SSean Eric Fagan */ 39bbeaf6c0SSean Eric Fagan 40580e0a2bSDag-Erling Smørgrav #include <sys/param.h> 415d2d083cSXin LI #include <sys/types.h> 425d2d083cSXin LI #include <sys/ptrace.h> 43580e0a2bSDag-Erling Smørgrav #include <sys/wait.h> 44580e0a2bSDag-Erling Smørgrav 453cf51049SPhilippe Charnier #include <err.h> 46821df508SXin LI #include <errno.h> 47821df508SXin LI #include <fcntl.h> 483cf51049SPhilippe Charnier #include <signal.h> 49bbeaf6c0SSean Eric Fagan #include <stdio.h> 50bbeaf6c0SSean Eric Fagan #include <stdlib.h> 51821df508SXin LI #include <string.h> 52821df508SXin LI #include <time.h> 53bbeaf6c0SSean Eric Fagan #include <unistd.h> 54bbeaf6c0SSean Eric Fagan 555d2d083cSXin LI #include <machine/reg.h> 565d2d083cSXin LI 57ec0bed25SMatthew N. Dodd #include "truss.h" 581be5d704SMark Murray #include "extern.h" 591be5d704SMark Murray 605d2d083cSXin LI static int child_pid; 61bbeaf6c0SSean Eric Fagan 62bbeaf6c0SSean Eric Fagan /* 63bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does 641fd98d7dSDag-Erling Smørgrav * is fork(), set itself up to stop on exec or exit, and then exec 65bbeaf6c0SSean Eric Fagan * the given command. At that point, the child process stops, and 66bbeaf6c0SSean Eric Fagan * the parent can wake up and deal with it. 67bbeaf6c0SSean Eric Fagan */ 68bbeaf6c0SSean Eric Fagan 69bbeaf6c0SSean Eric Fagan int 705321ae86SAlfred Perlstein setup_and_wait(char *command[]) 715321ae86SAlfred Perlstein { 72bbeaf6c0SSean Eric Fagan int pid; 735d2d083cSXin LI int waitval; 74bbeaf6c0SSean Eric Fagan 755d2d083cSXin LI pid = vfork(); 76bbeaf6c0SSean Eric Fagan if (pid == -1) { 771fd98d7dSDag-Erling Smørgrav err(1, "fork failed"); 78bbeaf6c0SSean Eric Fagan } 79bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 805d2d083cSXin LI ptrace(PT_TRACE_ME, 0, 0, 0); 815d2d083cSXin LI setpgid (0, 0); 82bbeaf6c0SSean Eric Fagan execvp(command[0], command); 835d2d083cSXin LI err(1, "execvp %s", command[0]); 84bbeaf6c0SSean Eric Fagan } 855d2d083cSXin LI 86bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 875d2d083cSXin LI if (waitpid(pid, &waitval, 0) < -1) { 885d2d083cSXin LI err(1, "unexpect stop in waitpid"); 895d2d083cSXin LI return 0; 90bbeaf6c0SSean Eric Fagan } 91bbeaf6c0SSean Eric Fagan 925d2d083cSXin LI child_pid = pid; 93081e5c48SPav Lucistnik 945321ae86SAlfred Perlstein return (pid); 95bbeaf6c0SSean Eric Fagan } 96bbeaf6c0SSean Eric Fagan 97bbeaf6c0SSean Eric Fagan /* 98bbeaf6c0SSean Eric Fagan * start_tracing picks up where setup_and_wait() dropped off -- namely, 99bbeaf6c0SSean Eric Fagan * it sets the event mask for the given process id. Called for both 100bbeaf6c0SSean Eric Fagan * monitoring an existing process and when we create our own. 101bbeaf6c0SSean Eric Fagan */ 102bbeaf6c0SSean Eric Fagan 103bbeaf6c0SSean Eric Fagan int 1045d2d083cSXin LI start_tracing(int pid) 1055321ae86SAlfred Perlstein { 1065d2d083cSXin LI int waitval; 1075d2d083cSXin LI int ret; 1085d2d083cSXin LI int retry = 10; 1095321ae86SAlfred Perlstein 1105d2d083cSXin LI do { 1115d2d083cSXin LI ret = ptrace(PT_ATTACH, pid, NULL, 0); 1125d2d083cSXin LI usleep(200); 1135d2d083cSXin LI } while(ret && retry-- > 0); 1145d2d083cSXin LI if (ret) 1155d2d083cSXin LI err(1, "can not attach to target process"); 11620fa828fSSean Eric Fagan 1175d2d083cSXin LI child_pid = pid; 1185d2d083cSXin LI if (waitpid(pid, &waitval, 0) < -1) 1195d2d083cSXin LI err(1, "Unexpect stop in waitpid"); 120bbeaf6c0SSean Eric Fagan 1215d2d083cSXin LI return (0); 122bbeaf6c0SSean Eric Fagan } 123bbeaf6c0SSean Eric Fagan 124bbeaf6c0SSean Eric Fagan /* 125bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 126bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 127bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 128bbeaf6c0SSean Eric Fagan * process. 129bbeaf6c0SSean Eric Fagan */ 130bbeaf6c0SSean Eric Fagan void 1315d2d083cSXin LI restore_proc(int signo __unused) 1325d2d083cSXin LI { 1335d2d083cSXin LI int waitval; 134bbeaf6c0SSean Eric Fagan 1355d2d083cSXin LI /* stop the child so that we can detach */ 1365d2d083cSXin LI kill(child_pid, SIGSTOP); 1375d2d083cSXin LI if (waitpid(child_pid, &waitval, 0) < -1) 1385d2d083cSXin LI err(1, "Unexpected stop in waitpid"); 1395d2d083cSXin LI 1405d2d083cSXin LI if (ptrace(PT_DETACH, child_pid, (caddr_t)1, 0) < 0) 1415d2d083cSXin LI err(1, "Can not detach the process"); 1425d2d083cSXin LI 1435d2d083cSXin LI kill(child_pid, SIGCONT); 144bbeaf6c0SSean Eric Fagan exit(0); 145bbeaf6c0SSean Eric Fagan } 1465d2d083cSXin LI 1475d2d083cSXin LI /* 1485d2d083cSXin LI * Change curthread member based on lwpid. 1495d2d083cSXin LI * If it is a new thread, create a threadinfo structure 1505d2d083cSXin LI */ 1515d2d083cSXin LI static void 1525d2d083cSXin LI find_thread(struct trussinfo *info, lwpid_t lwpid) 1535d2d083cSXin LI { 1545d2d083cSXin LI info->curthread = NULL; 1555d2d083cSXin LI struct threadinfo *np; 1565d2d083cSXin LI SLIST_FOREACH(np, &info->threadlist, entries) { 1575d2d083cSXin LI if (np->tid == lwpid) { 1585d2d083cSXin LI info->curthread = np; 1595d2d083cSXin LI return; 1605d2d083cSXin LI } 1615d2d083cSXin LI } 1625d2d083cSXin LI 1635d2d083cSXin LI np = (struct threadinfo *)malloc(sizeof(struct threadinfo)); 1645d2d083cSXin LI if (np == NULL) 1655d2d083cSXin LI errx(1, "malloc() failed"); 1665d2d083cSXin LI np->tid = lwpid; 1675d2d083cSXin LI np->in_fork = 0; 1685d2d083cSXin LI np->in_syscall = 0; 1695d2d083cSXin LI SLIST_INSERT_HEAD(&info->threadlist, np, entries); 1705d2d083cSXin LI info->curthread = np; 1715d2d083cSXin LI } 1725d2d083cSXin LI 1735d2d083cSXin LI /* 1745d2d083cSXin LI * Start the traced process and wait until it stoped. 1755d2d083cSXin LI * Fill trussinfo structure. 1765d2d083cSXin LI * When this even returns, the traced process is in stop state. 1775d2d083cSXin LI */ 1785d2d083cSXin LI void 1795d2d083cSXin LI waitevent(struct trussinfo *info) 1805d2d083cSXin LI { 1815d2d083cSXin LI int waitval; 1825d2d083cSXin LI static int pending_signal = 0; 1835d2d083cSXin LI 1845d2d083cSXin LI ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal); 1855d2d083cSXin LI pending_signal = 0; 1865d2d083cSXin LI 1875d2d083cSXin LI if (waitpid(info->pid, &waitval, 0) < -1) { 1885d2d083cSXin LI err(1, "Unexpected stop in waitpid"); 1895d2d083cSXin LI } 1905d2d083cSXin LI 1915d2d083cSXin LI if (WIFCONTINUED(waitval)) { 1925d2d083cSXin LI info->pr_why = S_NONE; 1935d2d083cSXin LI return; 1945d2d083cSXin LI } 1955d2d083cSXin LI if (WIFEXITED(waitval)) { 1965d2d083cSXin LI info->pr_why = S_EXIT; 1975d2d083cSXin LI info->pr_data = WEXITSTATUS(waitval); 1985d2d083cSXin LI return; 1995d2d083cSXin LI } 200ef29ac7fSXin LI if (WIFSTOPPED(waitval)) { 2015d2d083cSXin LI struct ptrace_lwpinfo lwpinfo; 2025d2d083cSXin LI ptrace(PT_LWPINFO, info->pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)); 2035d2d083cSXin LI find_thread(info, lwpinfo.pl_lwpid); 2045d2d083cSXin LI switch(WSTOPSIG(waitval)) { 2055d2d083cSXin LI case SIGTRAP: 2065d2d083cSXin LI info->pr_why = info->curthread->in_syscall?S_SCX:S_SCE; 2075d2d083cSXin LI info->curthread->in_syscall = 1 - info->curthread->in_syscall; 2085d2d083cSXin LI break; 2095d2d083cSXin LI default: 2105d2d083cSXin LI info->pr_why = S_SIG; 2115d2d083cSXin LI info->pr_data = WSTOPSIG(waitval); 2125d2d083cSXin LI pending_signal = info->pr_data; 2135d2d083cSXin LI break; 2145d2d083cSXin LI } 2155d2d083cSXin LI } 216ef29ac7fSXin LI if (WIFSIGNALED(waitval)) { 217ef29ac7fSXin LI info->pr_why = S_EXIT; 218f0bcd5c3SXin LI info->pr_data = 0; 219ef29ac7fSXin LI return; 220ef29ac7fSXin LI } 2215d2d083cSXin LI } 222