1130394Sdwmalone/*
2204977Simp * Copyright 1997 Sean Eric Fagan
3130394Sdwmalone *
4130394Sdwmalone * Redistribution and use in source and binary forms, with or without
5130394Sdwmalone * modification, are permitted provided that the following conditions
6130394Sdwmalone * are met:
7130394Sdwmalone * 1. Redistributions of source code must retain the above copyright
8130394Sdwmalone *    notice, this list of conditions and the following disclaimer.
9130394Sdwmalone * 2. Redistributions in binary form must reproduce the above copyright
10130394Sdwmalone *    notice, this list of conditions and the following disclaimer in the
11130394Sdwmalone *    documentation and/or other materials provided with the distribution.
12130394Sdwmalone * 3. All advertising materials mentioning features or use of this software
13130394Sdwmalone *    must display the following acknowledgement:
14130394Sdwmalone *	This product includes software developed by Sean Eric Fagan
15130394Sdwmalone * 4. Neither the name of the author may be used to endorse or promote
16130394Sdwmalone *    products derived from this software without specific prior written
17130394Sdwmalone *    permission.
18130394Sdwmalone *
19130394Sdwmalone * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20130394Sdwmalone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21130394Sdwmalone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22130394Sdwmalone * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23130394Sdwmalone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24130394Sdwmalone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25130394Sdwmalone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26130394Sdwmalone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27130394Sdwmalone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28130394Sdwmalone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29130394Sdwmalone * SUCH DAMAGE.
30130394Sdwmalone */
31130394Sdwmalone
32130394Sdwmalone#ifndef lint
33130394Sdwmalonestatic const char rcsid[] =
34130421Sbms  "$FreeBSD$";
35130394Sdwmalone#endif /* not lint */
36130394Sdwmalone
37130394Sdwmalone/*
38130394Sdwmalone * FreeBSD/amd64-specific system call handling.  This is probably the most
39130394Sdwmalone * complex part of the entire truss program, although I've got lots of
40130394Sdwmalone * it handled relatively cleanly now.  The system call names are generated
41130394Sdwmalone * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
42130394Sdwmalone * names used for the various structures are confusing, I sadly admit.
43130394Sdwmalone */
44130394Sdwmalone
45130394Sdwmalone#include <sys/types.h>
46168569Sdelphij#include <sys/ptrace.h>
47130394Sdwmalone#include <sys/syscall.h>
48130394Sdwmalone
49130394Sdwmalone#include <machine/reg.h>
50130394Sdwmalone#include <machine/psl.h>
51130394Sdwmalone
52130394Sdwmalone#include <errno.h>
53130394Sdwmalone#include <fcntl.h>
54130394Sdwmalone#include <signal.h>
55130394Sdwmalone#include <stdio.h>
56130394Sdwmalone#include <stdlib.h>
57130394Sdwmalone#include <string.h>
58130394Sdwmalone#include <time.h>
59130394Sdwmalone#include <unistd.h>
60130394Sdwmalone
61130394Sdwmalone#include "truss.h"
62130394Sdwmalone#include "syscall.h"
63130394Sdwmalone#include "extern.h"
64130394Sdwmalone
65130394Sdwmalone#include "syscalls.h"
66130394Sdwmalone
67130394Sdwmalonestatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
68130394Sdwmalone
69130394Sdwmalone/*
70130394Sdwmalone * This is what this particular file uses to keep track of a system call.
71130394Sdwmalone * It is probably not quite sufficient -- I can probably use the same
72130394Sdwmalone * structure for the various syscall personalities, and I also probably
73130394Sdwmalone * need to nest system calls (for signal handlers).
74130394Sdwmalone *
75130394Sdwmalone * 'struct syscall' describes the system call; it may be NULL, however,
76130394Sdwmalone * if we don't know about this particular system call yet.
77130394Sdwmalone */
78240562Szontstruct freebsd_syscall {
79130394Sdwmalone	struct syscall *sc;
80130394Sdwmalone	const char *name;
81130394Sdwmalone	int number;
82130394Sdwmalone	unsigned long *args;
83130394Sdwmalone	int nargs;	/* number of arguments -- *not* number of words! */
84130394Sdwmalone	char **s_args;	/* the printable arguments */
85240562Szont};
86130394Sdwmalone
87240562Szontstatic struct freebsd_syscall *
88240562Szontalloc_fsc(void)
89240562Szont{
90240562Szont
91240562Szont	return (malloc(sizeof(struct freebsd_syscall)));
92240562Szont}
93240562Szont
94130394Sdwmalone/* Clear up and free parts of the fsc structure. */
95240562Szontstatic void
96240562Szontfree_fsc(struct freebsd_syscall *fsc)
97240005Szont{
98240005Szont	int i;
99240005Szont
100240562Szont	free(fsc->args);
101240562Szont	if (fsc->s_args) {
102240562Szont		for (i = 0; i < fsc->nargs; i++)
103240562Szont			free(fsc->s_args[i]);
104240562Szont		free(fsc->s_args);
105240005Szont	}
106240562Szont	free(fsc);
107130394Sdwmalone}
108130394Sdwmalone
109130394Sdwmalone/*
110130394Sdwmalone * Called when a process has entered a system call.  nargs is the
111130394Sdwmalone * number of words, not number of arguments (a necessary distinction
112130394Sdwmalone * in some cases).  Note that if the STOPEVENT() code in amd64/amd64/trap.c
113130394Sdwmalone * is ever changed these functions need to keep up.
114130394Sdwmalone */
115130394Sdwmalone
116130394Sdwmalonevoid
117240005Szontamd64_syscall_entry(struct trussinfo *trussinfo, int nargs)
118240005Szont{
119240005Szont	struct ptrace_io_desc iorequest;
120240005Szont	struct reg regs;
121240562Szont	struct freebsd_syscall *fsc;
122240005Szont	struct syscall *sc;
123240562Szont	lwpid_t tid;
124240005Szont	int i, reg, syscall_num;
125130394Sdwmalone
126240562Szont	tid = trussinfo->curthread->tid;
127130394Sdwmalone
128240562Szont	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
129240005Szont		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
130240005Szont		return;
131240005Szont	}
132130394Sdwmalone
133240005Szont	/*
134240005Szont	 * FreeBSD has two special kinds of system call redirctions --
135240005Szont	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
136240005Szont	 * routine, basically; the latter is for quad-aligned arguments.
137240005Szont	 */
138240005Szont	reg = 0;
139240005Szont	syscall_num = regs.r_rax;
140240005Szont	switch (syscall_num) {
141240005Szont	case SYS_syscall:
142240005Szont	case SYS___syscall:
143240005Szont		syscall_num = regs.r_rdi;
144240005Szont		reg++;
145240005Szont		break;
146240005Szont	}
147130394Sdwmalone
148240562Szont	fsc = alloc_fsc();
149240562Szont	if (fsc == NULL)
150240562Szont		return;
151240562Szont	fsc->number = syscall_num;
152240562Szont	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
153240005Szont	    NULL : syscallnames[syscall_num];
154240562Szont	if (!fsc->name) {
155240005Szont		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
156240005Szont		    syscall_num);
157240005Szont	}
158130394Sdwmalone
159240562Szont	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
160240562Szont	    (strcmp(fsc->name, "fork") == 0 ||
161240562Szont	    strcmp(fsc->name, "rfork") == 0 ||
162240562Szont	    strcmp(fsc->name, "vfork") == 0))
163240005Szont		trussinfo->curthread->in_fork = 1;
164130394Sdwmalone
165240005Szont	if (nargs == 0)
166240005Szont		return;
167130394Sdwmalone
168240562Szont	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
169240005Szont	for (i = 0; i < nargs && reg < 6; i++, reg++) {
170240005Szont		switch (reg) {
171240562Szont		case 0: fsc->args[i] = regs.r_rdi; break;
172240562Szont		case 1: fsc->args[i] = regs.r_rsi; break;
173240562Szont		case 2: fsc->args[i] = regs.r_rdx; break;
174240562Szont		case 3: fsc->args[i] = regs.r_rcx; break;
175240562Szont		case 4: fsc->args[i] = regs.r_r8; break;
176240562Szont		case 5: fsc->args[i] = regs.r_r9; break;
177240005Szont		}
178240005Szont	}
179240005Szont	if (nargs > i) {
180240005Szont		iorequest.piod_op = PIOD_READ_D;
181240005Szont		iorequest.piod_offs = (void *)(regs.r_rsp + sizeof(register_t));
182240562Szont		iorequest.piod_addr = &fsc->args[i];
183240005Szont		iorequest.piod_len = (nargs - i) * sizeof(register_t);
184240562Szont		ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
185240005Szont		if (iorequest.piod_len == 0)
186240005Szont			return;
187240005Szont	}
188240005Szont
189240562Szont	sc = get_syscall(fsc->name);
190240005Szont	if (sc)
191240562Szont		fsc->nargs = sc->nargs;
192240005Szont	else {
193130394Sdwmalone#if DEBUG
194240005Szont		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
195240562Szont		    "args to %d\n", fsc->name, nargs);
196130394Sdwmalone#endif
197240562Szont		fsc->nargs = nargs;
198240005Szont	}
199130394Sdwmalone
200240562Szont	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
201240562Szont	fsc->sc = sc;
202130394Sdwmalone
203240005Szont	/*
204240005Szont	 * At this point, we set up the system call arguments.
205240005Szont	 * We ignore any OUT ones, however -- those are arguments that
206240005Szont	 * are set by the system call, and so are probably meaningless
207240005Szont	 * now.	This doesn't currently support arguments that are
208240005Szont	 * passed in *and* out, however.
209240005Szont	 */
210130394Sdwmalone
211240562Szont	if (fsc->name) {
212130394Sdwmalone#if DEBUG
213240562Szont		fprintf(stderr, "syscall %s(", fsc->name);
214130394Sdwmalone#endif
215240562Szont		for (i = 0; i < fsc->nargs; i++) {
216130394Sdwmalone#if DEBUG
217240005Szont			fprintf(stderr, "0x%lx%s", sc ?
218240562Szont			    fsc->args[sc->args[i].offset] : fsc->args[i],
219240562Szont			    i < (fsc->nargs - 1) ? "," : "");
220130394Sdwmalone#endif
221240005Szont			if (sc && !(sc->args[i].type & OUT)) {
222240562Szont				fsc->s_args[i] = print_arg(&sc->args[i],
223240562Szont				    fsc->args, 0, trussinfo);
224240005Szont			}
225240005Szont		}
226130394Sdwmalone#if DEBUG
227240005Szont		fprintf(stderr, ")\n");
228130394Sdwmalone#endif
229240005Szont	}
230130394Sdwmalone
231130394Sdwmalone#if DEBUG
232240005Szont	fprintf(trussinfo->outfile, "\n");
233130394Sdwmalone#endif
234130394Sdwmalone
235240562Szont	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
236240562Szont	    strcmp(fsc->name, "exit") == 0)) {
237240005Szont		/*
238240005Szont		 * XXX
239240005Szont		 * This could be done in a more general
240240005Szont		 * manner but it still wouldn't be very pretty.
241240005Szont		 */
242240562Szont		if (strcmp(fsc->name, "execve") == 0) {
243240005Szont			if ((trussinfo->flags & EXECVEARGS) == 0) {
244240562Szont				if (fsc->s_args[1]) {
245240562Szont					free(fsc->s_args[1]);
246240562Szont					fsc->s_args[1] = NULL;
247240005Szont				}
248240005Szont			}
249240005Szont			if ((trussinfo->flags & EXECVEENVS) == 0) {
250240562Szont				if (fsc->s_args[2]) {
251240562Szont					free(fsc->s_args[2]);
252240562Szont					fsc->s_args[2] = NULL;
253240005Szont				}
254240005Szont			}
255240005Szont		}
256240005Szont	}
257240562Szont	trussinfo->curthread->fsc = fsc;
258130394Sdwmalone}
259130394Sdwmalone
260130394Sdwmalone/*
261130394Sdwmalone * And when the system call is done, we handle it here.
262130394Sdwmalone * Currently, no attempt is made to ensure that the system calls
263130394Sdwmalone * match -- this needs to be fixed (and is, in fact, why S_SCX includes
264213799Sbcr * the system call number instead of, say, an error status).
265130394Sdwmalone */
266130394Sdwmalone
267130394Sdwmalonelong
268130394Sdwmaloneamd64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
269130394Sdwmalone{
270240005Szont	struct reg regs;
271240562Szont	struct freebsd_syscall *fsc;
272240005Szont	struct syscall *sc;
273240562Szont	lwpid_t tid;
274240005Szont	long retval;
275240005Szont	int errorp, i;
276130394Sdwmalone
277240562Szont	if (trussinfo->curthread->fsc == NULL)
278240005Szont		return (-1);
279171055Sdelphij
280240562Szont	tid = trussinfo->curthread->tid;
281130394Sdwmalone
282240562Szont	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
283240005Szont		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
284240005Szont		return (-1);
285240005Szont	}
286130394Sdwmalone
287240005Szont	retval = regs.r_rax;
288240005Szont	errorp = !!(regs.r_rflags & PSL_C);
289130394Sdwmalone
290130394Sdwmalone	/*
291240005Szont	 * This code, while simpler than the initial versions I used, could
292240005Szont	 * stand some significant cleaning.
293130394Sdwmalone	 */
294130394Sdwmalone
295240562Szont	fsc = trussinfo->curthread->fsc;
296240562Szont	sc = fsc->sc;
297240005Szont	if (!sc) {
298240562Szont		for (i = 0; i < fsc->nargs; i++)
299240562Szont			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
300240005Szont	} else {
301240005Szont		/*
302240005Szont		 * Here, we only look for arguments that have OUT masked in --
303240005Szont		 * otherwise, they were handled in the syscall_entry function.
304240005Szont		 */
305240005Szont		for (i = 0; i < sc->nargs; i++) {
306240005Szont			char *temp;
307240005Szont			if (sc->args[i].type & OUT) {
308240005Szont				/*
309240005Szont				 * If an error occurred, then don't bother
310240005Szont				 * getting the data; it may not be valid.
311240005Szont				 */
312240005Szont				if (errorp) {
313240005Szont					asprintf(&temp, "0x%lx",
314240562Szont					    fsc->args[sc->args[i].offset]);
315240005Szont				} else {
316240005Szont					temp = print_arg(&sc->args[i],
317240562Szont					    fsc->args, retval, trussinfo);
318240005Szont				}
319240562Szont				fsc->s_args[i] = temp;
320240005Szont			}
321240005Szont		}
322240005Szont	}
323171055Sdelphij
324240562Szont	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
325240562Szont	    strcmp(fsc->name, "exit") == 0))
326240005Szont		trussinfo->curthread->in_syscall = 1;
327130394Sdwmalone
328240005Szont	/*
329240005Szont	 * It would probably be a good idea to merge the error handling,
330240005Szont	 * but that complicates things considerably.
331240005Szont	 */
332130394Sdwmalone
333240562Szont	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
334240562Szont	    retval, fsc->sc);
335240562Szont	free_fsc(fsc);
336240005Szont
337240005Szont	return (retval);
338130394Sdwmalone}
339