166550Snyan/*- 266550Snyan * Copyright 1997 Sean Eric Fagan 366550Snyan * 466550Snyan * Redistribution and use in source and binary forms, with or without 5139749Simp * modification, are permitted provided that the following conditions 666550Snyan * are met: 766550Snyan * 1. Redistributions of source code must retain the above copyright 866550Snyan * notice, this list of conditions and the following disclaimer. 9139749Simp * 2. Redistributions in binary form must reproduce the above copyright 1066550Snyan * notice, this list of conditions and the following disclaimer in the 1166550Snyan * documentation and/or other materials provided with the distribution. 1266550Snyan * 3. All advertising materials mentioning features or use of this software 1366550Snyan * must display the following acknowledgement: 1466550Snyan * This product includes software developed by Sean Eric Fagan 1566550Snyan * 4. Neither the name of the author may be used to endorse or promote 1666550Snyan * products derived from this software without specific prior written 1766550Snyan * permission. 1866550Snyan * 1966550Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2066550Snyan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2166550Snyan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2266550Snyan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2366550Snyan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2466550Snyan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2566550Snyan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2666550Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2766550Snyan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2866550Snyan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2966550Snyan * SUCH DAMAGE. 3066550Snyan */ 3166550Snyan 3266550Snyan#include <sys/cdefs.h> 3366550Snyan__FBSDID("$FreeBSD$"); 3466550Snyan 3566550Snyan/* 3666550Snyan * Various setup functions for truss. Not the cleanest-written code, 3766550Snyan * I'm afraid. 3866550Snyan */ 3966550Snyan 4066550Snyan#include <sys/param.h> 4166550Snyan#include <sys/types.h> 4266550Snyan#include <sys/ptrace.h> 4366550Snyan#include <sys/wait.h> 4466550Snyan 4566550Snyan#include <err.h> 4666550Snyan#include <errno.h> 4766550Snyan#include <fcntl.h> 4866550Snyan#include <signal.h> 4966550Snyan#include <stdio.h> 5066550Snyan#include <stdlib.h> 5166550Snyan#include <string.h> 5266550Snyan#include <time.h> 5366550Snyan#include <unistd.h> 5466550Snyan 5566550Snyan#include <machine/reg.h> 5666550Snyan 5766550Snyan#include "truss.h" 5866550Snyan#include "extern.h" 5966550Snyan 6066550Snyanstatic sig_atomic_t detaching; 6166550Snyan 6266550Snyan/* 6366550Snyan * setup_and_wait() is called to start a process. All it really does 6466550Snyan * is fork(), set itself up to stop on exec or exit, and then exec 6566550Snyan * the given command. At that point, the child process stops, and 6666550Snyan * the parent can wake up and deal with it. 6766550Snyan */ 6866550Snyan 6966550Snyanint 7066550Snyansetup_and_wait(char *command[]) 7166550Snyan{ 7266550Snyan pid_t pid; 7366550Snyan 7466550Snyan pid = vfork(); 7566550Snyan if (pid == -1) 7666550Snyan err(1, "fork failed"); 7766550Snyan if (pid == 0) { /* Child */ 7866550Snyan ptrace(PT_TRACE_ME, 0, 0, 0); 7966550Snyan execvp(command[0], command); 8066550Snyan err(1, "execvp %s", command[0]); 8166550Snyan } 8266550Snyan 8366550Snyan /* Only in the parent here */ 8466550Snyan if (waitpid(pid, NULL, 0) < 0) 8566550Snyan err(1, "unexpect stop in waitpid"); 8666550Snyan 8766550Snyan return (pid); 8866550Snyan} 8966550Snyan 9066550Snyan/* 9166550Snyan * start_tracing picks up where setup_and_wait() dropped off -- namely, 9266550Snyan * it sets the event mask for the given process id. Called for both 9366550Snyan * monitoring an existing process and when we create our own. 9466550Snyan */ 9566550Snyan 9666550Snyanint 9766550Snyanstart_tracing(pid_t pid) 9866550Snyan{ 9966550Snyan int ret, retry; 10066550Snyan 10166550Snyan retry = 10; 10266550Snyan do { 10366550Snyan ret = ptrace(PT_ATTACH, pid, NULL, 0); 10466550Snyan usleep(200); 10566550Snyan } while (ret && retry-- > 0); 10666550Snyan if (ret) 10766550Snyan err(1, "can not attach to target process"); 108147256Sbrooks 10966550Snyan if (waitpid(pid, NULL, 0) < 0) 11066550Snyan err(1, "Unexpect stop in waitpid"); 11166550Snyan 11266550Snyan return (0); 11366550Snyan} 11466550Snyan 11566550Snyan/* 11666550Snyan * Restore a process back to it's pre-truss state. 11766550Snyan * Called for SIGINT, SIGTERM, SIGQUIT. This only 11866550Snyan * applies if truss was told to monitor an already-existing 11966550Snyan * process. 12066550Snyan */ 12166550Snyan 12266550Snyanvoid 12366550Snyanrestore_proc(int signo __unused) 12466550Snyan{ 12566550Snyan 12666550Snyan detaching = 1; 12766550Snyan} 12866550Snyan 12966550Snyanstatic int 13066550Snyandetach_proc(pid_t pid) 13166550Snyan{ 13266550Snyan int waitval; 13366550Snyan 13466550Snyan /* stop the child so that we can detach */ 13566550Snyan kill(pid, SIGSTOP); 13666550Snyan if (waitpid(pid, &waitval, 0) < 0) 13766550Snyan err(1, "Unexpected stop in waitpid"); 13866550Snyan 13966550Snyan if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) 14066550Snyan err(1, "Can not detach the process"); 14166550Snyan 14266550Snyan kill(pid, SIGCONT); 14366550Snyan 14466550Snyan return (waitval); 14566550Snyan} 14666550Snyan 14766550Snyan/* 14866550Snyan * Change curthread member based on lwpid. 14966550Snyan * If it is a new thread, create a threadinfo structure 15066550Snyan */ 15166550Snyanstatic void 15266550Snyanfind_thread(struct trussinfo *info, lwpid_t lwpid) 15366550Snyan{ 15466550Snyan struct threadinfo *np; 15566550Snyan 15666550Snyan info->curthread = NULL; 15766550Snyan SLIST_FOREACH(np, &info->threadlist, entries) { 15866550Snyan if (np->tid == lwpid) { 15966550Snyan info->curthread = np; 16066550Snyan return; 16166550Snyan } 16292739Salfred } 16366550Snyan 16492739Salfred np = (struct threadinfo *)calloc(1, sizeof(struct threadinfo)); 16566550Snyan if (np == NULL) 16666550Snyan err(1, "calloc() failed"); 16766550Snyan np->tid = lwpid; 16866550Snyan SLIST_INSERT_HEAD(&info->threadlist, np, entries); 16966550Snyan info->curthread = np; 17066550Snyan} 17166550Snyan 17266550Snyan/* 17366550Snyan * Start the traced process and wait until it stoped. 17492739Salfred * Fill trussinfo structure. 17566550Snyan * When this even returns, the traced process is in stop state. 17692739Salfred */ 17766550Snyanvoid 17892739Salfredwaitevent(struct trussinfo *info) 17966550Snyan{ 18092739Salfred struct ptrace_lwpinfo lwpinfo; 18166550Snyan static int pending_signal = 0; 18292739Salfred int waitval; 18366550Snyan 18466550Snyan ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal); 18566550Snyan pending_signal = 0; 18666550Snyan 18766550Snyandetach: 18866550Snyan if (detaching) { 18966550Snyan waitval = detach_proc(info->pid); 19066550Snyan info->pr_why = S_DETACHED; 19192739Salfred info->pr_data = WEXITSTATUS(waitval); 19292739Salfred return; 19392739Salfred } 19492739Salfred 19566550Snyan if (waitpid(info->pid, &waitval, 0) == -1) { 19666550Snyan if (errno == EINTR) 19766550Snyan goto detach; 19892739Salfred err(1, "Unexpected stop in waitpid"); 19992739Salfred } 20066550Snyan 20166550Snyan if (WIFCONTINUED(waitval)) { 20266550Snyan info->pr_why = S_NONE; 203181298Sjhb return; 204181298Sjhb } 205181298Sjhb if (WIFEXITED(waitval)) { 20666550Snyan info->pr_why = S_EXIT; 20766550Snyan info->pr_data = WEXITSTATUS(waitval); 208181298Sjhb return; 209181298Sjhb } 210181298Sjhb if (WIFSTOPPED(waitval)) { 211181298Sjhb ptrace(PT_LWPINFO, info->pid, (caddr_t)&lwpinfo, 21266550Snyan sizeof(lwpinfo)); 21366550Snyan find_thread(info, lwpinfo.pl_lwpid); 21466550Snyan switch (WSTOPSIG(waitval)) { 21566550Snyan case SIGTRAP: 21666550Snyan if (lwpinfo.pl_flags & PL_FLAG_SCE) { 21766550Snyan info->pr_why = S_SCE; 21866550Snyan info->curthread->in_syscall = 1; 21966550Snyan break; 22066550Snyan } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { 22166550Snyan info->pr_why = S_SCX; 22266550Snyan info->curthread->in_syscall = 0; 22366550Snyan break; 22466550Snyan } else { 22566550Snyan errx(1, 22666550Snyan "pl_flags %x contains neither PL_FLAG_SCE nor PL_FLAG_SCX", 22766550Snyan lwpinfo.pl_flags); 22866550Snyan } 22966550Snyan default: 23066550Snyan info->pr_why = S_SIG; 23166550Snyan info->pr_data = WSTOPSIG(waitval); 23266550Snyan pending_signal = info->pr_data; 23366550Snyan break; 23466550Snyan } 23566550Snyan } 23666550Snyan if (WIFSIGNALED(waitval)) { 23766550Snyan info->pr_why = S_EXIT; 23866550Snyan info->pr_data = 0; 23966550Snyan return; 24066550Snyan } 24166550Snyan} 24266550Snyan