2 * Copyright 1997 Sean Eric Fagan
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Sean Eric Fagan
15 * 4. Neither the name of the author may be used to endorse or promote
16 * products derived from this software without specific prior written
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
36 * Various setup functions for truss. Not the cleanest-written code,
40 #include <sys/param.h>
41 #include <sys/types.h>
42 #include <sys/ptrace.h>
55 #include <machine/reg.h>
60 static sig_atomic_t detaching;
63 * setup_and_wait() is called to start a process. All it really does
64 * is fork(), set itself up to stop on exec or exit, and then exec
65 * the given command. At that point, the child process stops, and
66 * the parent can wake up and deal with it.
70 setup_and_wait(char *command[])
76 err(1, "fork failed");
77 if (pid == 0) { /* Child */
78 ptrace(PT_TRACE_ME, 0, 0, 0);
79 execvp(command[0], command);
80 err(1, "execvp %s", command[0]);
83 /* Only in the parent here */
84 if (waitpid(pid, NULL, 0) < 0)
85 err(1, "unexpect stop in waitpid");
91 * start_tracing picks up where setup_and_wait() dropped off -- namely,
92 * it sets the event mask for the given process id. Called for both
93 * monitoring an existing process and when we create our own.
97 start_tracing(pid_t pid)
103 ret = ptrace(PT_ATTACH, pid, NULL, 0);
105 } while (ret && retry-- > 0);
107 err(1, "can not attach to target process");
109 if (waitpid(pid, NULL, 0) < 0)
110 err(1, "Unexpect stop in waitpid");
116 * Restore a process back to it's pre-truss state.
117 * Called for SIGINT, SIGTERM, SIGQUIT. This only
118 * applies if truss was told to monitor an already-existing
123 restore_proc(int signo __unused)
130 detach_proc(pid_t pid)
134 /* stop the child so that we can detach */
136 if (waitpid(pid, &waitval, 0) < 0)
137 err(1, "Unexpected stop in waitpid");
139 if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0)
140 err(1, "Can not detach the process");
148 * Change curthread member based on lwpid.
149 * If it is a new thread, create a threadinfo structure
152 find_thread(struct trussinfo *info, lwpid_t lwpid)
154 struct threadinfo *np;
156 info->curthread = NULL;
157 SLIST_FOREACH(np, &info->threadlist, entries) {
158 if (np->tid == lwpid) {
159 info->curthread = np;
164 np = (struct threadinfo *)calloc(1, sizeof(struct threadinfo));
166 err(1, "calloc() failed");
168 SLIST_INSERT_HEAD(&info->threadlist, np, entries);
169 info->curthread = np;
173 * Start the traced process and wait until it stoped.
174 * Fill trussinfo structure.
175 * When this even returns, the traced process is in stop state.
178 waitevent(struct trussinfo *info)
180 struct ptrace_lwpinfo lwpinfo;
181 static int pending_signal = 0;
184 ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal);
189 waitval = detach_proc(info->pid);
190 info->pr_why = S_DETACHED;
191 info->pr_data = WEXITSTATUS(waitval);
195 if (waitpid(info->pid, &waitval, 0) == -1) {
198 err(1, "Unexpected stop in waitpid");
201 if (WIFCONTINUED(waitval)) {
202 info->pr_why = S_NONE;
205 if (WIFEXITED(waitval)) {
206 info->pr_why = S_EXIT;
207 info->pr_data = WEXITSTATUS(waitval);
210 if (WIFSTOPPED(waitval)) {
211 ptrace(PT_LWPINFO, info->pid, (caddr_t)&lwpinfo,
213 find_thread(info, lwpinfo.pl_lwpid);
214 switch (WSTOPSIG(waitval)) {
216 if (lwpinfo.pl_flags & PL_FLAG_SCE) {
217 info->pr_why = S_SCE;
218 info->curthread->in_syscall = 1;
220 } else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
221 info->pr_why = S_SCX;
222 info->curthread->in_syscall = 0;
226 "pl_flags %x contains neither PL_FLAG_SCE nor PL_FLAG_SCX",
230 info->pr_why = S_SIG;
231 info->pr_data = WSTOPSIG(waitval);
232 pending_signal = info->pr_data;
236 if (WIFSIGNALED(waitval)) {
237 info->pr_why = S_EXIT;