1188628Simp/*
2204977Simp * Copyright 1998 Sean Eric Fagan
3188628Simp *
4188628Simp * Redistribution and use in source and binary forms, with or without
5188628Simp * modification, are permitted provided that the following conditions
6188628Simp * are met:
7188628Simp * 1. Redistributions of source code must retain the above copyright
8188628Simp *    notice, this list of conditions and the following disclaimer.
9188628Simp * 2. Redistributions in binary form must reproduce the above copyright
10188628Simp *    notice, this list of conditions and the following disclaimer in the
11188628Simp *    documentation and/or other materials provided with the distribution.
12188628Simp * 3. All advertising materials mentioning features or use of this software
13188628Simp *    must display the following acknowledgement:
14188628Simp *	This product includes software developed by Sean Eric Fagan
15188628Simp * 4. Neither the name of the author may be used to endorse or promote
16188628Simp *    products derived from this software without specific prior written
17188628Simp *    permission.
18188628Simp *
19188628Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20188628Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21188628Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22188628Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23188628Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24188628Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25188628Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26188628Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27188628Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28188628Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29188628Simp * SUCH DAMAGE.
30188628Simp */
31188628Simp
32188628Simp#ifndef lint
33188628Simpstatic const char rcsid[] =
34188628Simp  "$FreeBSD$";
35188628Simp#endif /* not lint */
36188628Simp
37188628Simp/*
38188628Simp * FreeBSD/sparc64-specific system call handling.  This is probably the most
39188628Simp * complex part of the entire truss program, although I've got lots of
40188628Simp * it handled relatively cleanly now.  The system call names are generated
41188628Simp * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
42188628Simp * names used for the various structures are confusing, I sadly admit.
43188628Simp *
44188628Simp * This file is almost nothing more than a slightly-edited i386-fbsd.c.
45188628Simp */
46188628Simp
47188628Simp#include <sys/types.h>
48188628Simp#include <sys/ptrace.h>
49188628Simp#include <sys/syscall.h>
50188628Simp
51188628Simp#include <machine/frame.h>
52188628Simp#include <machine/reg.h>
53188628Simp
54188628Simp#include <err.h>
55188628Simp#include <errno.h>
56188628Simp#include <fcntl.h>
57188628Simp#include <signal.h>
58188628Simp#include <stddef.h>
59188628Simp#include <stdio.h>
60188628Simp#include <stdlib.h>
61188628Simp#include <string.h>
62188628Simp#include <time.h>
63188628Simp#include <unistd.h>
64188628Simp
65188628Simp#include "truss.h"
66188628Simp#include "syscall.h"
67188628Simp#include "extern.h"
68188628Simp
69188628Simp#include "syscalls.h"
70188628Simp
71188628Simpstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
72188628Simp
73188628Simp/*
74188628Simp * This is what this particular file uses to keep track of a system call.
75188628Simp * It is probably not quite sufficient -- I can probably use the same
76188628Simp * structure for the various syscall personalities, and I also probably
77188628Simp * need to nest system calls (for signal handlers).
78188628Simp *
79188628Simp * 'struct syscall' describes the system call; it may be NULL, however,
80188628Simp * if we don't know about this particular system call yet.
81188628Simp */
82240562Szontstruct freebsd_syscall {
83188628Simp	struct syscall *sc;
84188628Simp	const char *name;
85188628Simp	int number;
86188628Simp	unsigned long *args;
87188628Simp	int nargs;	/* number of arguments -- *not* number of words! */
88188628Simp	char **s_args;	/* the printable arguments */
89240562Szont};
90188628Simp
91240562Szontstatic struct freebsd_syscall *
92240562Szontalloc_fsc(void)
93240562Szont{
94240562Szont
95240562Szont	return (malloc(sizeof(struct freebsd_syscall)));
96240562Szont}
97240562Szont
98188628Simp/* Clear up and free parts of the fsc structure. */
99240562Szontstatic void
100240562Szontfree_fsc(struct freebsd_syscall *fsc)
101240005Szont{
102240005Szont	int i;
103240005Szont
104240562Szont	free(fsc->args);
105240562Szont	if (fsc->s_args) {
106240562Szont		for (i = 0; i < fsc->nargs; i++)
107240562Szont			free(fsc->s_args[i]);
108240562Szont		free(fsc->s_args);
109240005Szont	}
110240562Szont	free(fsc);
111188628Simp}
112188628Simp
113188628Simp/*
114188628Simp * Called when a process has entered a system call.  nargs is the
115188628Simp * number of words, not number of arguments (a necessary distinction
116188628Simp * in some cases).  Note that if the STOPEVENT() code in sparc64/sparc64/trap.c
117188628Simp * is ever changed these functions need to keep up.
118188628Simp */
119188628Simp
120188628Simpvoid
121240005Szontmips_syscall_entry(struct trussinfo *trussinfo, int nargs)
122240005Szont{
123240005Szont	struct ptrace_io_desc iorequest;
124240005Szont	struct reg regs;
125240562Szont	struct freebsd_syscall *fsc;
126240005Szont	struct syscall *sc;
127240562Szont	lwpid_t tid;
128240005Szont	int i, syscall_num;
129240005Szont	int indir;	/* indirect system call */
130188628Simp
131240562Szont	tid = trussinfo->curthread->tid;
132188628Simp
133240562Szont	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
134240005Szont		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
135240005Szont		return;
136240005Szont	}
137188628Simp
138240005Szont	indir = 0;
139240005Szont	syscall_num = regs.r_regs[V0];
140240005Szont	if (syscall_num == SYS_syscall) {
141240005Szont		indir = 1;
142240005Szont		syscall_num = regs.r_regs[A0];
143240005Szont	}
144188628Simp
145240562Szont	fsc = alloc_fsc();
146240562Szont	if (fsc == NULL)
147240562Szont		return;
148240562Szont	fsc->number = syscall_num;
149240562Szont	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
150240005Szont	    NULL : syscallnames[syscall_num];
151240562Szont	if (!fsc->name) {
152240005Szont		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
153240005Szont		    syscall_num);
154240005Szont	}
155188628Simp
156240562Szont	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
157240562Szont	    (strcmp(fsc->name, "fork") == 0 ||
158240562Szont	    strcmp(fsc->name, "rfork") == 0 ||
159240562Szont	    strcmp(fsc->name, "vfork") == 0))
160240005Szont		trussinfo->curthread->in_fork = 1;
161188628Simp
162240005Szont	if (nargs == 0)
163240005Szont		return;
164240005Szont
165240562Szont	fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
166188628Simp#if 0 // XXX
167240005Szont	iorequest.piod_op = PIOD_READ_D;
168240005Szont	iorequest.piod_offs = (void *)parm_offset;
169240562Szont	iorequest.piod_addr = fsc->args;
170240005Szont	iorequest.piod_len = (1 + nargs) * sizeof(unsigned long);
171240562Szont	ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
172240005Szont	if (iorequest.piod_len == 0)
173240005Szont		return;
174188628Simp#else
175240005Szont	iorequest.piod_op = PIOD_READ_D;
176188628Simp#endif
177188628Simp
178240005Szont	switch (nargs) {
179240005Szont	default:
180240005Szont		/*
181240005Szont		 * The OS doesn't seem to allow more than 10 words of
182240005Szont		 * parameters (yay!).	So we shouldn't be here.
183240005Szont		 */
184240005Szont		warn("More than 10 words (%d) of arguments!\n", nargs);
185240005Szont		break;
186240005Szont	case 10:
187240005Szont	case 9:
188240005Szont	case 8:
189240005Szont	case 7:
190240005Szont	case 6:
191240005Szont	case 5:
192240005Szont		/*
193240005Szont		 * If there are 7-10 words of arguments, they are placed
194240005Szont		 * on the stack, as is normal for other processors.
195240005Szont		 * The fall-through for all of these is deliberate!!!
196240005Szont		 */
197240005Szont		// XXX BAD constant used here
198240005Szont		iorequest.piod_op = PIOD_READ_D;
199240005Szont		iorequest.piod_offs = (void *)(regs.r_regs[SP] +
200240005Szont		    4 * sizeof(uint32_t));
201240562Szont		iorequest.piod_addr = &fsc->args[4];
202240562Szont		iorequest.piod_len = (nargs - 4) * sizeof(fsc->args[0]);
203240562Szont		ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
204240005Szont		if (iorequest.piod_len == 0)
205240005Szont			return;
206240562Szont	case 4:	fsc->args[3] = regs.r_regs[A3];
207240562Szont	case 3:	fsc->args[2] = regs.r_regs[A2];
208240562Szont	case 2:	fsc->args[1] = regs.r_regs[A1];
209240562Szont	case 1:	fsc->args[0] = regs.r_regs[A0];
210240005Szont	case 0: break;
211240005Szont	}
212240005Szont	if (indir) {
213240562Szont		memmove(&fsc->args[0], &fsc->args[1],
214240562Szont		    (nargs - 1) * sizeof(fsc->args[0]));
215240005Szont	}
216188628Simp
217240562Szont	sc = get_syscall(fsc->name);
218240005Szont	if (sc)
219240562Szont		fsc->nargs = sc->nargs;
220240005Szont	else {
221188628Simp#if DEBUG
222240005Szont		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
223240562Szont		    "args to %d\n", fsc->name, nargs);
224188628Simp#endif
225240562Szont		fsc->nargs = nargs;
226240005Szont	}
227188628Simp
228240562Szont	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
229240562Szont	fsc->sc = sc;
230188628Simp
231240005Szont	/*
232240005Szont	 * At this point, we set up the system call arguments.
233240005Szont	 * We ignore any OUT ones, however -- those are arguments that
234240005Szont	 * are set by the system call, and so are probably meaningless
235240005Szont	 * now.	This doesn't currently support arguments that are
236240005Szont	 * passed in *and* out, however.
237240005Szont	 */
238188628Simp
239240562Szont	if (fsc->name) {
240188628Simp#if DEBUG
241240562Szont		fprintf(stderr, "syscall %s(", fsc->name);
242188628Simp#endif
243240562Szont		for (i = 0; i < fsc->nargs; i++) {
244188628Simp#if DEBUG
245240005Szont			fprintf(stderr, "0x%x%s", sc ?
246240562Szont			    fsc->args[sc->args[i].offset] : fsc->args[i],
247240562Szont			    i < (fsc->nargs - 1) ? "," : "");
248188628Simp#endif
249240005Szont			if (sc && !(sc->args[i].type & OUT)) {
250240562Szont				fsc->s_args[i] = print_arg(&sc->args[i],
251240562Szont				    fsc->args, 0, trussinfo);
252240005Szont			}
253240005Szont		}
254188628Simp#if DEBUG
255240005Szont		fprintf(stderr, ")\n");
256188628Simp#endif
257240005Szont	}
258188628Simp
259188628Simp#if DEBUG
260240005Szont	fprintf(trussinfo->outfile, "\n");
261188628Simp#endif
262188628Simp
263240562Szont	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
264240562Szont	    strcmp(fsc->name, "exit") == 0)) {
265240005Szont		/*
266240005Szont		 * XXX
267240005Szont		 * This could be done in a more general
268240005Szont		 * manner but it still wouldn't be very pretty.
269240005Szont		 */
270240562Szont		if (strcmp(fsc->name, "execve") == 0) {
271240005Szont			if ((trussinfo->flags & EXECVEARGS) == 0) {
272240562Szont				if (fsc->s_args[1]) {
273240562Szont					free(fsc->s_args[1]);
274240562Szont					fsc->s_args[1] = NULL;
275240005Szont				}
276240005Szont			}
277240005Szont			if ((trussinfo->flags & EXECVEENVS) == 0) {
278240562Szont				if (fsc->s_args[2]) {
279240562Szont					free(fsc->s_args[2]);
280240562Szont					fsc->s_args[2] = NULL;
281240005Szont				}
282240005Szont			}
283240005Szont		}
284240005Szont	}
285240562Szont	trussinfo->curthread->fsc = fsc;
286188628Simp}
287188628Simp
288188628Simp/*
289188628Simp * And when the system call is done, we handle it here.
290188628Simp * Currently, no attempt is made to ensure that the system calls
291188628Simp * match -- this needs to be fixed (and is, in fact, why S_SCX includes
292213799Sbcr * the system call number instead of, say, an error status).
293188628Simp */
294188628Simp
295188628Simplong
296240005Szontmips_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
297240005Szont{
298240005Szont	struct reg regs;
299240562Szont	struct freebsd_syscall *fsc;
300240005Szont	struct syscall *sc;
301240562Szont	lwpid_t tid;
302240005Szont	long retval;
303240005Szont	int errorp, i;
304188628Simp
305240562Szont	if (trussinfo->curthread->fsc == NULL)
306240005Szont		return (-1);
307188628Simp
308240562Szont	tid = trussinfo->curthread->tid;
309188628Simp
310240562Szont	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
311240005Szont		fprintf(trussinfo->outfile, "\n");
312240005Szont		return (-1);
313240005Szont	}
314188628Simp
315240005Szont	retval = regs.r_regs[V0];
316240005Szont	errorp = !!regs.r_regs[A3];
317240005Szont
318188628Simp	/*
319240005Szont	 * This code, while simpler than the initial versions I used, could
320240005Szont	 * stand some significant cleaning.
321188628Simp	 */
322188628Simp
323240562Szont	fsc = trussinfo->curthread->fsc;
324240562Szont	sc = fsc->sc;
325240005Szont	if (!sc) {
326240562Szont		for (i = 0; i < fsc->nargs; i++)
327240562Szont			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
328240005Szont	} else {
329240005Szont		/*
330240005Szont		 * Here, we only look for arguments that have OUT masked in --
331240005Szont		 * otherwise, they were handled in the syscall_entry function.
332240005Szont		 */
333240005Szont		for (i = 0; i < sc->nargs; i++) {
334240005Szont			char *temp;
335240005Szont			if (sc->args[i].type & OUT) {
336240005Szont				/*
337240005Szont				 * If an error occurred, then don't bother
338240005Szont				 * getting the data; it may not be valid.
339240005Szont				 */
340240005Szont				if (errorp) {
341240005Szont					asprintf(&temp, "0x%lx",
342240562Szont					    fsc->args[sc->args[i].offset]);
343240005Szont				} else {
344240005Szont					temp = print_arg(&sc->args[i],
345240562Szont					    fsc->args, retval, trussinfo);
346240005Szont				}
347240562Szont				fsc->s_args[i] = temp;
348240005Szont			}
349240005Szont		}
350240005Szont	}
351188628Simp
352240562Szont	if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
353240562Szont	    strcmp(fsc->name, "exit") == 0))
354240005Szont		trussinfo->curthread->in_syscall = 1;
355188628Simp
356240005Szont	/*
357240005Szont	 * It would probably be a good idea to merge the error handling,
358240005Szont	 * but that complicates things considerably.
359240005Szont	 */
360240005Szont
361240562Szont	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
362240562Szont	    retval, fsc->sc);
363240562Szont	free_fsc(fsc);
364240005Szont
365240005Szont	return (retval);
366188628Simp}
367