1149423Spjd/*
2149423Spjd * Copyright 1997 Sean Eric Fagan
3149423Spjd *
4149423Spjd * Redistribution and use in source and binary forms, with or without
5149423Spjd * modification, are permitted provided that the following conditions
6149423Spjd * are met:
7149423Spjd * 1. Redistributions of source code must retain the above copyright
8149423Spjd *    notice, this list of conditions and the following disclaimer.
9149423Spjd * 2. Redistributions in binary form must reproduce the above copyright
10149423Spjd *    notice, this list of conditions and the following disclaimer in the
11149423Spjd *    documentation and/or other materials provided with the distribution.
12149423Spjd * 3. All advertising materials mentioning features or use of this software
13149423Spjd *    must display the following acknowledgement:
14149423Spjd *	This product includes software developed by Sean Eric Fagan
15149423Spjd * 4. Neither the name of the author may be used to endorse or promote
16149423Spjd *    products derived from this software without specific prior written
17149423Spjd *    permission.
18149423Spjd *
19149423Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20149423Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21149423Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22149423Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23149423Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24149423Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25149423Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26149423Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27184092Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28149423Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29149423Spjd * SUCH DAMAGE.
30149423Spjd */
31149423Spjd
32149423Spjd#ifndef lint
33149423Spjdstatic const char rcsid[] =
34149423Spjd  "$FreeBSD$";
35152579Sru#endif /* not lint */
36149423Spjd
37149423Spjd/*
38149423Spjd * Linux/i386-specific system call handling.  Given how much of this code
39149423Spjd * is taken from the freebsd equivalent, I can probably put even more of
40149423Spjd * it in support routines that can be used by any personality support.
41152579Sru */
42149423Spjd
43149423Spjd#include <sys/types.h>
44149423Spjd#include <sys/ptrace.h>
45149423Spjd
46149423Spjd#include <machine/reg.h>
47149423Spjd#include <machine/psl.h>
48149423Spjd
49233837Sghelmer#include <errno.h>
50233837Sghelmer#include <fcntl.h>
51149423Spjd#include <signal.h>
52149423Spjd#include <stdio.h>
53152579Sru#include <stdlib.h>
54152579Sru#include <string.h>
55149423Spjd#include <time.h>
56184092Sdes#include <unistd.h>
57152579Sru
58149423Spjd#include "truss.h"
59149423Spjd#include "syscall.h"
60149423Spjd#include "extern.h"
61152579Sru
62149423Spjd#include "linux_syscalls.h"
63184092Sdes
64152579Srustatic int nsyscalls =
65152579Sru	sizeof(linux_syscallnames) / sizeof(linux_syscallnames[0]);
66149423Spjd
67152579Sru/*
68152579Sru * This is what this particular file uses to keep track of a system call.
69152579Sru * It is probably not quite sufficient -- I can probably use the same
70152579Sru * structure for the various syscall personalities, and I also probably
71152579Sru * need to nest system calls (for signal handlers).
72152579Sru *
73152579Sru * 'struct syscall' describes the system call; it may be NULL, however,
74149423Spjd * if we don't know about this particular system call yet.
75152579Sru */
76152579Srustruct linux_syscall {
77152579Sru	struct syscall *sc;
78149423Spjd	const char *name;
79149423Spjd	int number;
80149423Spjd	unsigned long args[5];
81149423Spjd	int nargs;	/* number of arguments -- *not* number of words! */
82152579Sru	char **s_args;	/* the printable arguments */
83149423Spjd};
84149423Spjd
85149423Spjdstatic struct linux_syscall *
86152579Srualloc_fsc(void)
87152579Sru{
88152579Sru
89152579Sru	return (malloc(sizeof(struct linux_syscall)));
90149423Spjd}
91149423Spjd
92149423Spjd/* Clear up and free parts of the fsc structure. */
93152579Srustatic void
94233837Sghelmerfree_fsc(struct linux_syscall *fsc)
95233837Sghelmer{
96233837Sghelmer	int i;
97233856Sghelmer
98149423Spjd	if (fsc->s_args) {
99149423Spjd		for (i = 0; i < fsc->nargs; i++)
100149423Spjd			free(fsc->s_args[i]);
101152579Sru		free(fsc->s_args);
102152579Sru	}
103152579Sru	free(fsc);
104149423Spjd}
105149423Spjd
106152579Sru/*
107149423Spjd * Called when a process has entered a system call.  nargs is the
108149423Spjd * number of words, not number of arguments (a necessary distinction
109193589Sdes * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
110149423Spjd * is ever changed these functions need to keep up.
111233837Sghelmer */
112233837Sghelmer
113233837Sghelmervoid
114233837Sghelmeri386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs)
115233856Sghelmer{
116233856Sghelmer	struct reg regs;
117233856Sghelmer	struct linux_syscall *fsc;
118233837Sghelmer	struct syscall *sc;
119233837Sghelmer	lwpid_t tid;
120233837Sghelmer	int i, syscall_num;
121233837Sghelmer
122149423Spjd	tid = trussinfo->curthread->tid;
123152579Sru
124154952Spjd	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
125154952Spjd		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
126154952Spjd		return;
127154952Spjd	}
128233837Sghelmer
129233837Sghelmer	syscall_num = regs.r_eax;
130154952Spjd
131233837Sghelmer	fsc = alloc_fsc();
132154952Spjd	if (fsc == NULL)
133149423Spjd		return;
134149423Spjd	fsc->number = syscall_num;
135149423Spjd	fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
136149423Spjd	    NULL : linux_syscallnames[syscall_num];
137150214Spjd	if (!fsc->name) {
138149423Spjd		fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
139154952Spjd		    syscall_num);
140156280Skeramida	}
141156280Skeramida
142154952Spjd	if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
143149423Spjd	    (strcmp(fsc->name, "linux_fork") == 0 ||
144149423Spjd	    strcmp(fsc->name, "linux_vfork") == 0))
145149423Spjd		trussinfo->curthread->in_fork = 1;
146149423Spjd
147149423Spjd	if (nargs == 0)
148149423Spjd		return;
149149423Spjd
150149423Spjd	/*
151149423Spjd	 * Linux passes syscall arguments in registers, not
152149423Spjd	 * on the stack.  Fortunately, we've got access to the
153149423Spjd	 * register set.  Note that we don't bother checking the
154149423Spjd	 * number of arguments.	And what does linux do for syscalls
155149423Spjd	 * that have more than five arguments?
156149423Spjd	 */
157149423Spjd
158149423Spjd	fsc->args[0] = regs.r_ebx;
159149423Spjd	fsc->args[1] = regs.r_ecx;
160149423Spjd	fsc->args[2] = regs.r_edx;
161149423Spjd	fsc->args[3] = regs.r_esi;
162149423Spjd	fsc->args[4] = regs.r_edi;
163149423Spjd
164149423Spjd	sc = get_syscall(fsc->name);
165149423Spjd	if (sc)
166149423Spjd		fsc->nargs = sc->nargs;
167156280Skeramida	else {
168149423Spjd#if DEBUG
169149423Spjd		fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
170149423Spjd		    "args to %d\n", fsc->name, nargs);
171149423Spjd#endif
172149423Spjd		fsc->nargs = nargs;
173149423Spjd	}
174149423Spjd
175149423Spjd	fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
176149423Spjd	fsc->sc = sc;
177149423Spjd
178149423Spjd	/*
179149423Spjd	 * At this point, we set up the system call arguments.
180149423Spjd	 * We ignore any OUT ones, however -- those are arguments that
181152579Sru	 * are set by the system call, and so are probably meaningless
182149423Spjd	 * now.	This doesn't currently support arguments that are
183149423Spjd	 * passed in *and* out, however.
184149423Spjd	 */
185149423Spjd
186149423Spjd	if (fsc->name) {
187149423Spjd#if DEBUG
188172577Skib		fprintf(stderr, "syscall %s(", fsc->name);
189172577Skib#endif
190172611Ssimon		for (i = 0; i < fsc->nargs; i++) {
191172611Ssimon#if DEBUG
192172577Skib			fprintf(stderr, "0x%x%s", sc ?
193149423Spjd			    fsc->args[sc->args[i].offset] : fsc->args[i],
194149423Spjd			    i < (fsc->nargs - 1) ? "," : "");
195149423Spjd#endif
196149423Spjd			if (sc && !(sc->args[i].type & OUT)) {
197149423Spjd				fsc->s_args[i] = print_arg(&sc->args[i],
198149423Spjd				    fsc->args, 0, trussinfo);
199149423Spjd			}
200149423Spjd		}
201149423Spjd#if DEBUG
202152579Sru		fprintf(stderr, ")\n");
203149423Spjd#endif
204152579Sru	}
205149423Spjd
206149423Spjd#if DEBUG
207149423Spjd	fprintf(trussinfo->outfile, "\n");
208149423Spjd#endif
209149423Spjd
210149423Spjd	if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
211152579Sru	    strcmp(fsc->name, "exit") == 0)) {
212149423Spjd		/*
213149423Spjd		 * XXX
214149423Spjd		 * This could be done in a more general
215149423Spjd		 * manner but it still wouldn't be very pretty.
216149423Spjd		 */
217149423Spjd		if (strcmp(fsc->name, "linux_execve") == 0) {
218149423Spjd			if ((trussinfo->flags & EXECVEARGS) == 0) {
219149423Spjd				if (fsc->s_args[1]) {
220149423Spjd					free(fsc->s_args[1]);
221149423Spjd					fsc->s_args[1] = NULL;
222149423Spjd				}
223152579Sru			}
224149423Spjd			if ((trussinfo->flags & EXECVEENVS) == 0) {
225152579Sru				if (fsc->s_args[2]) {
226149423Spjd					free(fsc->s_args[2]);
227149423Spjd					fsc->s_args[2] = NULL;
228149423Spjd				}
229149423Spjd			}
230149423Spjd		}
231149423Spjd	}
232152579Sru	trussinfo->curthread->fsc = fsc;
233152579Sru}
234149423Spjd
235152579Sru/*
236149423Spjd * Linux syscalls return negative errno's, we do positive and map them
237149423Spjd */
238149423Spjdconst int bsd_to_linux_errno[] = {
239149423Spjd	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
240149423Spjd	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
241149423Spjd	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
242152579Sru	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
243149423Spjd	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
244149423Spjd	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
245149423Spjd	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
246149423Spjd	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
247149423Spjd	-6,
248149423Spjd};
249149423Spjd
250149423Spjdlong
251149423Spjdi386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
252149423Spjd{
253149423Spjd	struct reg regs;
254149423Spjd	struct linux_syscall *fsc;
255152579Sru	struct syscall *sc;
256149423Spjd	lwpid_t tid;
257184092Sdes	long retval;
258184092Sdes	int errorp, i;
259184092Sdes
260233837Sghelmer	if (trussinfo->curthread->fsc == NULL)
261233837Sghelmer		return (-1);
262233837Sghelmer
263233837Sghelmer	tid = trussinfo->curthread->tid;
264233837Sghelmer
265233837Sghelmer	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
266233837Sghelmer		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
267233837Sghelmer		return (-1);
268233837Sghelmer	}
269233837Sghelmer
270149423Spjd	retval = regs.r_eax;
271149423Spjd	errorp = !!(regs.r_eflags & PSL_C);
272184092Sdes
273184092Sdes	/*
274149423Spjd	 * This code, while simpler than the initial versions I used, could
275149423Spjd	 * stand some significant cleaning.
276149423Spjd	 */
277152579Sru
278149423Spjd	fsc = trussinfo->curthread->fsc;
279149423Spjd	sc = fsc->sc;
280149423Spjd	if (!sc) {
281149423Spjd		for (i = 0; i < fsc->nargs; i++)
282149423Spjd			asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
283	} else {
284		/*
285		 * Here, we only look for arguments that have OUT masked in --
286		 * otherwise, they were handled in the syscall_entry function.
287		 */
288		for (i = 0; i < sc->nargs; i++) {
289			char *temp;
290			if (sc->args[i].type & OUT) {
291				/*
292				 * If an error occurred, then don't bother
293				 * getting the data; it may not be valid.
294				 */
295				if (errorp) {
296					asprintf(&temp, "0x%lx",
297					    fsc->args[sc->args[i].offset]);
298				} else {
299					temp = print_arg(&sc->args[i],
300					    fsc->args, retval, trussinfo);
301				}
302				fsc->s_args[i] = temp;
303			}
304		}
305	}
306
307	/*
308	 * It would probably be a good idea to merge the error handling,
309	 * but that complicates things considerably.
310	 */
311	if (errorp) {
312		for (i = 0;
313		    (size_t)i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) {
314			if (retval == bsd_to_linux_errno[i])
315				break;
316		}
317	}
318
319	if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
320	    strcmp(fsc->name, "exit") == 0))
321		trussinfo->curthread->in_syscall = 1;
322
323	print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
324	    errorp ? i : retval, fsc->sc);
325	free_fsc(fsc);
326
327	return (retval);
328}
329