setup.c revision 298410
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: stable/10/usr.bin/truss/setup.c 298410 2016-04-21 15:25:17Z jhb $");
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
442static void
443report_exit(struct trussinfo *info, siginfo_t *si)
444{
445	struct timespec timediff;
446
447	if (info->flags & FOLLOWFORKS)
448		fprintf(info->outfile, "%5d: ", si->si_pid);
449	clock_gettime(CLOCK_REALTIME, &info->curthread->after);
450	if (info->flags & ABSOLUTETIMESTAMPS) {
451		timespecsubt(&info->curthread->after, &info->start_time,
452		    &timediff);
453		fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
454		    timediff.tv_nsec);
455	}
456	if (info->flags & RELATIVETIMESTAMPS) {
457		timespecsubt(&info->curthread->after, &info->curthread->before,
458		    &timediff);
459		fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
460		    timediff.tv_nsec);
461	}
462	if (si->si_code == CLD_EXITED)
463		fprintf(info->outfile, "process exit, rval = %u\n",
464		    si->si_status);
465	else
466		fprintf(info->outfile, "process killed, signal = %u%s\n",
467		    si->si_status, si->si_code == CLD_DUMPED ?
468		    " (core dumped)" : "");
469}
470
471static void
472report_new_child(struct trussinfo *info, pid_t pid)
473{
474	struct timespec timediff;
475
476	clock_gettime(CLOCK_REALTIME, &info->curthread->after);
477	assert(info->flags & FOLLOWFORKS);
478	fprintf(info->outfile, "%5d: ", pid);
479	if (info->flags & ABSOLUTETIMESTAMPS) {
480		timespecsubt(&info->curthread->after, &info->start_time,
481		    &timediff);
482		fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
483		    timediff.tv_nsec);
484	}
485	if (info->flags & RELATIVETIMESTAMPS) {
486		timediff.tv_sec = 0;
487		timediff.tv_nsec = 0;
488		fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
489		    timediff.tv_nsec);
490	}
491	fprintf(info->outfile, "<new process>\n");
492}
493
494static void
495report_signal(struct trussinfo *info, siginfo_t *si)
496{
497	struct timespec timediff;
498	char *signame;
499
500	if (info->flags & FOLLOWFORKS)
501		fprintf(info->outfile, "%5d: ", si->si_pid);
502	if (info->flags & ABSOLUTETIMESTAMPS) {
503		timespecsubt(&info->curthread->after, &info->start_time,
504		    &timediff);
505		fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
506		    timediff.tv_nsec);
507	}
508	if (info->flags & RELATIVETIMESTAMPS) {
509		timespecsubt(&info->curthread->after, &info->curthread->before,
510		    &timediff);
511		fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
512		    timediff.tv_nsec);
513	}
514	signame = strsig(si->si_status);
515	fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status,
516	    signame == NULL ? "?" : signame);
517}
518
519/*
520 * Wait for events until all the processes have exited or truss has been
521 * asked to stop.
522 */
523void
524eventloop(struct trussinfo *info)
525{
526	struct ptrace_lwpinfo pl;
527	siginfo_t si;
528	int pending_signal;
529
530	while (!LIST_EMPTY(&info->proclist)) {
531		if (detaching) {
532			detach_all_procs(info);
533			return;
534		}
535
536		if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) {
537			if (errno == EINTR)
538				continue;
539			err(1, "Unexpected error from waitid");
540		}
541
542		assert(si.si_signo == SIGCHLD);
543
544		switch (si.si_code) {
545		case CLD_EXITED:
546		case CLD_KILLED:
547		case CLD_DUMPED:
548			find_exit_thread(info, si.si_pid);
549			if ((info->flags & COUNTONLY) == 0)
550				report_exit(info, &si);
551			free_proc(info->curthread->proc);
552			info->curthread = NULL;
553			break;
554		case CLD_TRAPPED:
555			if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl,
556			    sizeof(pl)) == -1)
557				err(1, "ptrace(PT_LWPINFO)");
558
559			if (pl.pl_flags & PL_FLAG_CHILD) {
560				new_proc(info, si.si_pid);
561				assert(LIST_FIRST(&info->proclist)->abi !=
562				    NULL);
563			}
564			find_thread(info, si.si_pid, pl.pl_lwpid);
565
566			if (si.si_status == SIGTRAP &&
567			    (pl.pl_flags & (PL_FLAG_SCE|PL_FLAG_SCX)) != 0) {
568				if (pl.pl_flags & PL_FLAG_SCE)
569					enter_syscall(info, &pl);
570				else if (pl.pl_flags & PL_FLAG_SCX)
571					exit_syscall(info, &pl);
572				pending_signal = 0;
573			} else if (pl.pl_flags & PL_FLAG_CHILD) {
574				if ((info->flags & COUNTONLY) == 0)
575					report_new_child(info, si.si_pid);
576				pending_signal = 0;
577			} else {
578				if ((info->flags & NOSIGS) == 0)
579					report_signal(info, &si);
580				pending_signal = si.si_status;
581			}
582			ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1,
583			    pending_signal);
584			break;
585		case CLD_STOPPED:
586			errx(1, "waitid reported CLD_STOPPED");
587		case CLD_CONTINUED:
588			break;
589		}
590	}
591}
592