1f0bcd5c3SXin LI /*- 20a6c71f8SWarner Losh * Copyright 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 60be305c9cSAndrey Zonov static pid_t 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 { 72be305c9cSAndrey Zonov pid_t pid; 735d2d083cSXin LI int waitval; 74bbeaf6c0SSean Eric Fagan 755d2d083cSXin LI pid = vfork(); 76*94355cfdSAndrey Zonov if (pid == -1) 771fd98d7dSDag-Erling Smørgrav err(1, "fork failed"); 78bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 795d2d083cSXin LI ptrace(PT_TRACE_ME, 0, 0, 0); 80bbeaf6c0SSean Eric Fagan execvp(command[0], command); 815d2d083cSXin LI err(1, "execvp %s", command[0]); 82bbeaf6c0SSean Eric Fagan } 835d2d083cSXin LI 84bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 85ad018914SJohn Baldwin if (waitpid(pid, &waitval, 0) < 0) { 865d2d083cSXin LI err(1, "unexpect stop in waitpid"); 875d2d083cSXin LI return 0; 88bbeaf6c0SSean Eric Fagan } 89bbeaf6c0SSean Eric Fagan 905d2d083cSXin LI child_pid = pid; 91081e5c48SPav Lucistnik 925321ae86SAlfred Perlstein return (pid); 93bbeaf6c0SSean Eric Fagan } 94bbeaf6c0SSean Eric Fagan 95bbeaf6c0SSean Eric Fagan /* 96bbeaf6c0SSean Eric Fagan * start_tracing picks up where setup_and_wait() dropped off -- namely, 97bbeaf6c0SSean Eric Fagan * it sets the event mask for the given process id. Called for both 98bbeaf6c0SSean Eric Fagan * monitoring an existing process and when we create our own. 99bbeaf6c0SSean Eric Fagan */ 100bbeaf6c0SSean Eric Fagan 101bbeaf6c0SSean Eric Fagan int 102be305c9cSAndrey Zonov start_tracing(pid_t pid) 1035321ae86SAlfred Perlstein { 104*94355cfdSAndrey Zonov int ret, retry, waitval; 1055321ae86SAlfred Perlstein 106*94355cfdSAndrey Zonov retry = 10; 1075d2d083cSXin LI do { 1085d2d083cSXin LI ret = ptrace(PT_ATTACH, pid, NULL, 0); 1095d2d083cSXin LI usleep(200); 1105d2d083cSXin LI } while (ret && retry-- > 0); 1115d2d083cSXin LI if (ret) 1125d2d083cSXin LI err(1, "can not attach to target process"); 11320fa828fSSean Eric Fagan 1145d2d083cSXin LI child_pid = pid; 115ad018914SJohn Baldwin if (waitpid(pid, &waitval, 0) < 0) 1165d2d083cSXin LI err(1, "Unexpect stop in waitpid"); 117bbeaf6c0SSean Eric Fagan 1185d2d083cSXin LI return (0); 119bbeaf6c0SSean Eric Fagan } 120bbeaf6c0SSean Eric Fagan 121bbeaf6c0SSean Eric Fagan /* 122bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 123bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 124bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 125bbeaf6c0SSean Eric Fagan * process. 126bbeaf6c0SSean Eric Fagan */ 127bbeaf6c0SSean Eric Fagan void 1285d2d083cSXin LI restore_proc(int signo __unused) 1295d2d083cSXin LI { 1305d2d083cSXin LI int waitval; 131bbeaf6c0SSean Eric Fagan 1325d2d083cSXin LI /* stop the child so that we can detach */ 1335d2d083cSXin LI kill(child_pid, SIGSTOP); 134ad018914SJohn Baldwin if (waitpid(child_pid, &waitval, 0) < 0) 1355d2d083cSXin LI err(1, "Unexpected stop in waitpid"); 1365d2d083cSXin LI 1375d2d083cSXin LI if (ptrace(PT_DETACH, child_pid, (caddr_t)1, 0) < 0) 1385d2d083cSXin LI err(1, "Can not detach the process"); 1395d2d083cSXin LI 1405d2d083cSXin LI kill(child_pid, SIGCONT); 141bbeaf6c0SSean Eric Fagan exit(0); 142bbeaf6c0SSean Eric Fagan } 1435d2d083cSXin LI 1445d2d083cSXin LI /* 1455d2d083cSXin LI * Change curthread member based on lwpid. 1465d2d083cSXin LI * If it is a new thread, create a threadinfo structure 1475d2d083cSXin LI */ 1485d2d083cSXin LI static void 1495d2d083cSXin LI find_thread(struct trussinfo *info, lwpid_t lwpid) 1505d2d083cSXin LI { 1515d2d083cSXin LI struct threadinfo *np; 152*94355cfdSAndrey Zonov 153*94355cfdSAndrey Zonov info->curthread = NULL; 1545d2d083cSXin LI SLIST_FOREACH(np, &info->threadlist, entries) { 1555d2d083cSXin LI if (np->tid == lwpid) { 1565d2d083cSXin LI info->curthread = np; 1575d2d083cSXin LI return; 1585d2d083cSXin LI } 1595d2d083cSXin LI } 1605d2d083cSXin LI 1615d2d083cSXin LI np = (struct threadinfo *)malloc(sizeof(struct threadinfo)); 1625d2d083cSXin LI if (np == NULL) 1635d2d083cSXin LI errx(1, "malloc() failed"); 1645d2d083cSXin LI np->tid = lwpid; 1655d2d083cSXin LI np->in_fork = 0; 1665d2d083cSXin LI np->in_syscall = 0; 1675d2d083cSXin LI SLIST_INSERT_HEAD(&info->threadlist, np, entries); 1685d2d083cSXin LI info->curthread = np; 1695d2d083cSXin LI } 1705d2d083cSXin LI 1715d2d083cSXin LI /* 1725d2d083cSXin LI * Start the traced process and wait until it stoped. 1735d2d083cSXin LI * Fill trussinfo structure. 1745d2d083cSXin LI * When this even returns, the traced process is in stop state. 1755d2d083cSXin LI */ 1765d2d083cSXin LI void 1775d2d083cSXin LI waitevent(struct trussinfo *info) 1785d2d083cSXin LI { 179*94355cfdSAndrey Zonov struct ptrace_lwpinfo lwpinfo; 1805d2d083cSXin LI static int pending_signal = 0; 181*94355cfdSAndrey Zonov int waitval; 1825d2d083cSXin LI 1835d2d083cSXin LI ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal); 1845d2d083cSXin LI pending_signal = 0; 1855d2d083cSXin LI 186*94355cfdSAndrey Zonov if (waitpid(info->pid, &waitval, 0) < 0) 1875d2d083cSXin LI err(1, "Unexpected stop in waitpid"); 1885d2d083cSXin LI 1895d2d083cSXin LI if (WIFCONTINUED(waitval)) { 1905d2d083cSXin LI info->pr_why = S_NONE; 1915d2d083cSXin LI return; 1925d2d083cSXin LI } 1935d2d083cSXin LI if (WIFEXITED(waitval)) { 1945d2d083cSXin LI info->pr_why = S_EXIT; 1955d2d083cSXin LI info->pr_data = WEXITSTATUS(waitval); 1965d2d083cSXin LI return; 1975d2d083cSXin LI } 198ef29ac7fSXin LI if (WIFSTOPPED(waitval)) { 199*94355cfdSAndrey Zonov ptrace(PT_LWPINFO, info->pid, (caddr_t)&lwpinfo, 200*94355cfdSAndrey Zonov sizeof(lwpinfo)); 2015d2d083cSXin LI find_thread(info, lwpinfo.pl_lwpid); 2025d2d083cSXin LI switch (WSTOPSIG(waitval)) { 2035d2d083cSXin LI case SIGTRAP: 20497695ad4SKonstantin Belousov if (lwpinfo.pl_flags & PL_FLAG_SCE) { 20597695ad4SKonstantin Belousov info->pr_why = S_SCE; 20697695ad4SKonstantin Belousov info->curthread->in_syscall = 1; 2075d2d083cSXin LI break; 20897695ad4SKonstantin Belousov } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { 20997695ad4SKonstantin Belousov info->pr_why = S_SCX; 21097695ad4SKonstantin Belousov info->curthread->in_syscall = 0; 21197695ad4SKonstantin Belousov break; 21297695ad4SKonstantin Belousov } else { 21397695ad4SKonstantin Belousov errx(1, 21497695ad4SKonstantin Belousov "pl_flags %x contains neither PL_FLAG_SCE nor PL_FLAG_SCX", 21597695ad4SKonstantin Belousov lwpinfo.pl_flags); 21697695ad4SKonstantin Belousov } 2175d2d083cSXin LI default: 2185d2d083cSXin LI info->pr_why = S_SIG; 2195d2d083cSXin LI info->pr_data = WSTOPSIG(waitval); 2205d2d083cSXin LI pending_signal = info->pr_data; 2215d2d083cSXin LI break; 2225d2d083cSXin LI } 2235d2d083cSXin LI } 224ef29ac7fSXin LI if (WIFSIGNALED(waitval)) { 225ef29ac7fSXin LI info->pr_why = S_EXIT; 226f0bcd5c3SXin LI info->pr_data = 0; 227ef29ac7fSXin LI return; 228ef29ac7fSXin LI } 2295d2d083cSXin LI } 230