add to, and prioritize the TODO a little.
[trinity.git] / syscall.c
blobf23ec0587f5f819cc5946e678fd9893f8f73020f
1 /*
2 * Functions for actually doing the system calls.
3 */
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <sys/ptrace.h>
12 #include <sys/syscall.h>
13 #include <sys/wait.h>
15 #include "arch.h"
16 #include "child.h"
17 #include "random.h"
18 #include "sanitise.h"
19 #include "shm.h"
20 #include "syscall.h"
21 #include "pids.h"
22 #include "log.h"
23 #include "params.h"
24 #include "maps.h"
25 #include "tables.h"
26 #include "trinity.h"
27 #include "uid.h"
28 #include "utils.h"
30 #define __syscall_return(type, res) \
31 do { \
32 if ((unsigned long)(res) >= (unsigned long)(-125)) { \
33 errno = -(res); \
34 res = -1; \
35 } \
36 return (type) (res); \
37 } while (0)
39 #ifdef ARCH_IS_BIARCH
41 * This routine does 32 bit syscalls on 64 bit kernel.
42 * 32-on-32 will just use syscall() directly from do_syscall() because do32bit flag is biarch only.
44 static long syscall32(unsigned int call,
45 unsigned long a1, unsigned long a2, unsigned long a3,
46 unsigned long a4, unsigned long a5, unsigned long a6)
48 long __res = 0;
50 //FIXME: Move the implementations out to arch header files.
52 #if defined(__x86_64__)
53 __asm__ volatile (
54 "pushq %%rbp\n\t"
55 "pushq %%r10\n\t"
56 "pushq %%r11\n\t"
57 "movq %7, %%rbp\n\t"
58 "int $0x80\n\t"
59 "popq %%r11\n\t"
60 "popq %%r10\n\t"
61 "popq %%rbp\n\t"
62 : "=a" (__res)
63 : "0" (call),"b" ((long)(a1)),"c" ((long)(a2)),"d" ((long)(a3)), "S" ((long)(a4)),"D" ((long)(a5)), "g" ((long)(a6))
64 : "%rbp" /* mark EBP reg as dirty */
66 __syscall_return(long, __res);
68 #else
69 /* non-x86 implementations go here. */
70 #error Implement 32-on-64 syscall in syscall.c:syscall32() for this architecture.
72 #endif
73 return __res;
75 #else
76 #define syscall32(a,b,c,d,e,f,g) 0
77 #endif /* ARCH_IS_BIARCH */
79 static unsigned long do_syscall(int childno, int *errno_saved)
81 int nr = shm->syscall[childno].nr;
82 unsigned long a1, a2, a3, a4, a5, a6;
83 unsigned long ret = 0;
85 a1 = shm->syscall[childno].a1;
86 a2 = shm->syscall[childno].a2;
87 a3 = shm->syscall[childno].a3;
88 a4 = shm->syscall[childno].a4;
89 a5 = shm->syscall[childno].a5;
90 a6 = shm->syscall[childno].a6;
92 shm->total_syscalls_done++;
93 shm->child_syscall_count[childno]++;
94 (void)gettimeofday(&shm->tv[childno], NULL);
96 if (syscalls[nr].entry->flags & NEED_ALARM)
97 (void)alarm(1);
99 errno = 0;
101 if (shm->syscall[childno].do32bit == FALSE)
102 ret = syscall(nr, a1, a2, a3, a4, a5, a6);
103 else
104 ret = syscall32(nr, a1, a2, a3, a4, a5, a6);
106 *errno_saved = errno;
108 if (syscalls[nr].entry->flags & NEED_ALARM)
109 (void)alarm(0);
111 return ret;
115 * Generate arguments, print them out, then call the syscall.
117 * returns a bool that determines whether we can keep doing syscalls
118 * in this child.
120 bool mkcall(int childno)
122 struct syscallentry *entry;
123 unsigned int call = shm->syscall[childno].nr;
124 unsigned long ret = 0;
125 int errno_saved;
127 entry = syscalls[call].entry;
129 shm->regenerate++;
131 shm->syscall[childno].a1 = (unsigned long) rand64();
132 shm->syscall[childno].a2 = (unsigned long) rand64();
133 shm->syscall[childno].a3 = (unsigned long) rand64();
134 shm->syscall[childno].a4 = (unsigned long) rand64();
135 shm->syscall[childno].a5 = (unsigned long) rand64();
136 shm->syscall[childno].a6 = (unsigned long) rand64();
138 generic_sanitise(childno);
139 if (entry->sanitise)
140 entry->sanitise(childno);
142 output_syscall_prefix(childno, call);
144 /* If we're going to pause, might as well sync pre-syscall */
145 if (dopause == TRUE)
146 synclogs();
148 /* Some architectures (IA64/MIPS) start their Linux syscalls
149 * At non-zero, and have other ABIs below.
151 call += SYSCALL_OFFSET;
153 /* This is a special case for things like execve, which would replace our
154 * child process with something unknown to us. We use a 'throwaway' process
155 * to do the execve in, and let it run for a max of a seconds before we kill it */
156 #if 0
157 if (syscalls[call].entry->flags & EXTRA_FORK) {
158 pid_t extrapid;
160 extrapid = fork();
161 if (extrapid == 0) {
162 ret = do_syscall(childno, &errno_saved);
163 shm->syscall[childno].retval = ret;
164 _exit(EXIT_SUCCESS);
165 } else {
166 if (pid_alive(extrapid)) {
167 sleep(1);
168 kill(extrapid, SIGKILL);
170 return FALSE;
173 #endif
175 /* common-case, do the syscall in this child process. */
176 ret = do_syscall(childno, &errno_saved);
177 shm->syscall[childno].retval = ret;
179 if (IS_ERR(ret))
180 shm->failures++;
181 else
182 shm->successes++;
184 output_syscall_postfix(ret, errno_saved, IS_ERR(ret));
185 if (dopause == TRUE)
186 sleep(1);
188 /* If the syscall doesn't exist don't bother calling it next time. */
189 if ((ret == -1UL) && (errno_saved == ENOSYS)) {
191 /* Futex is awesome, it ENOSYS's depending on arguments. Sigh. */
192 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "futex"))
193 goto skip_enosys;
195 /* Unknown ioctls also ENOSYS. */
196 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "ioctl"))
197 goto skip_enosys;
199 /* sendfile() may ENOSYS depending on args. */
200 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "sendfile"))
201 goto skip_enosys;
203 output(1, "%s (%d) returned ENOSYS, marking as inactive.\n",
204 entry->name, call);
206 if (biarch == FALSE) {
207 deactivate_syscall(call);
208 } else {
209 if (shm->syscall[childno].do32bit == TRUE)
210 deactivate_syscall32(call);
211 else
212 deactivate_syscall64(call);
216 skip_enosys:
218 if (entry->post)
219 entry->post(childno);
221 /* store info for debugging. */
222 shm->previous[childno].nr = shm->syscall[childno].nr;
223 shm->previous[childno].a1 = shm->syscall[childno].a1;
224 shm->previous[childno].a2 = shm->syscall[childno].a2;
225 shm->previous[childno].a3 = shm->syscall[childno].a3;
226 shm->previous[childno].a4 = shm->syscall[childno].a4;
227 shm->previous[childno].a5 = shm->syscall[childno].a5;
228 shm->previous[childno].a6 = shm->syscall[childno].a6;
229 shm->previous[childno].do32bit = shm->syscall[childno].do32bit;
231 check_uid();
233 return TRUE;
236 bool this_syscallname(const char *thisname, int childno)
238 unsigned int call = shm->syscall[childno].nr;
239 struct syscallentry *syscall_entry = syscalls[call].entry;
241 return strcmp(thisname, syscall_entry->name);