]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/arm/systemcalls.c
df9f22d09e5084cbc3960a0681f293761d96932a
[apple/xnu.git] / bsd / dev / arm / systemcalls.c
1 /*
2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
3 */
4
5 #include <kern/task.h>
6 #include <kern/thread.h>
7 #include <kern/assert.h>
8 #include <kern/clock.h>
9 #include <kern/locks.h>
10 #include <kern/sched_prim.h>
11 #include <mach/machine/thread_status.h>
12 #include <mach/thread_act.h>
13 #include <arm/thread.h>
14 #include <arm/proc_reg.h>
15 #include <pexpert/pexpert.h>
16
17 #include <sys/kernel.h>
18 #include <sys/vm.h>
19 #include <sys/proc_internal.h>
20 #include <sys/syscall.h>
21 #include <sys/systm.h>
22 #include <sys/user.h>
23 #include <sys/errno.h>
24 #include <sys/kdebug.h>
25 #include <sys/sysent.h>
26 #include <sys/sysproto.h>
27 #include <sys/kauth.h>
28
29 #include <security/audit/audit.h>
30
31 #if CONFIG_DTRACE
32 extern int32_t dtrace_systrace_syscall(struct proc *, void *, int *);
33 extern void dtrace_systrace_syscall_return(unsigned short, int, int *);
34 #endif /* CONFIG_DTRACE */
35
36 extern void
37 unix_syscall(struct arm_saved_state * regs, thread_t thread_act,
38 struct uthread * uthread, struct proc * proc);
39
40 static int arm_get_syscall_args(uthread_t, struct arm_saved_state *, struct sysent *);
41 static int arm_get_u32_syscall_args(uthread_t, arm_saved_state32_t *, struct sysent *);
42 static void arm_prepare_u32_syscall_return(struct sysent *, arm_saved_state32_t *, uthread_t, int);
43 static void arm_prepare_syscall_return(struct sysent *, struct arm_saved_state *, uthread_t, int);
44 static int arm_get_syscall_number(struct arm_saved_state *);
45 static void arm_trace_unix_syscall(int, struct arm_saved_state *);
46 static void arm_clear_syscall_error(struct arm_saved_state *);
47 #define save_r0 r[0]
48 #define save_r1 r[1]
49 #define save_r2 r[2]
50 #define save_r3 r[3]
51 #define save_r4 r[4]
52 #define save_r5 r[5]
53 #define save_r6 r[6]
54 #define save_r7 r[7]
55 #define save_r8 r[8]
56 #define save_r9 r[9]
57 #define save_r10 r[10]
58 #define save_r11 r[11]
59 #define save_r12 r[12]
60 #define save_r13 r[13]
61
62 #if COUNT_SYSCALLS
63 __XNU_PRIVATE_EXTERN int do_count_syscalls = 1;
64 __XNU_PRIVATE_EXTERN int syscalls_log[SYS_MAXSYSCALL];
65 #endif
66
67 #define code_is_kdebug_trace(code) (((code) == SYS_kdebug_trace) || \
68 ((code) == SYS_kdebug_trace64) || \
69 ((code) == SYS_kdebug_trace_string))
70
71 /*
72 * Function: unix_syscall
73 *
74 * Inputs: regs - pointer to Process Control Block
75 *
76 * Outputs: none
77 */
78 #ifdef __arm__
79 __attribute__((noreturn))
80 #endif
81 void
82 unix_syscall(
83 struct arm_saved_state * state,
84 __unused thread_t thread_act,
85 struct uthread * uthread,
86 struct proc * proc)
87 {
88 struct sysent *callp;
89 int error;
90 unsigned short code;
91 pid_t pid;
92
93 #if defined(__arm__)
94 assert(is_saved_state32(state));
95 #endif
96
97 uthread_reset_proc_refcount(uthread);
98
99 code = arm_get_syscall_number(state);
100
101 #define unix_syscall_kprintf(x...) /* kprintf("unix_syscall: " x) */
102
103 #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST)
104 if (kdebug_enable && !code_is_kdebug_trace(code)) {
105 arm_trace_unix_syscall(code, state);
106 }
107 #endif
108
109 if ((uthread->uu_flag & UT_VFORK))
110 proc = current_proc();
111
112 callp = (code >= nsysent) ? &sysent[SYS_invalid] : &sysent[code];
113
114 /*
115 * sy_narg is inaccurate on ARM if a 64 bit parameter is specified. Since user_addr_t
116 * is currently a 32 bit type, this is really a long word count. See rdar://problem/6104668.
117 */
118 if (callp->sy_narg != 0) {
119 if (arm_get_syscall_args(uthread, state, callp) != 0) {
120 /* Too many arguments, or something failed */
121 unix_syscall_kprintf("arm_get_syscall_args failed.\n");
122 callp = &sysent[SYS_invalid];
123 }
124 }
125
126 uthread->uu_flag |= UT_NOTCANCELPT;
127 uthread->syscall_code = code;
128
129 uthread->uu_rval[0] = 0;
130
131 /*
132 * r4 is volatile, if we set it to regs->save_r4 here the child
133 * will have parents r4 after execve
134 */
135 uthread->uu_rval[1] = 0;
136
137 error = 0;
138
139 /*
140 * ARM runtime will call cerror if the carry bit is set after a
141 * system call, so clear it here for the common case of success.
142 */
143 arm_clear_syscall_error(state);
144
145 #if COUNT_SYSCALLS
146 if (do_count_syscalls > 0) {
147 syscalls_log[code]++;
148 }
149 #endif
150 pid = proc_pid(proc);
151
152 #ifdef JOE_DEBUG
153 uthread->uu_iocount = 0;
154 uthread->uu_vpindex = 0;
155 #endif
156 unix_syscall_kprintf("code %d (pid %d - %s, tid %lld)\n", code,
157 pid, proc->p_comm, thread_tid(current_thread()));
158
159 AUDIT_SYSCALL_ENTER(code, proc, uthread);
160 error = (*(callp->sy_call)) (proc, &uthread->uu_arg[0], &(uthread->uu_rval[0]));
161 AUDIT_SYSCALL_EXIT(code, proc, uthread, error);
162
163 unix_syscall_kprintf("code %d, error %d, results %x, %x (pid %d - %s, tid %lld)\n", code, error,
164 uthread->uu_rval[0], uthread->uu_rval[1],
165 pid, get_bsdtask_info(current_task()) ? proc->p_comm : "unknown" , thread_tid(current_thread()));
166
167 #ifdef JOE_DEBUG
168 if (uthread->uu_iocount) {
169 printf("system call returned with uu_iocount != 0");
170 }
171 #endif
172 #if CONFIG_DTRACE
173 uthread->t_dtrace_errno = error;
174 #endif /* CONFIG_DTRACE */
175 #if DEBUG || DEVELOPMENT
176 kern_allocation_name_t
177 prior __assert_only = thread_set_allocation_name(NULL);
178 assertf(prior == NULL, "thread_set_allocation_name(\"%s\") not cleared", kern_allocation_get_name(prior));
179 #endif /* DEBUG || DEVELOPMENT */
180
181 arm_prepare_syscall_return(callp, state, uthread, error);
182
183 uthread->uu_flag &= ~UT_NOTCANCELPT;
184
185 if (uthread->uu_lowpri_window) {
186 /*
187 * task is marked as a low priority I/O type
188 * and the I/O we issued while in this system call
189 * collided with normal I/O operations... we'll
190 * delay in order to mitigate the impact of this
191 * task on the normal operation of the system
192 */
193 throttle_lowpri_io(1);
194 }
195 #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST)
196 if (kdebug_enable && !code_is_kdebug_trace(code)) {
197 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
198 BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
199 error, uthread->uu_rval[0], uthread->uu_rval[1], pid, 0);
200 }
201 #endif
202
203 #if PROC_REF_DEBUG
204 if (__improbable(uthread_get_proc_refcount(uthread) != 0)) {
205 panic("system call returned with uu_proc_refcount != 0");
206 }
207 #endif
208
209 #ifdef __arm__
210 thread_exception_return();
211 #endif
212 }
213
214 void
215 unix_syscall_return(int error)
216 {
217 thread_t thread_act;
218 struct uthread *uthread;
219 struct proc *proc;
220 struct arm_saved_state *regs;
221 unsigned short code;
222 struct sysent *callp;
223
224 #define unix_syscall_return_kprintf(x...) /* kprintf("unix_syscall_retur
225 * n: " x) */
226
227 thread_act = current_thread();
228 proc = current_proc();
229 uthread = get_bsdthread_info(thread_act);
230
231 regs = find_user_regs(thread_act);
232 code = uthread->syscall_code;
233 callp = (code >= nsysent) ? &sysent[SYS_invalid] : &sysent[code];
234
235 #if CONFIG_DTRACE
236 if (callp->sy_call == dtrace_systrace_syscall)
237 dtrace_systrace_syscall_return( code, error, uthread->uu_rval );
238 #endif /* CONFIG_DTRACE */
239 #if DEBUG || DEVELOPMENT
240 kern_allocation_name_t
241 prior __assert_only = thread_set_allocation_name(NULL);
242 assertf(prior == NULL, "thread_set_allocation_name(\"%s\") not cleared", kern_allocation_get_name(prior));
243 #endif /* DEBUG || DEVELOPMENT */
244
245 AUDIT_SYSCALL_EXIT(code, proc, uthread, error);
246
247 /*
248 * Get index into sysent table
249 */
250 arm_prepare_syscall_return(callp, regs, uthread, error);
251
252 uthread->uu_flag &= ~UT_NOTCANCELPT;
253
254 if (uthread->uu_lowpri_window) {
255 /*
256 * task is marked as a low priority I/O type
257 * and the I/O we issued while in this system call
258 * collided with normal I/O operations... we'll
259 * delay in order to mitigate the impact of this
260 * task on the normal operation of the system
261 */
262 throttle_lowpri_io(1);
263 }
264 #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST)
265 if (kdebug_enable && !code_is_kdebug_trace(code)) {
266 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
267 BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
268 error, uthread->uu_rval[0], uthread->uu_rval[1], proc->p_pid, 0);
269 }
270 #endif
271
272 thread_exception_return();
273 /* NOTREACHED */
274 }
275
276 static void
277 arm_prepare_u32_syscall_return(struct sysent *callp, arm_saved_state32_t *regs, uthread_t uthread, int error)
278 {
279 if (error == ERESTART) {
280 regs->pc -= 4;
281 } else if (error != EJUSTRETURN) {
282 if (error) {
283 regs->save_r0 = error;
284 regs->save_r1 = 0;
285 /* set the carry bit to execute cerror routine */
286 regs->cpsr |= PSR_CF;
287 unix_syscall_return_kprintf("error: setting carry to trigger cerror call\n");
288 } else { /* (not error) */
289 switch (callp->sy_return_type) {
290 case _SYSCALL_RET_INT_T:
291 case _SYSCALL_RET_UINT_T:
292 case _SYSCALL_RET_OFF_T:
293 case _SYSCALL_RET_ADDR_T:
294 case _SYSCALL_RET_SIZE_T:
295 case _SYSCALL_RET_SSIZE_T:
296 case _SYSCALL_RET_UINT64_T:
297 regs->save_r0 = uthread->uu_rval[0];
298 regs->save_r1 = uthread->uu_rval[1];
299 break;
300 case _SYSCALL_RET_NONE:
301 regs->save_r0 = 0;
302 regs->save_r1 = 0;
303 break;
304 default:
305 panic("unix_syscall: unknown return type");
306 break;
307 }
308 }
309 }
310 /* else (error == EJUSTRETURN) { nothing } */
311
312 }
313
314 static void
315 arm_trace_u32_unix_syscall(int code, arm_saved_state32_t *regs)
316 {
317 boolean_t indirect = (regs->save_r12 == 0);
318 if (indirect)
319 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
320 BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
321 regs->save_r1, regs->save_r2, regs->save_r3, regs->save_r4, 0);
322 else
323 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
324 BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
325 regs->save_r0, regs->save_r1, regs->save_r2, regs->save_r3, 0);
326 }
327
328 static void
329 arm_clear_u32_syscall_error(arm_saved_state32_t *regs)
330 {
331 regs->cpsr &= ~PSR_CF;
332 }
333
334 #if defined(__arm__)
335
336 static int
337 arm_get_syscall_args(uthread_t uthread, struct arm_saved_state *state, struct sysent *callp)
338 {
339 assert(is_saved_state32(state));
340 return arm_get_u32_syscall_args(uthread, saved_state32(state), callp);
341 }
342
343 #if __arm__ && (__BIGGEST_ALIGNMENT__ > 4)
344 /*
345 * For armv7k, the alignment constraints of the ABI mean we don't know how the userspace
346 * arguments are arranged without knowing the the prototype of the syscall. So we use mungers
347 * to marshal the userspace data into the uu_arg. This also means we need the same convention
348 * as mach syscalls. That means we use r8 to pass arguments in the BSD case as well.
349 */
350 static int
351 arm_get_u32_syscall_args(uthread_t uthread, arm_saved_state32_t *regs, struct sysent *callp)
352 {
353 sy_munge_t *munger;
354
355 /* This check is probably not very useful since these both come from build-time */
356 if (callp->sy_arg_bytes > sizeof(uthread->uu_arg))
357 return -1;
358
359 /* get the munger and use it to marshal in the data from userspace */
360 munger = callp->sy_arg_munge32;
361 if (munger == NULL || (callp->sy_arg_bytes == 0))
362 return 0;
363
364 return munger(regs, uthread->uu_arg);
365 }
366 #else
367 /*
368 * For an AArch32 kernel, where we know that we have only AArch32 userland,
369 * we do not do any munging (which is a little confusing, as it is a contrast
370 * to the i386 kernel, where, like the x86_64 kernel, we always munge
371 * arguments from a 32-bit userland out to 64-bit.
372 */
373 static int
374 arm_get_u32_syscall_args(uthread_t uthread, arm_saved_state32_t *regs, struct sysent *callp)
375 {
376 int regparams;
377 int flavor = (regs->save_r12 == 0 ? 1 : 0);
378
379 regparams = (7 - flavor); /* Indirect value consumes a register */
380
381 assert((unsigned) callp->sy_arg_bytes <= sizeof (uthread->uu_arg));
382
383 if (callp->sy_arg_bytes <= (sizeof(uint32_t) * regparams)) {
384 /*
385 * Seven arguments or less are passed in registers.
386 */
387 memcpy(&uthread->uu_arg[0], &regs->r[flavor], callp->sy_arg_bytes);
388 } else if (callp->sy_arg_bytes <= sizeof(uthread->uu_arg)) {
389 /*
390 * In this case, we composite - take the first args from registers,
391 * the remainder from the stack (offset by the 7 regs therein).
392 */
393 unix_syscall_kprintf("%s: spillover...\n", __FUNCTION__);
394 memcpy(&uthread->uu_arg[0] , &regs->r[flavor], regparams * sizeof(int));
395 if (copyin((user_addr_t)regs->sp + 7 * sizeof(int), (int *)&uthread->uu_arg[0] + regparams,
396 (callp->sy_arg_bytes - (sizeof(uint32_t) * regparams))) != 0) {
397 return -1;
398 }
399 } else {
400 return -1;
401 }
402
403 return 0;
404 }
405 #endif
406
407 static int
408 arm_get_syscall_number(struct arm_saved_state *regs)
409 {
410 if (regs->save_r12 != 0) {
411 return regs->save_r12;
412 } else {
413 return regs->save_r0;
414 }
415 }
416
417 static void
418 arm_prepare_syscall_return(struct sysent *callp, struct arm_saved_state *state, uthread_t uthread, int error)
419 {
420 assert(is_saved_state32(state));
421 arm_prepare_u32_syscall_return(callp, state, uthread, error);
422 }
423
424 static void
425 arm_trace_unix_syscall(int code, struct arm_saved_state *state)
426 {
427 assert(is_saved_state32(state));
428 arm_trace_u32_unix_syscall(code, saved_state32(state));
429 }
430
431 static void
432 arm_clear_syscall_error(struct arm_saved_state * state)
433 {
434 assert(is_saved_state32(state));
435 arm_clear_u32_syscall_error(saved_state32(state));
436 }
437
438 #elif defined(__arm64__)
439 static void arm_prepare_u64_syscall_return(struct sysent *, arm_saved_state64_t *, uthread_t, int);
440 static int arm_get_u64_syscall_args(uthread_t, arm_saved_state64_t *, struct sysent *);
441
442 static int
443 arm_get_syscall_args(uthread_t uthread, struct arm_saved_state *state, struct sysent *callp)
444 {
445 if (is_saved_state32(state)) {
446 return arm_get_u32_syscall_args(uthread, saved_state32(state), callp);
447 } else {
448 return arm_get_u64_syscall_args(uthread, saved_state64(state), callp);
449 }
450 }
451
452 /*
453 * 64-bit: all arguments in registers. We're willing to use x9, a temporary
454 * register per the ABI, to pass an argument to the kernel for one case,
455 * an indirect syscall with 8 arguments. No munging required, as all arguments
456 * are in 64-bit wide registers already.
457 */
458 static int
459 arm_get_u64_syscall_args(uthread_t uthread, arm_saved_state64_t *regs, struct sysent *callp)
460 {
461 int indirect_offset, regparams;
462
463 indirect_offset = (regs->x[ARM64_SYSCALL_CODE_REG_NUM] == 0) ? 1 : 0;
464 regparams = 9 - indirect_offset;
465
466 /*
467 * Everything should fit in registers for now.
468 */
469 assert(callp->sy_narg <= 8);
470 if (callp->sy_narg > regparams) {
471 return -1;
472 }
473
474 memcpy(&uthread->uu_arg[0], &regs->x[indirect_offset], callp->sy_narg * sizeof(uint64_t));
475 return 0;
476 }
477 /*
478 * When the kernel is running AArch64, munge arguments from 32-bit
479 * userland out to 64-bit.
480 *
481 * flavor == 1 indicates an indirect syscall.
482 */
483 static int
484 arm_get_u32_syscall_args(uthread_t uthread, arm_saved_state32_t *regs, struct sysent *callp)
485 {
486 int regparams;
487 #if CONFIG_REQUIRES_U32_MUNGING
488 sy_munge_t *mungerp;
489 #else
490 #error U32 syscalls on ARM64 kernel requires munging
491 #endif
492 int flavor = (regs->save_r12 == 0 ? 1 : 0);
493
494 regparams = (7 - flavor); /* Indirect value consumes a register */
495
496 assert((unsigned) callp->sy_arg_bytes <= sizeof (uthread->uu_arg));
497
498 if (callp->sy_arg_bytes <= (sizeof(uint32_t) * regparams)) {
499 /*
500 * Seven arguments or less are passed in registers.
501 */
502 memcpy(&uthread->uu_arg[0], &regs->r[flavor], callp->sy_arg_bytes);
503 } else if (callp->sy_arg_bytes <= sizeof(uthread->uu_arg)) {
504 /*
505 * In this case, we composite - take the first args from registers,
506 * the remainder from the stack (offset by the 7 regs therein).
507 */
508 unix_syscall_kprintf("%s: spillover...\n", __FUNCTION__);
509 memcpy(&uthread->uu_arg[0] , &regs->r[flavor], regparams * sizeof(int));
510 if (copyin((user_addr_t)regs->sp + 7 * sizeof(int), (int *)&uthread->uu_arg[0] + regparams,
511 (callp->sy_arg_bytes - (sizeof(uint32_t) * regparams))) != 0) {
512 return -1;
513 }
514 } else {
515 return -1;
516 }
517
518 #if CONFIG_REQUIRES_U32_MUNGING
519 /* Munge here */
520 mungerp = callp->sy_arg_munge32;
521 if (mungerp != NULL) {
522 (*mungerp)(&uthread->uu_arg[0]);
523 }
524 #endif
525
526 return 0;
527
528 }
529
530 static int
531 arm_get_syscall_number(struct arm_saved_state *state)
532 {
533 if (is_saved_state32(state)) {
534 if (saved_state32(state)->save_r12 != 0) {
535 return saved_state32(state)->save_r12;
536 } else {
537 return saved_state32(state)->save_r0;
538 }
539 } else {
540 if (saved_state64(state)->x[ARM64_SYSCALL_CODE_REG_NUM] != 0) {
541 return saved_state64(state)->x[ARM64_SYSCALL_CODE_REG_NUM];
542 } else {
543 return saved_state64(state)->x[0];
544 }
545 }
546
547 }
548
549 static void
550 arm_prepare_syscall_return(struct sysent *callp, struct arm_saved_state *state, uthread_t uthread, int error)
551 {
552 if (is_saved_state32(state)) {
553 arm_prepare_u32_syscall_return(callp, saved_state32(state), uthread, error);
554 } else {
555 arm_prepare_u64_syscall_return(callp, saved_state64(state), uthread, error);
556 }
557 }
558
559 static void
560 arm_prepare_u64_syscall_return(struct sysent *callp, arm_saved_state64_t *regs, uthread_t uthread, int error)
561 {
562 if (error == ERESTART) {
563 regs->pc -= 4;
564 } else if (error != EJUSTRETURN) {
565 if (error) {
566 regs->x[0] = error;
567 regs->x[1] = 0;
568 /*
569 * Set the carry bit to execute cerror routine.
570 * ARM64_TODO: should we have a separate definition?
571 * The bits are the same.
572 */
573 regs->cpsr |= PSR_CF;
574 unix_syscall_return_kprintf("error: setting carry to trigger cerror call\n");
575 } else { /* (not error) */
576 switch (callp->sy_return_type) {
577 case _SYSCALL_RET_INT_T:
578 regs->x[0] = uthread->uu_rval[0];
579 regs->x[1] = uthread->uu_rval[1];
580 break;
581 case _SYSCALL_RET_UINT_T:
582 regs->x[0] = (u_int)uthread->uu_rval[0];
583 regs->x[1] = (u_int)uthread->uu_rval[1];
584 break;
585 case _SYSCALL_RET_OFF_T:
586 case _SYSCALL_RET_ADDR_T:
587 case _SYSCALL_RET_SIZE_T:
588 case _SYSCALL_RET_SSIZE_T:
589 case _SYSCALL_RET_UINT64_T:
590 regs->x[0] = *((uint64_t *)(&uthread->uu_rval[0]));
591 regs->x[1] = 0;
592 break;
593 case _SYSCALL_RET_NONE:
594 break;
595 default:
596 panic("unix_syscall: unknown return type");
597 break;
598 }
599 }
600 }
601 /* else (error == EJUSTRETURN) { nothing } */
602
603
604 }
605 static void
606 arm_trace_u64_unix_syscall(int code, arm_saved_state64_t *regs)
607 {
608 boolean_t indirect = (regs->x[ARM64_SYSCALL_CODE_REG_NUM] == 0);
609 if (indirect)
610 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
611 BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
612 regs->x[1], regs->x[2], regs->x[3], regs->x[4], 0);
613 else
614 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
615 BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
616 regs->x[0], regs->x[1], regs->x[2], regs->x[3], 0);
617 }
618
619 static void
620 arm_trace_unix_syscall(int code, struct arm_saved_state *state)
621 {
622 if (is_saved_state32(state)) {
623 arm_trace_u32_unix_syscall(code, saved_state32(state));
624 } else {
625 arm_trace_u64_unix_syscall(code, saved_state64(state));
626 }
627 }
628
629 static void
630 arm_clear_u64_syscall_error(arm_saved_state64_t *regs)
631 {
632 /*
633 * ARM64_TODO: should we have a separate definition?
634 * The bits are the same.
635 */
636 regs->cpsr &= ~PSR_CF;
637 }
638
639 static void
640 arm_clear_syscall_error(struct arm_saved_state * state)
641 {
642 if (is_saved_state32(state)) {
643 arm_clear_u32_syscall_error(saved_state32(state));
644 } else {
645 arm_clear_u64_syscall_error(saved_state64(state));
646 }
647 }
648
649 #else
650 #error Unknown architecture.
651 #endif