1247975Scognet/*
2247975Scognet * Copyright 1997 Sean Eric Fagan
3247975Scognet *
4247975Scognet * Redistribution and use in source and binary forms, with or without
5247975Scognet * modification, are permitted provided that the following conditions
6247975Scognet * are met:
7247975Scognet * 1. Redistributions of source code must retain the above copyright
8247975Scognet *    notice, this list of conditions and the following disclaimer.
9247975Scognet * 2. Redistributions in binary form must reproduce the above copyright
10247975Scognet *    notice, this list of conditions and the following disclaimer in the
11247975Scognet *    documentation and/or other materials provided with the distribution.
12247975Scognet * 3. All advertising materials mentioning features or use of this software
13247975Scognet *    must display the following acknowledgement:
14247975Scognet *	This product includes software developed by Sean Eric Fagan
15247975Scognet * 4. Neither the name of the author may be used to endorse or promote
16247975Scognet *    products derived from this software without specific prior written
17247975Scognet *    permission.
18247975Scognet *
19247975Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20247975Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21247975Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22247975Scognet * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23247975Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24247975Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25247975Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26247975Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27247975Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28247975Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29247975Scognet * SUCH DAMAGE.
30247975Scognet */
31247975Scognet
32247975Scognet#include <sys/cdefs.h>
33247975Scognet__FBSDID("$FreeBSD$");
34290052Sjhb
35290052Sjhb/* FreeBSD/arm-specific system call handling. */
36290052Sjhb
37247975Scognet#include <sys/ptrace.h>
38247975Scognet#include <sys/syscall.h>
39247975Scognet
40247975Scognet#include <machine/reg.h>
41247975Scognet#include <machine/armreg.h>
42247975Scognet#include <machine/ucontext.h>
43247975Scognet
44247975Scognet#include <stdio.h>
45247975Scognet
46247975Scognet#include "truss.h"
47247975Scognet
48247975Scognet#include "syscalls.h"
49247975Scognet
50290052Sjhbstatic int
51290052Sjhbarm_fetch_args(struct trussinfo *trussinfo, u_int narg)
52247975Scognet{
53247975Scognet	struct ptrace_io_desc iorequest;
54247975Scognet	struct reg regs;
55290052Sjhb	struct current_syscall *cs;
56247975Scognet	lwpid_t tid;
57290052Sjhb	u_int i, reg, syscall_num;
58247975Scognet
59247975Scognet	tid = trussinfo->curthread->tid;
60290052Sjhb	cs = &trussinfo->curthread->cs;
61247975Scognet	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
62247975Scognet		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
63290052Sjhb		return (-1);
64247975Scognet	}
65247975Scognet
66247975Scognet	/*
67290052Sjhb	 * FreeBSD has two special kinds of system call redirections --
68247975Scognet	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
69247975Scognet	 * routine, basically; the latter is for quad-aligned arguments.
70290052Sjhb	 *
71290052Sjhb	 * The system call argument count and code from ptrace() already
72290052Sjhb	 * account for these, but we need to skip over the first argument.
73247975Scognet	 */
74247975Scognet#ifdef __ARM_EABI__
75247975Scognet	syscall_num = regs.r[7];
76247975Scognet#else
77290052Sjhb	if ((syscall_num = ptrace(PT_READ_I, tid,
78247975Scognet	    (caddr_t)(regs.r[_REG_PC] - INSN_SIZE), 0)) == -1) {
79247975Scognet		fprintf(trussinfo->outfile, "-- CANNOT READ PC --\n");
80290052Sjhb		return (-1);
81247975Scognet	}
82247975Scognet	syscall_num = syscall_num & 0x000fffff;
83247975Scognet#endif
84290052Sjhb
85290052Sjhb	reg = 0;
86247975Scognet	switch (syscall_num) {
87247975Scognet	case SYS_syscall:
88290052Sjhb		reg = 1;
89247975Scognet		break;
90247975Scognet	case SYS___syscall:
91290052Sjhb		reg = 2;
92247975Scognet		break;
93247975Scognet	}
94247975Scognet
95290052Sjhb	for (i = 0; i < narg && reg < 4; i++, reg++)
96290052Sjhb		cs->args[i] = regs.r[reg];
97290052Sjhb	if (narg > i) {
98247975Scognet		iorequest.piod_op = PIOD_READ_D;
99290052Sjhb		iorequest.piod_offs = (void *)(regs.r_sp +
100247975Scognet		    4 * sizeof(uint32_t));
101290052Sjhb		iorequest.piod_addr = &cs->args[i];
102290052Sjhb		iorequest.piod_len = (narg - i) * sizeof(cs->args[0]);
103247975Scognet		ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
104247975Scognet		if (iorequest.piod_len == 0)
105290052Sjhb			return (-1);
106247975Scognet	}
107247975Scognet
108290052Sjhb	return (0);
109247975Scognet}
110247975Scognet
111290052Sjhbstatic int
112290052Sjhbarm_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
113247975Scognet{
114247975Scognet	struct reg regs;
115247975Scognet	lwpid_t tid;
116247975Scognet
117247975Scognet	tid = trussinfo->curthread->tid;
118247975Scognet	if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
119247975Scognet		fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
120247975Scognet		return (-1);
121247975Scognet	}
122247975Scognet
123290052Sjhb	/* XXX: Does not have the __ARMEB__ handling for __syscall(). */
124290052Sjhb	retval[0] = regs.r[0];
125290052Sjhb	retval[1] = regs.r[1];
126290052Sjhb	*errorp = !!(regs.r_cpsr & PSR_C);
127290052Sjhb	return (0);
128290052Sjhb}
129247975Scognet
130290052Sjhbstatic struct procabi arm_fbsd = {
131290052Sjhb	"FreeBSD ELF32",
132290052Sjhb	syscallnames,
133290052Sjhb	nitems(syscallnames),
134290052Sjhb	arm_fetch_args,
135290052Sjhb	arm_fetch_retval
136290052Sjhb};
137247975Scognet
138290052SjhbPROCABI(arm_fbsd);
139