split up constants.h some
[trinity.git] / syscall.c
blob31886c0e589bae4ccacab38402d0ee525cbd62e3
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_op_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 generic_free_arg(childno);
171 return FALSE;
174 #endif
176 /* common-case, do the syscall in this child process. */
177 ret = do_syscall(childno, &errno_saved);
178 shm->syscall[childno].retval = ret;
180 if (IS_ERR(ret))
181 shm->failures++;
182 else
183 shm->successes++;
185 output_syscall_postfix(ret, errno_saved, IS_ERR(ret));
186 if (dopause == TRUE)
187 sleep(1);
189 /* If the syscall doesn't exist don't bother calling it next time. */
190 if ((ret == -1UL) && (errno_saved == ENOSYS)) {
192 /* Futex is awesome, it ENOSYS's depending on arguments. Sigh. */
193 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "futex"))
194 goto skip_enosys;
196 /* Unknown ioctls also ENOSYS. */
197 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "ioctl"))
198 goto skip_enosys;
200 /* sendfile() may ENOSYS depending on args. */
201 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "sendfile"))
202 goto skip_enosys;
204 output(1, "%s (%d) returned ENOSYS, marking as inactive.\n",
205 entry->name, call);
207 if (biarch == FALSE) {
208 deactivate_syscall(call);
209 } else {
210 if (shm->syscall[childno].do32bit == TRUE)
211 deactivate_syscall32(call);
212 else
213 deactivate_syscall64(call);
217 skip_enosys:
219 if (entry->post)
220 entry->post(childno);
222 /* store info for debugging. */
223 shm->previous[childno].nr = shm->syscall[childno].nr;
224 shm->previous[childno].a1 = shm->syscall[childno].a1;
225 shm->previous[childno].a2 = shm->syscall[childno].a2;
226 shm->previous[childno].a3 = shm->syscall[childno].a3;
227 shm->previous[childno].a4 = shm->syscall[childno].a4;
228 shm->previous[childno].a5 = shm->syscall[childno].a5;
229 shm->previous[childno].a6 = shm->syscall[childno].a6;
230 shm->previous[childno].do32bit = shm->syscall[childno].do32bit;
232 check_uid();
234 generic_free_arg(childno);
236 return TRUE;
239 bool this_syscallname(const char *thisname, int childno)
241 unsigned int call = shm->syscall[childno].nr;
242 struct syscallentry *syscall_entry = syscalls[call].entry;
244 return strcmp(thisname, syscall_entry->name);