add common routine for setting a1/a2 for start/len of mmap.
[trinity.git] / syscall.c
blob648a4f060c0d4ac8be394bb9aeee5182949ba949
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 "utils.h"
28 #define __syscall_return(type, res) \
29 do { \
30 if ((unsigned long)(res) >= (unsigned long)(-125)) { \
31 errno = -(res); \
32 res = -1; \
33 } \
34 return (type) (res); \
35 } while (0)
37 #ifdef ARCH_IS_BIARCH
39 * This routine does 32 bit syscalls on 64 bit kernel.
40 * 32-on-32 will just use syscall() directly from do_syscall() because shm->do32bit is biarch only.
42 long syscall32(unsigned int call,
43 unsigned long a1, unsigned long a2, unsigned long a3,
44 unsigned long a4, unsigned long a5, unsigned long a6)
46 long __res = 0;
48 //FIXME: Move the implementations out to arch header files.
50 #if defined(__x86_64__)
51 __asm__ volatile (
52 "pushq %%rbp\n\t"
53 "pushq %%r10\n\t"
54 "pushq %%r11\n\t"
55 "movq %7, %%rbp\n\t"
56 "int $0x80\n\t"
57 "popq %%r11\n\t"
58 "popq %%r10\n\t"
59 "popq %%rbp\n\t"
60 : "=a" (__res)
61 : "0" (call),"b" ((long)(a1)),"c" ((long)(a2)),"d" ((long)(a3)), "S" ((long)(a4)),"D" ((long)(a5)), "g" ((long)(a6))
62 : "%rbp" /* mark EBP reg as dirty */
64 __syscall_return(long, __res);
66 #else
67 /* non-x86 implementations go here. */
68 #error Implement 32-on-64 syscall in syscall.c:syscall32() for this architecture.
70 #endif
71 return __res;
73 #else
74 #define syscall32(a,b,c,d,e,f,g) 0
75 #endif /* ARCH_IS_BIARCH */
77 static void check_uid(uid_t olduid)
79 uid_t myuid;
81 myuid = getuid();
82 if (myuid != olduid) {
84 /* unshare() can change us to /proc/sys/kernel/overflowuid */
85 if (myuid == 65534)
86 return;
88 output(0, "uid changed! Was: %d, now %d\n", olduid, myuid);
90 shm->exit_reason = EXIT_UID_CHANGED;
91 _exit(EXIT_FAILURE);
95 static unsigned long do_syscall(int childno, int *errno_saved)
97 int nr = shm->syscallno[childno];
98 unsigned long a1, a2, a3, a4, a5, a6;
99 unsigned long ret = 0;
100 int pidslot;
102 a1 = shm->a1[childno];
103 a2 = shm->a2[childno];
104 a3 = shm->a3[childno];
105 a4 = shm->a4[childno];
106 a5 = shm->a5[childno];
107 a6 = shm->a6[childno];
109 pidslot = find_pid_slot(getpid());
110 if (pidslot != PIDSLOT_NOT_FOUND) {
111 shm->total_syscalls_done++;
112 shm->child_syscall_count[pidslot]++;
113 (void)gettimeofday(&shm->tv[pidslot], NULL);
116 if (syscalls[nr].entry->flags & NEED_ALARM)
117 (void)alarm(1);
119 errno = 0;
121 if (shm->do32bit[childno] == FALSE)
122 ret = syscall(nr, a1, a2, a3, a4, a5, a6);
123 else
124 ret = syscall32(nr, a1, a2, a3, a4, a5, a6);
126 *errno_saved = errno;
128 if (syscalls[nr].entry->flags & NEED_ALARM)
129 (void)alarm(0);
131 return ret;
135 * Generate arguments, print them out, then call the syscall.
137 long mkcall(int childno)
139 unsigned int call = shm->syscallno[childno];
140 unsigned long ret = 0;
141 int errno_saved;
142 uid_t olduid = getuid();
144 shm->regenerate++;
146 shm->a1[childno] = (unsigned long)rand64();
147 shm->a2[childno] = (unsigned long)rand64();
148 shm->a3[childno] = (unsigned long)rand64();
149 shm->a4[childno] = (unsigned long)rand64();
150 shm->a5[childno] = (unsigned long)rand64();
151 shm->a6[childno] = (unsigned long)rand64();
153 generic_sanitise(childno);
154 if (syscalls[call].entry->sanitise)
155 syscalls[call].entry->sanitise(childno);
157 output_syscall_prefix(childno, call);
159 /* If we're going to pause, might as well sync pre-syscall */
160 if (dopause == TRUE)
161 synclogs();
163 if (((unsigned long)shm->a1 == (unsigned long) shm) ||
164 ((unsigned long)shm->a2 == (unsigned long) shm) ||
165 ((unsigned long)shm->a3 == (unsigned long) shm) ||
166 ((unsigned long)shm->a4 == (unsigned long) shm) ||
167 ((unsigned long)shm->a5 == (unsigned long) shm) ||
168 ((unsigned long)shm->a6 == (unsigned long) shm)) {
169 BUG("Address of shm ended up in a register!\n");
172 /* Some architectures (IA64/MIPS) start their Linux syscalls
173 * At non-zero, and have other ABIs below.
175 call += SYSCALL_OFFSET;
177 ret = do_syscall(childno, &errno_saved);
178 shm->retval[childno] = 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 syscalls[call].entry->name, call);
207 if (biarch == FALSE) {
208 deactivate_syscall(call);
209 } else {
210 if (shm->do32bit[childno] == TRUE)
211 deactivate_syscall32(call);
212 else
213 deactivate_syscall64(call);
217 skip_enosys:
219 if (syscalls[call].entry->post)
220 syscalls[call].entry->post(childno);
222 /* store info for debugging. */
223 shm->previous_syscallno[childno] = shm->syscallno[childno];
224 shm->previous_a1[childno] = shm->a1[childno];
225 shm->previous_a2[childno] = shm->a2[childno];
226 shm->previous_a3[childno] = shm->a3[childno];
227 shm->previous_a4[childno] = shm->a4[childno];
228 shm->previous_a5[childno] = shm->a5[childno];
229 shm->previous_a6[childno] = shm->a6[childno];
231 check_uid(olduid);
233 return ret;