1/*-
2 * Copyright 1997 Sean Eric Fagan
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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
17 *    permission.
18 *
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
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD$");
34
35/*
36 * Various setup functions for truss.  Not the cleanest-written code,
37 * I'm afraid.
38 */
39
40#include <sys/ptrace.h>
41#include <sys/sysctl.h>
42#include <sys/wait.h>
43
44#include <assert.h>
45#include <err.h>
46#include <errno.h>
47#include <signal.h>
48#include <stdint.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <time.h>
53#include <unistd.h>
54
55#include "truss.h"
56#include "syscall.h"
57#include "extern.h"
58
59SET_DECLARE(procabi, struct procabi);
60
61static sig_atomic_t detaching;
62
63static void	new_proc(struct trussinfo *, pid_t);
64
65/*
66 * setup_and_wait() is called to start a process.  All it really does
67 * is fork(), enable tracing in the child, and then exec the given
68 * command.  At that point, the child process stops, and the parent
69 * can wake up and deal with it.
70 */
71void
72setup_and_wait(struct trussinfo *info, char *command[])
73{
74	pid_t pid;
75
76	pid = vfork();
77	if (pid == -1)
78		err(1, "fork failed");
79	if (pid == 0) {	/* Child */
80		ptrace(PT_TRACE_ME, 0, 0, 0);
81		execvp(command[0], command);
82		err(1, "execvp %s", command[0]);
83	}
84
85	/* Only in the parent here */
86	if (waitpid(pid, NULL, 0) < 0)
87		err(1, "unexpect stop in waitpid");
88
89	new_proc(info, pid);
90}
91
92/*
93 * start_tracing is called to attach to an existing process.
94 */
95void
96start_tracing(struct trussinfo *info, pid_t pid)
97{
98	int ret, retry;
99
100	retry = 10;
101	do {
102		ret = ptrace(PT_ATTACH, pid, NULL, 0);
103		usleep(200);
104	} while (ret && retry-- > 0);
105	if (ret)
106		err(1, "can not attach to target process");
107
108	if (waitpid(pid, NULL, 0) < 0)
109		err(1, "Unexpect stop in waitpid");
110
111	new_proc(info, pid);
112}
113
114/*
115 * Restore a process back to it's pre-truss state.
116 * Called for SIGINT, SIGTERM, SIGQUIT.  This only
117 * applies if truss was told to monitor an already-existing
118 * process.
119 */
120void
121restore_proc(int signo __unused)
122{
123
124	detaching = 1;
125}
126
127static void
128detach_proc(pid_t pid)
129{
130
131	/* stop the child so that we can detach */
132	kill(pid, SIGSTOP);
133	if (waitpid(pid, NULL, 0) < 0)
134		err(1, "Unexpected stop in waitpid");
135
136	if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0)
137		err(1, "Can not detach the process");
138
139	kill(pid, SIGCONT);
140}
141
142/*
143 * Determine the ABI.  This is called after every exec, and when
144 * a process is first monitored.
145 */
146static struct procabi *
147find_abi(pid_t pid)
148{
149	struct procabi **pabi;
150	size_t len;
151	int error;
152	int mib[4];
153	char progt[32];
154
155	len = sizeof(progt);
156	mib[0] = CTL_KERN;
157	mib[1] = KERN_PROC;
158	mib[2] = KERN_PROC_SV_NAME;
159	mib[3] = pid;
160	error = sysctl(mib, 4, progt, &len, NULL, 0);
161	if (error != 0)
162		err(2, "can not get sysvec name");
163
164	SET_FOREACH(pabi, procabi) {
165		if (strcmp((*pabi)->type, progt) == 0)
166			return (*pabi);
167	}
168	warnx("ABI %s for pid %ld is not supported", progt, (long)pid);
169	return (NULL);
170}
171
172static void
173new_proc(struct trussinfo *info, pid_t pid)
174{
175	struct procinfo *np;
176
177	/*
178	 * If this happens it means there is a bug in truss.  Unfortunately
179	 * this will kill any processes are attached to.
180	 */
181	LIST_FOREACH(np, &info->proclist, entries) {
182		if (np->pid == pid)
183			errx(1, "Duplicate process for pid %ld", (long)pid);
184	}
185
186	if (info->flags & FOLLOWFORKS)
187		if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1)
188			err(1, "Unable to follow forks for pid %ld", (long)pid);
189	np = calloc(1, sizeof(struct procinfo));
190	np->pid = pid;
191	np->abi = find_abi(pid);
192	SLIST_INIT(&np->threadlist);
193	LIST_INSERT_HEAD(&info->proclist, np, entries);
194}
195
196static void
197free_proc(struct procinfo *p)
198{
199	struct threadinfo *t, *t2;
200
201	SLIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) {
202		free(t);
203	}
204	LIST_REMOVE(p, entries);
205	free(p);
206}
207
208static void
209detach_all_procs(struct trussinfo *info)
210{
211	struct procinfo *p, *p2;
212
213	LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) {
214		detach_proc(p->pid);
215		free_proc(p);
216	}
217}
218
219static struct procinfo *
220find_proc(struct trussinfo *info, pid_t pid)
221{
222	struct procinfo *np;
223
224	LIST_FOREACH(np, &info->proclist, entries) {
225		if (np->pid == pid)
226			return (np);
227	}
228
229	return (NULL);
230}
231
232/*
233 * Change curthread member based on (pid, lwpid).
234 * If it is a new thread, create a threadinfo structure.
235 */
236static void
237find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
238{
239	struct procinfo *np;
240	struct threadinfo *nt;
241
242	np = find_proc(info, pid);
243	assert(np != NULL);
244
245	SLIST_FOREACH(nt, &np->threadlist, entries) {
246		if (nt->tid == lwpid) {
247			info->curthread = nt;
248			return;
249		}
250	}
251
252	nt = calloc(1, sizeof(struct threadinfo));
253	if (nt == NULL)
254		err(1, "calloc() failed");
255	nt->proc = np;
256	nt->tid = lwpid;
257	SLIST_INSERT_HEAD(&np->threadlist, nt, entries);
258	info->curthread = nt;
259}
260
261/*
262 * When a process exits, it no longer has any threads left.  However,
263 * the main loop expects a valid curthread.  In cases when a thread
264 * triggers the termination (e.g. calling exit or triggering a fault)
265 * we would ideally use that thread.  However, if a process is killed
266 * by a signal sent from another process then there is no "correct"
267 * thread.  We just punt and use the first thread.
268 */
269static void
270find_exit_thread(struct trussinfo *info, pid_t pid)
271{
272	struct procinfo *np;
273	struct threadinfo *nt;
274
275	np = find_proc(info, pid);
276	assert(np != NULL);
277
278	if (SLIST_EMPTY(&np->threadlist)) {
279		/*
280		 * If an existing process exits right after we attach
281		 * to it but before it posts any events, there won't
282		 * be any threads.  Create a dummy thread and set its
283		 * "before" time to the global start time.
284		 */
285		nt = calloc(1, sizeof(struct threadinfo));
286		if (nt == NULL)
287			err(1, "calloc() failed");
288		nt->proc = np;
289		nt->tid = 0;
290		SLIST_INSERT_HEAD(&np->threadlist, nt, entries);
291		nt->before = info->start_time;
292	}
293	info->curthread = SLIST_FIRST(&np->threadlist);
294}
295
296static void
297alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl)
298{
299	u_int i;
300
301	assert(t->in_syscall == 0);
302	assert(t->cs.number == 0);
303	assert(t->cs.name == NULL);
304	assert(t->cs.nargs == 0);
305	for (i = 0; i < nitems(t->cs.s_args); i++)
306		assert(t->cs.s_args[i] == NULL);
307	memset(t->cs.args, 0, sizeof(t->cs.args));
308	t->cs.number = pl->pl_syscall_code;
309	t->in_syscall = 1;
310}
311
312static void
313free_syscall(struct threadinfo *t)
314{
315	u_int i;
316
317	for (i = 0; i < t->cs.nargs; i++)
318		free(t->cs.s_args[i]);
319	memset(&t->cs, 0, sizeof(t->cs));
320	t->in_syscall = 0;
321}
322
323static void
324enter_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
325{
326	struct threadinfo *t;
327	struct syscall *sc;
328	u_int i, narg;
329
330	t = info->curthread;
331	alloc_syscall(t, pl);
332	narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args));
333	if (narg != 0 && t->proc->abi->fetch_args(info, narg) != 0) {
334		free_syscall(t);
335		return;
336	}
337
338	if (t->cs.number >= 0 && t->cs.number < t->proc->abi->nsyscalls)
339		t->cs.name = t->proc->abi->syscallnames[t->cs.number];
340	if (t->cs.name == NULL)
341		fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n",
342		    t->proc->abi->type, t->cs.number);
343
344	sc = get_syscall(t->cs.name, narg);
345	t->cs.nargs = sc->nargs;
346	assert(sc->nargs <= nitems(t->cs.s_args));
347
348	t->cs.sc = sc;
349
350	/*
351	 * At this point, we set up the system call arguments.
352	 * We ignore any OUT ones, however -- those are arguments that
353	 * are set by the system call, and so are probably meaningless
354	 * now.	This doesn't currently support arguments that are
355	 * passed in *and* out, however.
356	 */
357	if (t->cs.name != NULL) {
358#if DEBUG
359		fprintf(stderr, "syscall %s(", t->cs.name);
360#endif
361		for (i = 0; i < t->cs.nargs; i++) {
362#if DEBUG
363			fprintf(stderr, "0x%lx%s", sc ?
364			    t->cs.args[sc->args[i].offset] : t->cs.args[i],
365			    i < (t->cs.nargs - 1) ? "," : "");
366#endif
367			if (!(sc->args[i].type & OUT)) {
368				t->cs.s_args[i] = print_arg(&sc->args[i],
369				    t->cs.args, 0, info);
370			}
371		}
372#if DEBUG
373		fprintf(stderr, ")\n");
374#endif
375	}
376
377	clock_gettime(CLOCK_REALTIME, &t->before);
378}
379
380static void
381exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
382{
383	struct threadinfo *t;
384	struct procinfo *p;
385	struct syscall *sc;
386	long retval[2];
387	u_int i;
388	int errorp;
389
390	t = info->curthread;
391	if (!t->in_syscall)
392		return;
393
394	clock_gettime(CLOCK_REALTIME, &t->after);
395	p = t->proc;
396	if (p->abi->fetch_retval(info, retval, &errorp) < 0) {
397		free_syscall(t);
398		return;
399	}
400
401	sc = t->cs.sc;
402	/*
403	 * Here, we only look for arguments that have OUT masked in --
404	 * otherwise, they were handled in enter_syscall().
405	 */
406	for (i = 0; i < sc->nargs; i++) {
407		char *temp;
408
409		if (sc->args[i].type & OUT) {
410			/*
411			 * If an error occurred, then don't bother
412			 * getting the data; it may not be valid.
413			 */
414			if (errorp) {
415				asprintf(&temp, "0x%lx",
416				    t->cs.args[sc->args[i].offset]);
417			} else {
418				temp = print_arg(&sc->args[i],
419				    t->cs.args, retval, info);
420			}
421			t->cs.s_args[i] = temp;
422		}
423	}
424
425	print_syscall_ret(info, errorp, retval);
426	free_syscall(t);
427
428	/*
429	 * If the process executed a new image, check the ABI.  If the
430	 * new ABI isn't supported, stop tracing this process.
431	 */
432	if (pl->pl_flags & PL_FLAG_EXEC) {
433		p->abi = find_abi(p->pid);
434		if (p->abi == NULL) {
435			if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0)
436				err(1, "Can not detach the process");
437			free_proc(p);
438		}
439	}
440}
441
442int
443print_line_prefix(struct trussinfo *info)
444{
445	struct timespec timediff;
446	struct threadinfo *t;
447	int len;
448
449	len = 0;
450	t = info->curthread;
451	if (info->flags & (FOLLOWFORKS | DISPLAYTIDS)) {
452		if (info->flags & FOLLOWFORKS)
453			len += fprintf(info->outfile, "%5d", t->proc->pid);
454		if ((info->flags & (FOLLOWFORKS | DISPLAYTIDS)) ==
455		    (FOLLOWFORKS | DISPLAYTIDS))
456			len += fprintf(info->outfile, " ");
457		if (info->flags & DISPLAYTIDS)
458			len += fprintf(info->outfile, "%6d", t->tid);
459		len += fprintf(info->outfile, ": ");
460	}
461	if (info->flags & ABSOLUTETIMESTAMPS) {
462		timespecsubt(&t->after, &info->start_time, &timediff);
463		len += fprintf(info->outfile, "%jd.%09ld ",
464		    (intmax_t)timediff.tv_sec, timediff.tv_nsec);
465	}
466	if (info->flags & RELATIVETIMESTAMPS) {
467		timespecsubt(&t->after, &t->before, &timediff);
468		len += fprintf(info->outfile, "%jd.%09ld ",
469		    (intmax_t)timediff.tv_sec, timediff.tv_nsec);
470	}
471	return (len);
472}
473
474static void
475report_exit(struct trussinfo *info, siginfo_t *si)
476{
477	struct threadinfo *t;
478
479	t = info->curthread;
480	clock_gettime(CLOCK_REALTIME, &t->after);
481	print_line_prefix(info);
482	if (si->si_code == CLD_EXITED)
483		fprintf(info->outfile, "process exit, rval = %u\n",
484		    si->si_status);
485	else
486		fprintf(info->outfile, "process killed, signal = %u%s\n",
487		    si->si_status, si->si_code == CLD_DUMPED ?
488		    " (core dumped)" : "");
489}
490
491static void
492report_new_child(struct trussinfo *info)
493{
494	struct threadinfo *t;
495
496	t = info->curthread;
497	clock_gettime(CLOCK_REALTIME, &t->after);
498	t->before = t->after;
499	print_line_prefix(info);
500	fprintf(info->outfile, "<new process>\n");
501}
502
503static void
504report_signal(struct trussinfo *info, siginfo_t *si)
505{
506	struct threadinfo *t;
507	char *signame;
508
509	t = info->curthread;
510	clock_gettime(CLOCK_REALTIME, &t->after);
511	print_line_prefix(info);
512	signame = strsig(si->si_status);
513	fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status,
514	    signame == NULL ? "?" : signame);
515}
516
517/*
518 * Wait for events until all the processes have exited or truss has been
519 * asked to stop.
520 */
521void
522eventloop(struct trussinfo *info)
523{
524	struct ptrace_lwpinfo pl;
525	siginfo_t si;
526	int pending_signal;
527
528	while (!LIST_EMPTY(&info->proclist)) {
529		if (detaching) {
530			detach_all_procs(info);
531			return;
532		}
533
534		if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) {
535			if (errno == EINTR)
536				continue;
537			err(1, "Unexpected error from waitid");
538		}
539
540		assert(si.si_signo == SIGCHLD);
541
542		switch (si.si_code) {
543		case CLD_EXITED:
544		case CLD_KILLED:
545		case CLD_DUMPED:
546			find_exit_thread(info, si.si_pid);
547			if ((info->flags & COUNTONLY) == 0)
548				report_exit(info, &si);
549			free_proc(info->curthread->proc);
550			info->curthread = NULL;
551			break;
552		case CLD_TRAPPED:
553			if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl,
554			    sizeof(pl)) == -1)
555				err(1, "ptrace(PT_LWPINFO)");
556
557			if (pl.pl_flags & PL_FLAG_CHILD) {
558				new_proc(info, si.si_pid);
559				assert(LIST_FIRST(&info->proclist)->abi !=
560				    NULL);
561			}
562			find_thread(info, si.si_pid, pl.pl_lwpid);
563
564			if (si.si_status == SIGTRAP &&
565			    (pl.pl_flags & (PL_FLAG_SCE|PL_FLAG_SCX)) != 0) {
566				if (pl.pl_flags & PL_FLAG_SCE)
567					enter_syscall(info, &pl);
568				else if (pl.pl_flags & PL_FLAG_SCX)
569					exit_syscall(info, &pl);
570				pending_signal = 0;
571			} else if (pl.pl_flags & PL_FLAG_CHILD) {
572				if ((info->flags & COUNTONLY) == 0)
573					report_new_child(info);
574				pending_signal = 0;
575			} else {
576				if ((info->flags & NOSIGS) == 0)
577					report_signal(info, &si);
578				pending_signal = si.si_status;
579			}
580			ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1,
581			    pending_signal);
582			break;
583		case CLD_STOPPED:
584			errx(1, "waitid reported CLD_STOPPED");
585		case CLD_CONTINUED:
586			break;
587		}
588	}
589}
590